Problem in inserting segmented control to header view - iphone

I'm trying to add a UISegmentedControl in my tableview. I have two sections in my tableview and I want the segmented control to be placed in the 2nd section. In my implementation, I override viewForHeaderInSection as follows.
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
if (section == 1)
{
UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(10, 0,tableView.bounds.size.width, 10)] autorelease];
NSArray *segmentTextContent = [NSArray arrayWithObjects:NSLocalizedString(#"Singles", #""), NSLocalizedString(#"Everyone", #""),nil];
UISegmentedControl *segmentedControl = [[[UISegmentedControl alloc] initWithItems:segmentTextContent] autorelease];
segmentedControl.selectedSegmentIndex = 1;
segmentedControl.autoresizingMask = UIViewAutoresizingFlexibleWidth;
segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
segmentedControl.frame = CGRectMake(0, 0, tableView.bounds.size.width+10, 20);
[segmentedControl addTarget:self action:#selector(loadTable:) forControlEvents:UIControlEventValueChanged];
[headerView addSubview:segmentedControl];
return headerView;
}
else
{
UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(10, 0,tableView.bounds.size.width, 10)] autorelease];
return headerView;
}
}
My problem is that once I select a particular segment, it doesn't appear to be selected. i.e. it's not getting dark colored as expected. I have placed the segmented control in my navigation bar earlier and it colors the segment after selection as expected.
Any help would be highly appreciated.
Thanks

This is a late reaction, but I ran into the same issue and figured out the problem. In the code above, the headerView is recreated everytime the tableView calls reloadData (which in my occurs after I resort the data based on a click on the segmentedControl), and therefore the segmented control goes back to its original state, and touches are not apparently reflected.
To solve this, I made segmentedControl an ivar, and check if it already exists. If so, then just call
[headerView addSubview: segmentedControl];
otherwise do the whole setup of the control.
Hope this helps.

Had you ever found the answer to this? I implemented virtually the same thing and it worked fine. My guess is that you have sized you control bigger than the bounds of the view.
CGRectMake(0, 0, tableView.bounds.size.width+10, 20)
I believe this will cause a control not to receive touch events in all cases.

Related

Why is my UIButton not added to the custom header view of my viewForSectionHeader

I have this following code to add a button to my custom header for section.
-(UIView*)tableView:(UITableView*)tableView viewForHeaderInSection:(NSInteger)section {
if (tableView == menuListTableView) {
UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, 40)] autorelease];
UIButton *headerButton = [UIButton buttonWithType:UIButtonTypeCustom];
[headerButton setFrame:CGRectMake(0, 0, tableView.bounds.size.width, 40)];
[headerButton setImage:[UIImage imageNamed:#"Gray_Gradient.png"] forState:UIControlStateSelected];
[headerButton addTarget:nil action:#selector(toggleOpen:) forControlEvents:UIControlEventTouchUpInside];
[headerView addSubview:headerButton];
return headerView;
}
return nil;
}
Why is my button not added to the custom header view?? The sub view array of the headerview seems to be nil when checked in the debugging mode.
Did you see the header view itself? Check the height of the header view. Also check whether the image exists. If in doubt, change the button type to rounded rect and see whether it was added properly.
Oh I got the answer myself!!! I looked at the button code.. and the control state was set to UIControlStateSelected. instead of UIControlStateNormal. Its so ignorant of me. Sorry guys for the bothering!!

UISegmentControl behaves unusual when placed in tableView's header

I have some problem implementing a segment control. Because i want it to be a fixed header so when i scroll i can always see it, i've implemented it in the
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
All is well till here, the segment control appears. The problem is when the segments are clicked. Although the function implemented with a selector is called and the segment control has the correct selectedSegmentIndex, the segments are not highlighted except the one that is initially set with the
sortControl.selectedSegmentIndex = 0; in the viewForHeaderInSection . This Segment interacts being highlighted and non-highlighted (when pressed again). Another weird thing is that when i press the other segments, the segment at 0 becomes highlighted.
Here is the complete code for the viewForHeaderInSection :
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIColor *tintColor = [UIColor colorWithRed:241.0/255 green:78.0/255 blue:35.0/255 alpha:1];
sortControl = [[UISegmentedControl alloc] initWithItems:
[NSArray arrayWithObjects:#"Distance", #"Rating", #"Name", nil]];
sortControl.segmentedControlStyle = UISegmentedControlStyleBar;
sortControl.tintColor = tintColor;
sortControl.frame = CGRectMake(20, 20, 280, 35);
sortControl.selectedSegmentIndex = 0;
[sortControl addTarget:self action:#selector(sortChanged) forControlEvents:UIControlEventValueChanged];
UIView *view=[UIView new];
view.frame = CGRectMake(0, 0, 320, 70);
view.backgroundColor =[UIColor blueColor];
[sortControl setEnabled:YES forSegmentAtIndex:0];
[sortControl setEnabled:YES forSegmentAtIndex:1];
[sortControl setEnabled:YES forSegmentAtIndex:2];
view.userInteractionEnabled = YES;
[view addSubview:sortControl];
return view;
}
You have here two kind of problems:
the first one has been arisen by AliSoftware in his previous response: you must set the momentary property to NO to avoid the flickering issue.
But the main problem is in the way you use the tableView:viewForHeaderInSection: delegate method. In this method you are recreating each time the same view, with two bad effects:
- the first is visible in your app: the segmented control is re-initialized and the selected button is set to the first one (index 0)
- the second is adding a memory leak each time the method is called by the table view. Consider that this method is called multiple times by the table view and out of your control: essentially each time the header is scrolled outside the screen and then it re-enters, the table needs to regenerate the view and calls the method again. On your code the segment is created but never released thus leaking.
The solution to this problem is to define a single instance for the header, set it initially to nil and then check if it is nil or not. If nil create it, if not use the previously generated instance.
Another possible way to do this is in the code below. So create a static instance and use GCD's dispatch_once to create the segmented control only the first time. In this case you will never lose the current control status as it will be reused at each header call. You can improve the performance by also moving the whole header UIView creation inside the dispatch_once block, so avoiding extra allocs each time.
static UISegmentedControl *sortControl;
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
UIColor *tintColor = [UIColor colorWithRed:241.0/255 green:78.0/255 blue:35.0/255 alpha:1];
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sortControl = [[UISegmentedControl alloc] initWithItems:
[NSArray arrayWithObjects:#"Distance", #"Rating", #"Name", nil]];
sortControl.segmentedControlStyle = UISegmentedControlStyleBar;
sortControl.tintColor = tintColor;
sortControl.frame = CGRectMake(20, 20, 280, 35);
sortControl.selectedSegmentIndex = 0;
});
[sortControl addTarget:self action:#selector(sortChanged) forControlEvents:UIControlEventValueChanged];
UIView *view=[UIView new];
view.frame = CGRectMake(0, 0, 320, 70);
view.backgroundColor =[UIColor blueColor];
sortControl.momentary = NO;
[sortControl setEnabled:YES forSegmentAtIndex:0];
[sortControl setEnabled:YES forSegmentAtIndex:1];
[sortControl setEnabled:YES forSegmentAtIndex:2];
view.userInteractionEnabled = YES;
[view addSubview:sortControl];
return view;
}
This is because you set sortControl.momentary = YES;.
This property makes each segment of your SegmentedControl behaves like a "momentary button", meaning that when touching a segment, the segment is highlighted, then it triggers the event, and when you stop touching it comes back to its original state.
Removing this line (or setting this property to NO) should solve your issue.

UIScrollView and UIPageControl within UITableView

I've seen lots of sources saying it is possible to include a UIScrollView with UIPageControl inside a UITableViewCell to be able to scroll horizontally (through a list of selectable images), but can't find any raw examples that does what I want. I've gotten my scroll view "working", but I am unsure how to go forward - hopefully someone can send me some guidance.
Within my cellForRowAtIndexPath, I create a cell, and add both a scrollView and pageControl as subviews.
UITableViewCell *cell = [self.challengeListView dequeueReusableCellWithIdentifier:SubmitChallengeCellIdentifier];
if(cell == nil){
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:SubmitChallengeCellIdentifier] autorelease];
cell.frame = CGRectMake(0, 0, 1000, 50);
}
scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, tv.frame.size.width, 50)];
[scrollView setContentSize:CGSizeMake(1000, 50)];
[[cell contentView] addSubview:scrollView];
pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, 50, tv.frame.size.width, 50)];
[pageControl setNumberOfPages:4];
[[cell contentView] addSubview:pageControl];
I've attached a screenshot of what's being displayed
the bottom portion of the main view is my UITableView that contains the scrollView/pageControl (and it will scroll horizontally, as I can see the scrollerIndicator showing this), and I've got its method's set to the following:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
My Scroll view will indicate a "horizontalScroller" and I am able to scroll back and forth, but obviously there's no content there. How do I go about populating the tableView/scrollView with say, a list of "clickable" images? Any direction would be greatly appreciated - preferably not a "hey this guy's done it somewhat similar, check out this link" but maybe more an explanation of how this functionality should be implemented correctly (ESPECIALLY in regards to iOS 3.0+ - it is my understanding Apple has made our lives easier in implementing this)
I've solved my own problem; maybe the reason no once answered me is because its a minor implementation once you understand each view's purpose.
From within cellForRowAtIndexPath:
I created a standard UITableViewCell, however I altered the frame of the cell to my own custom frame of 1000 width by 50 height (catered to my needs for project).
I then created a UIScrollView, set it to the following (keep in mind I have my tableView defined in IB, so I'm mapping some of my height/widths to those values):
scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, tv.frame.size.width, 78)];
I then create the desired image view (I realize I will next create a loop that does many images and lays them out across the scroll view):
UIImage *image = [UIImage imageNamed:#"dummy.png"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.frame = CGRectMake(0, 0, 80, 78);
[scrollView addSubview: imageView];
Here's the part I was missing. After adding the scrollView to the cell contents, you need to use the UIPageControl (which didn't seem obvious to me for this implementation at first) to setup the actual "visual horizonal scrolling" affect:
[[cell contentView] addSubview:scrollView];
pageControl = [[UIPageControl alloc] initWithFrame:CGRectMake(0, 50, tv.frame.size.width, 50)];
[pageControl setNumberOfPages:4];
[[cell contentView] addSubview:pageControl];
Hope that helps someone's search - I spent quite some time on Google looking for the example I just explained and didn't have much luck other than the general overview of how it would work.

iPhone: Add "loading" subView

I am wanting to show a simple loading dialog when certain things are happening in my app. I figured I would just create a new view, add a label to that, and then set that view to a subView of my current view.
When doing this, I don't see anything!
Here is how I am writing my method:
- (void)showLoading {
UIView *loading = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
loading.backgroundColor = [UIColor blackColor];
UILabel *txt = [[UILabel alloc] initWithFrame:CGRectMake(198, 9, 94, 27)];
txt.text = #"Loading...";
txt.textColor = [UIColor whiteColor];
[loading addSubview:txt];
[super.view addSubview:loading];
[super.view bringSubviewToFront:loading];
[loading release];
[txt release];
}
Am I doing this completely wrong?
EDIT:
I added it to the viewDidLoad method, and it works how I want:
loading = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
loading.backgroundColor = [UIColor blackColor];
UILabel *txt = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 94, 27)];
txt.text = #"Loading...";
txt.textColor = [UIColor whiteColor];
[loading addSubview:txt];
[txt release];
[self.view addSubview:loading];
[self.view bringSubviewToFront:loading];
But when loading it from a method, it seems to lag, and not show up for a bit.
Although this doesn't directly answer your question, I'd recommend grabbing MBProgressHUD from GitHub and using that in place of a static label. Looks better, less code for you to directly maintain, etc. You can find it at http://github.com/matej/MBProgressHUD
The way I use it is by creating a subclass of UITableViewController and defining a handful of methods to show and hide the HUD view. From there, I call each relevant method when I'm loading or done loading.
Specifically, I have four methods: -hudView, -showLoadingUI, -showLoadingUIWithText:, and -hideLoadingUI.
-hudView creates a new MBProgressHUD object if one doesn't already exist, and adds it to the current view ([self.view addSubview:hudView]).
-showLoadingUI calls -showLoadingUIWithText: with a default title, -showLoadingUIWithText: just unhides the MBProgressHUD and sets a label value for it (self.hudView.labelText = #"foo";).
-hideLoadingUI hides the hudView ([self.hudView hide:YES]).
First, I don't think UIView has method called init. You may just call the super of it. The appropriate method you should call is - (id)initWithFrame:(CGRect)aRect . The frame is the position, the size of the View you want to display. More here
Another thing is why you call [super.view addSubView:], I think it should be self.view, isn't it?

How to access a UIActivityIndicatorView in a UITableView's section header view?

I want to do something pretty simple with my UITableView: I want to add a UIActivityIndicatorView to a section's header view, and make it animate or disappear whenever I want.
I had no trouble adding the UIActivityIndicatorView to the header view using tableView:viewForHeaderInSection:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
UIView* customView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 60.0)];
// create the title
UILabel * headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(15.0, 12.0, 310.0, 22.0)];
headerLabel.text = #"some random title here";
[customView addSubview:headerLabel];
[headerLabel release];
// Add a UIActivityIndicatorView in section 1
if(section == 1)
{
[activityIndicator startAnimating];
[customView addSubview:activityIndicator];
}
return [customView autorelease];
}
activityIndicator is a property of my controller's class.
I alloc it in the viewDidLoad method:
- (void)viewDidLoad
{
(...)
activityIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(200, 10, 25, 25)];
}
This way I can send messages to it (like -startAnimating or -stopAnimating) whenever I want.
The problem is that the activityIndicator disappears as soon as I scroll the tableView (I guess it is because the tableView:viewForHeaderInSection: method is called a second time).
How else can I add an activityIndicatorView to the section's header view and still be able to send messages to it afterwards? (with the activityIndicator not disapearing when I scroll down of course)
Thank you very much!
If you try to use the same activity indicator in multiple places then it is probably getting moved from one place to the other. I believe you need a different one for every single section header. You might want to use a MutableArray to keep track of the header views you create so you can reuse them if you find one in the array that doesn't have a superview, sort of like dequeuing and reusing cells.
This is just a guess as I haven't done this, but I'm pretty sure the issue is trying to reuse the same view in multiple places.
The problem seemed to be caused by re-creating a customView and adding the activityIndicator as a subview every time tableView:viewForHeaderInSection: is called.
Not using subviews helped me fix it:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
// Add a UIActivityIndicatorView in section 1
if(section == 1)
{
[activityIndicator startAnimating];
return activityIndicator;
}
UIView* customView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 60.0)];
// create the title
UILabel * headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(15.0, 12.0, 310.0, 22.0)];
headerLabel.text = #"some random title here";
[customView addSubview:headerLabel];
[headerLabel release];
return [customView autorelease];
}
(it looks quite ugly though, the activityIndicator takes the whole width of the section. I'd better create a unique customView for section 1 and add the activityIndicator as a subView once and for all).