Grouped Bar chart with JBChartView library - ios

I've needed to draw a grouped bar charts in an iOS Projects I'm doing. So the iOS Third party library I used is JBChartView from Jawbone.
Up to the knowledge I gained with my research regarding this I found no any already supported ways within the library.
However I tried doing something like as follows:
- (NSUInteger)numberOfBarsInBarChartView:(JBBarChartView *)barChartView
{
return [self.chartLegend count]; // number of bars in chart "BB", "HB", "FB", "RO"
}
- (CGFloat)barChartView:(JBBarChartView *)barChartView heightForBarViewAtIndex:(NSUInteger)index
{
CGFloat height = (isnan((([[chartData objectAtIndex:index] doubleValue]/total)*100))) ? 0.0 : (([[chartData objectAtIndex:index] doubleValue]/total)*100);
NSLog(#"height : %f", height);
return height;
}
- (UIView *)barChartView:(JBBarChartView *)barChartView barViewAtIndex:(NSUInteger)index {
CGFloat height = (isnan((([[chartData objectAtIndex:index] doubleValue]/total)*100)))
? 0.0
: (([[chartData objectAtIndex:index] doubleValue]/total)*100);
UIView *view = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 50, height)];
[view setBackgroundColor:[UIColor grayColor]];
UIView *firstHalf = [[UIView alloc] initWithFrame:CGRectMake(0, height, 25, height)];
[firstHalf setBackgroundColor:[UIColor redColor]];
UIView *secondHalf = [[UIView alloc] initWithFrame:CGRectMake(25, height, 25, height/2)];
if (index == 0) {
[secondHalf setBackgroundColor:UIColorFromRGB(0xF15854)];
} else if (index == 1) {
[secondHalf setBackgroundColor:UIColorFromRGB(0x5DA5DA)];
} else if (index == 2) {
[secondHalf setBackgroundColor:UIColorFromRGB(0xFAA43A)];
} else if (index == 3) {
[secondHalf setBackgroundColor:UIColorFromRGB(0x60BD68)];
}
[view addSubview:firstHalf];
[view addSubview:secondHalf];
return view;
}
Note: Please, ignore the data values which I've put to determine the heights of the Red color and other varying color bars. And UIColorFromRGB is a custom methods I use in my development.
But it gives the graph as follows:
But what I really want to draw using JBChartView library is as follows:
Any help is accepted with loads of gratitude and respect, but except don't suggest to use any other library to get this done. I like the simplicity of JBChartView library. :-)
Thanks in advance!

From what I've found out, this is not possible using standard way, but can be worked around. See https://github.com/Jawbone/JBChartView/issues/139

Related

UIScrollView with many subviews takes time to process

I have an UIScrollView with subviews. It contains a result list of products/items. UIViewwith UIImageView and UILabel. It may contain many items. My problem is when I'm pressing the button(Grid Button) to change the UI result into grid view, it takes time before it finishes the processing. Is there a way to make this faster? Like remove images which are not visible in screen/UIScrollView?
Here's my code for listView
-(void)actionList {
NSLog(#"List!!");
isGrid = NO;
for(UIView*iView in sv_results.subviews){
for(UILabel *iView2 in iView.subviews){
if([iView2 isMemberOfClass:[UILabel class]]){
if(iView2.tag == 0)
{
iView2.frame = CGRectMake(80, 0, 150, 50);
iView2.font = [UIFont boldSystemFontOfSize:12.0f];
}
else if(iView2.tag == 1)
{
pricewidth = [iView2.text sizeWithAttributes:#{NSFontAttributeName:[UIFont systemFontOfSize:13.0f]}];
iView2.frame = CGRectMake(80, 20, pricewidth.width+1, 50);
iView2.font = [UIFont systemFontOfSize:13.0f];
for(UIView *discountline in iView2.subviews)
{
discountline.frame = CGRectMake(0, iView2.frame.size.height/2, iView2.frame.size.width, 1);
}
}
else if(iView2.tag == 2)
{
iView2.frame = CGRectMake(screenRect.size.width-60, 30, 50, 15);
iView2.font = [UIFont systemFontOfSize:10.0f];
}
else if(iView2.tag == 3)
{
iView2.frame = CGRectMake(140, 20, 150, 50);
iView2.font = [UIFont systemFontOfSize:13.0f];
}
else {
iView2.frame = CGRectMake(80, 0, 150, 50);
iView2.font = [UIFont boldSystemFontOfSize:12.0f];
}
}
if([iView2 isMemberOfClass:[AsyncImageView class]]){
iView2.frame = CGRectMake(15,12,50,50);
iView2.layer.cornerRadius = 5;
}
}
for(int i = 0;i<=allAvailableData;i++)
{
if(iView.tag == i)
{
iView.frame = CGRectMake(0,((i-1)*75),320,75);
}
//sv_results.contentSize = CGSizeMake(320,yPosition);//optional resize height scrollview from gridview
}
iView.layer.borderWidth = .3f;
}
sv_results.contentSize = CGSizeMake(320,(allAvailableData)*75);
}
It can take a time because of images. If you are loading a lots of images in main thread then it is normal to take a time. Try to use lazy image loading with UITableView. I use this in my project and easy to implement and use. http://www.theappguruz.com/sample-code/ios-lazy-loading-images/ there is some codes and helps. I did not check this but it looks also fine https://developer.apple.com/library/ios/samplecode/LazyTableImages/Introduction/Intro.html
Just use
scrollView.delaysContentTouches = NO;
A Boolean value that determines whether the scroll view delays the handling of touch-down gestures.
If the value of this property is YES, the scroll view delays handling the touch-down gesture until it can determine if scrolling is the intent. If the value is NO , the scroll view immediately calls touchesShouldBegin:withEvent:inContentView:. The default value is YES.
This means, scrollView will delay touches by default, you can disable that functionality by above code,
Hope it will solve your problem.
I think you should implement UITableView and you can load image with "dispatch_async" so it will not take time. I hope you may get solution this way.

Resizing start behaving inaccurate after starting loop of scrolling

i got images scrollview and i am trying to change the size of views while scrolling, it works correct first time but when i started loop of scrolling means setting contentoff 0, 0, then it will start behaving inaccurate, means it started shuffeling views, up and down, it is working fine while scrolling upwards. if anyone get the problem please guide me where i am doing wrong? or suggest me any tutorial. HERE IS MY CODE.
- (void)viewDidLoad{
if (IS_IPHONE5)
scroller.contentSize=CGSizeMake(320, ((count*142)+710));
else
scroller.contentSize=CGSizeMake(320, ((count*130)+530));
makecopy= tableArray.count+4;
for(int i=0;i<=makecopy;i++)
{
if(i==0)
yValue=0;
else
yValue=130;
UIView* view1;
//=[[UIView alloc]initWithFrame:CGRectMake(0, (i*130)+yValue, 320, 260)];
if (IS_IPHONE5) {
if (i!=0/*&&i!=count*/){
yValue=142;
view1=[[UIView alloc]initWithFrame:CGRectMake(0, (i*142)+yValue, 320, 284)];
}
else{
yValue=0;
view1=[[UIView alloc]initWithFrame:CGRectMake(0, (i*142)+yValue, 320, 284)];
}
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if ([[UIScreen mainScreen] bounds].size.height == 568)
{
if (normalScroll)
{
for(int i=0;i<count;i++)
{
// NSLog(#">:%i %i:<",(i*142),((i+1)*142));
if (scroller.contentOffset.y>=(i*142)&&scroller.contentOffset.y<((i+1)*142)){
[self doscrollingwiththView:[scroller viewWithTag:i+1] view2:[scroller viewWithTag:i+2] view3:[scroller viewWithTag:i+3] view4:[scroller viewWithTag:i+4]];
}
}
changeMe = true;
if (!isUp && scrollView.contentOffset.y>(count*142)) {
[scrollView setContentOffset:CGPointMake(0, 0)];
changeMe = false;
}
if (isUp && scrollView.contentOffset.y<= -1) {
[scrollView setContentOffset:CGPointMake(0, (count*142)-10)];
changeMe = false;
}
}
-(void)doscrollingwiththView:(UIView*)view1 view2:(UIView*)view2 view3:(UIView*)view3 view4:(UIView*)view4
{
// NSLog(#"view1 : %# view1 : %# view1 : %# view1 : %# ",view1,view2,view3,view4);
offsetY=offsetY1+ scroller.contentOffset.y;
int view1Y=0;
int view2Y=0;
//int view3Y;
//int view4Y;
if (IS_IPHONE5)
{
view2Y=284;
}
else
{
view2Y=260;
//view3Y=390;
//view4Y=520;
}
for(int i=0;i<makecopy;i++)
{
if (IS_IPHONE5) {
// NSLog(#"the value is: %i the contentoffset is:%f",(142*i),scroller.contentOffset.y);
if(scroller.contentOffset.y>=(142*i)&&scroller.contentOffset.y<(142*(i+1)))
{
view1Y=(142*i);
view2Y=284+(142*i);
}
}
else
{
if (scroller.contentOffset.y>=(130*i)&&scroller.contentOffset.y<(130*(i+1)))
{
view1Y=(130*i);
view2Y=260+(130*i);
}
}
}
if (IS_IPHONE5) {
view1.frame=CGRectMake(0, view1Y-(offsetY%142), 320, 284);
view2.frame=CGRectMake(0, view2Y-(offsetY%142), 320, 284);
view3.frame=CGRectMake(0, 426+view1Y, 320, 284);
view4.frame=CGRectMake(0, 568+view1Y, 320, 284);
NSLog(#"the content offset is: %d",offsetY);
}
else
{
view1.frame=CGRectMake(0, view1Y-(offsetY%130), 320, 260);
view2.frame=CGRectMake(0, view2Y-(offsetY%130), 320, 260);
view3.frame=CGRectMake(0, 390+view1Y, 320, 260);
view4.frame=CGRectMake(0, 520+view1Y, 320, 260);
}
}
what i understood by your code is, you are shifting the images while scrolling and resizing it to when it reaches some specific point as you r doing its top i think, then my friend you r making 4 view and i think there are 3 views at a time shown in screen, what you hav to do is make 5 view instead of making 4 views, and revolve these view and let me know after it, i hope it will work in your case.

UITableView bigger than screen inside UIPageView

Lately I'm pulling my hair out because of this. I'm still a rookie iOS Developer therefore a simple solution would be appreciated.
I have a UIPageViewController with three views, the middle view is a UITableView which i populate with data programmatically and try to make a layout like a grid. When the UITableView has too many data the information gets outside of the screen.
I've tried to disable auto layout and add the UITableView to a UIScrollView, enabling the UITableView to scroll horizontal. I've managed to do that but somehow the interaction is messy and most of the times when trying to horizontal scroll the table it catches the UIPageViewController interaction. Also the vertical scroll of the table does not respond well too.
Is there a known solution for this situation?
After testing a few things I ended up with a acceptable solution using autolayout.
So first I added a UIScrollView and added the UITableView inside the UIScrollView.
I've enabled the Paging and disabled the Bounce Horizontally in the UIScrollView.
In the UITableView I've basically disabled everything relative to bouncing paging and scrolling.
Since the data is being populated programmatically to be some sort of a grid I have to know the total width of the longest row for that I've created a few methods to calculate the maximum width and arrange the labels.
I also created constraints for the table Width and Height which I calculate and update after all the calculations are done.
-(void) ArrangeTable
{
for (int i= 0; i < [arrayTable count]; i++) {
for (int j=0; j< [[arrayTable objectAtIndex:i ] count]; j++) {
UILabel * nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 8.0, 95.0, 30.0)];
[nameLabel setText:[NSString stringWithFormat:#"%#",[[arrayTable objectAtIndex:i] objectAtIndex:j]]];
[nameLabel sizeToFit];
float widthIs = [nameLabel.text
boundingRectWithSize:nameLabel.frame.size
options:NSStringDrawingUsesLineFragmentOrigin
attributes:#{ NSFontAttributeName:nameLabel.font }
context:nil].size.width;
[self alignLabels:j currentWidth:[NSNumber numberWithFloat: widthIs]];
}
}
}
-(void) alignLabels:(int)colNumber currentWidth:(NSNumber*)labelWidth
{
if(colNumber >= [arrayLabelWidth count])
{
//Insert without position
[arrayLabelWidth addObject:labelWidth];
}else if ([labelWidth floatValue] > [[arrayLabelWidth objectAtIndex:colNumber] floatValue] )
{
[arrayLabelWidth replaceObjectAtIndex:colNumber withObject:labelWidth];
}
}
-(void) setMaxRowWidth
{
float widthTV =[[arrayLabelWidth valueForKeyPath:#"#sum.self"] floatValue] + ([arrayLabelWidth count]) * 10;
CGRect screenRect = [[UIScreen mainScreen] bounds];
float heightTV = [self tableViewHeight];
if(widthTV > screenRect.size.width)
{
tvWidth.constant = widthTV;
//svWidth.constant = valueTV;
}else{
if (UIDeviceOrientationIsPortrait(self.interfaceOrientation)){
//DO Portrait
tvWidth.constant = screenRect.size.width;
}else{
//DO Landscape
float calc = screenRect.size.width - self.view.frame.size.width;
tvWidth.constant = screenRect.size.width - calc;
}
}
tvHeight.constant = heightTV;
}
- (CGFloat)tableViewHeight
{
[tablePod layoutIfNeeded];
return [tablePod contentSize].height;
}

IOS - round cornered temporary alert - how to implement?

I would like to implement a temporary alert into to a uitableviewcontroller to inform a user that their data has been saved.
I could do this with a uiAlertView - but for aesthetic reasons it would be preferable to implement something similar to the round cornered fade in/out alert view used in IOS7 for tasks such as showing volume control - as in this pic -
Is this a IOS7 class? I cant find any info on it (probably because I don't know what its called!), or would I need to extend the uiAlertView to replicate this functionality?
No, this is not a native iOS 7 subclass but there are plenty implementations of it in the wild. One example would be DTAlertView or CXAlertView or SDCAlertView. Check them out.
If you just want the volume-thingy type behavior, don't search too far. It's easily home-rolled with a full screen sized image view that's mostly transparent, and has in it's center a rounded-corner message rectangle, translucent if you like. Then build a convenience method to show/hide it with animation...
- (void)setAlertHidden:(BOOL)hidden animated:(BOOL)animated {
UIImageView *alertImageView = [self alertImageView];
BOOL currentlyHidden = alertImageView.alpha == 0.0;
if (currentlyHidden == hidden) return;
NSTimeInterval alpha = (hidden)? 0.0 : 1.0;
NSTimeInterval duration = (animated)? 0.3 : 0.0;
[UIView animateWithDuration:duration animations:^{
alertImageView.alpha = alpha;
} completion:^(BOOL finished) {
// if we showed the alert, hide it after 3 seconds
// you can make this duration a parameter
if (!hidden) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3*NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[self setAlertHidden:YES animated:YES];
});
}
}];
}
All you need other than this is to build the image view lazily...
- (UIImageView *)alertImageView {
UIImageView *alertImageView = (UIImageView *)[self.view viewWithTag:999];
if (!alertImageView) {
alertImageView = [[UIImageView alloc] initWithFrame:self.view.bounds];
alertImageView.image = [UIImage imageNamed:#"fullscreen-volume-looking-thing.png"];
alertImageView.tag = 999;
[self.view addSubview:alertImageView];
}
return alertImageView;
}
Realize it's not exactly what you need, but this was pretty easy to paste together. It's the volume thing on a screen sized transparent background...
This is a quick implementation of a subview that will do what you want
#import "BellAlert.h"
#implementation BellAlert
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor clearColor];
UIImageView *bell = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Bell.png"]];
bell.frame = CGRectMake(0, 0, 50, 50);
bell.center = self.center;
[self addSubview:bell];
}
return self;
}
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.1].CGColor);
CGContextMoveToPoint(context, 5, 0);
CGContextAddLineToPoint(context, 95, 0);
CGContextAddArcToPoint(context, 100, 0, 100, 5, 10);
CGContextAddLineToPoint(context, 100, 95);
CGContextAddArcToPoint(context, 100, 100, 95, 100, 10);
CGContextAddLineToPoint(context, 5, 100);
CGContextAddArcToPoint(context, 0, 100, 0, 95, 10);
CGContextAddLineToPoint(context, 0, 5);
CGContextAddArcToPoint(context, 0, 0, 5, 0, 10);
CGContextFillPath(context);
}
#end
If you want more complex functionality, you can implement public properties and a protocols
If you want to check it working look at it at GitHub... https://github.com/eharo2/BellAlert
for aesthetic reasons it would be preferable to implement something
similar to the round cornered fade in/out alert view used in IOS7
Rounding the corners of any view is incredibly easy:
someView.layer.cornerRadius = 5.0;
Making a view fade in and out is also trivial using Core Animation. For example, if you want to fade in someView, set its alpha property to 0 and then animate setting it to 1:
someView.alpha = 0.0;
[UIView animateWithDuration:1.0 animations:^{
someView.alpha = 1.0;
}];
With those tools at your disposal, you'll find it very easy to roll your own version of Apple's display.

Fill view with buttons at random positions

i want to fill area (UIView) with buttons(UIButton) so that they do not intersect with each others.
My idea:
create initial button at random position in view;
fill view with other buttons from initial button (count < 20) that they do not intersect ~10 pixels from each other.
What have i done so far:
I created method:
-(void)generateButtonsForView:(UIView *)view buttonCount:(int)count
{
//get size of main view
float viewWidth = view.frame.size.width;
float viewHeight = view.frame.size.height;
//set button at random position
UIButton *initialButton = [[UIButton alloc] initWithFrame:CGRectMake(arc4random() % (int)viewWidth,
arc4random() % (int)viewHeight,
buttonWidth, buttonHeight)];
[initialButton setBackgroundImage:[UIImage imageNamed:#"button"] forState:UIControlStateNormal];
[view addSubview:initialButton];
// set count to 20 - max number of buttons on screen
if (count > 20)
count = 20;
//fill view with buttons from initial button +- 10 pixels
for (int i=0;i<=count;i++)
{
//button
UIButton *otherButtons = [[UIButton alloc] init];
[otherButtons setBackgroundImage:[UIImage imageNamed:#"button"] forState:UIControlStateNormal];
...//have no idea what to do here
}
}
So i'm confused on the place where i want to generate the position of the other buttons, depending on the initial button. I do not know how to generate theirs position that they were at a distance of 5-10 pixels from each other... Any ideas how to realise this? Thanks!
Here's an example with views rather than buttons, but the concept is the same. I use CGRectInset to give the new potential view a buffer of 10 points around it, then look for whether the new view intersects any of the other views. If there's no intersection, add the subview, if there is, try again with a new random location.
-(void)generateButtonsForView {
float viewWidth = self.view.frame.size.width;
float viewHeight = self.view.frame.size.height;
UIView *initialView = [[UIView alloc] initWithFrame:CGRectMake(arc4random() % (int)viewWidth, arc4random() % (int)viewHeight, 50, 30)];
initialView.backgroundColor = [UIColor redColor];
[self.view addSubview:initialView];
int numViews = 0;
while (numViews < 19) {
BOOL goodView = YES;
UIView *candidateView = [[UIView alloc] initWithFrame:CGRectMake(arc4random() % (int)viewWidth, arc4random() % (int)viewHeight, 50, 30)];
candidateView.backgroundColor = [UIColor redColor];
for (UIView *placedView in self.view.subviews) {
if (CGRectIntersectsRect(CGRectInset(candidateView.frame, -10, -10), placedView.frame)) {
goodView = NO;
break;
}
}
if (goodView) {
[self.view addSubview:candidateView];
numViews += 1;
}
}
}

Resources