Move buttons down in UIAlertView - iphone

I have an app which displays in landscape mode and I've overwritten the height of a UIAlertView with the following code:
- (void) willPresentAlertView:(UIAlertView *)alertView
{
CGRect screenBounds = [[UIScreen mainScreen] bounds];
CGRect frame = [alertView frame];
alertView.frame = CGRectMake(frame.origin.x, 0, frame.size.width, screenBounds.size.width);
}
This almost works. The UIAlertView is taller, however, the buttons in the alertview don't get pushed down.
Does anyone know how I can push the buttons in a UIAlertView down when I change the alert view's height?

I think it is more elegant and less risky to replace UIAlertView with some independent AlertView instead of messing around with it.With independent I mean not inheriting form UIAlertView.
TSAlertView is such a replacement.
http://dl.dropbox.com/u/47535/TSAlertView/1-thumb.png
http://dl.dropbox.com/u/47535/TSAlertView/3-thumb.png
http://dl.dropbox.com/u/47535/TSAlertView/2-thumb.png

I'm guessing that you'll probably have to subclass / manipulate the UIAlertView class to achieve that, which can be risky as Apple can change their implementations so wrap your code in appropriate checks.
A start would be to do:
NSLog(#"UIAlertView subviews: %#",alertView.subviews);
That'll print some output for the various elements making up the UIAlertView, you will probably see a few UIButtons in there which you can then manipulate by using something like:
UIButton* button1 = (UIButton*)[alertView.subviews objectAtIndex:N];
[button1 setFrame:CGRect(button1.frame.origin.x, button1.frame.origin.y+10, button1.frame.size.width, button1.frame.size.height)]
A sensible check would be to confirm that the objectAtIndex is the correct type of element before you perform operations on it, this isn't foolproof however as Apple could add more UIButtons or something..
if ([[alertView.subviews objectAtIndex:N] isKindOfClass:[UIButton class]]) {
...
}
Depending on your situation you may also want to iterate over the subviews array and move all UIButtons down rather than just hardcoding in some specific objectsAtIndex but that's a whole other answer. :-)

This link should help. In my opinion, I would not try messing around with the view hierarchies. This can lead to rejection from the App Store. Either build a new AlertView from scratch, or leave it as it is.

NSArray *subViewArray=[alertView subviews];
for (NSUInteger ind=0 ; ind < [subViewArray count]; ind++) {
if ([[alertView.subviews objectAtIndex:ind] isKindOfClass:[UIButton class]]) {
UIButton* button1 = (UIButton*)[alertView.subviews objectAtIndex:ind];
[button1 setFrame:CGRectMake(button1.frame.origin.x, button1.frame.origin.y+100, button1.frame.size.width, button1.frame.size.height)];
NSLog(#"button1.frame.origin.y=[%1.0f]",button1.frame.origin.y);
}
}

Related

iOS: Removing one view from superview causes another to get removed?

This is a very odd problem. I have 5 subviews added to a UIViewController. One of them needs to be removed, but when I do this, one of the remaining 4 subviews is also removed. This necessitates that I re-add it using addSubview. The two views in question are not related in any way.
Is this a known iOS SDK bug? It happens for sure running on the simulator with iOS 6.1.
Thanks.
Here, In Your Question not mention That which Method you use for remove subView so,I give you simple suggestion for remove subView.
Give Tag of Each subView such like,
self.subView1.tag = 1;
self.subView2.tag = 2;
.
.
.
.
self.subViewN.tag = N;
And You can access(Remove) any subView base on its Tag, such like
[[self.view viewWithTag:1] removeFromSuperview];
This tips might helpful for you.
You can remove single subview using the following code.
[subview_Name removeFromSuperview];
if you want to remove all subviews form the view then use this.
NSArray *subViewArray = [self.view subviews];
for (id obj in subViewArray)
{
[obj removeFromSuperview];
}
if you want to remove all subview of particular class then use this.
NSArray *subViewArray = [self.view subviews];
for (id obj in subViewArray)
{
if([obj isKindOfClass:[classname class]])
{
[obj removeFromSuperview];
}
}
example : if you want to remove subview of UIImageView class then replace if condition with this.
[obj isKindOfClass:[UIImageView class]]

Add subview (rows) fast to UIScrollView while scrolling

I have UIScrollView with a lot of rows (~100) and I implemented dequeueReusableRow method for fast allocating and adding my subviews (rows). Everything work fine, but if I scroll very fast with decelerate some view don't added to scrollView on time only later.
- (UIView *)dequeueReusableRow
{
UIView *view = [reusableRows anyObject];
if(view)
{
[[view retain] autorelease];
[reusableRows removeObject:view];
}else{
view = [[UIView alloc] init....
}
return view;
}
- (void)addVisibleRows
{
UIView *row = [self dequeueReusableRow];
row.frame = ....
[scrollView addSubview:row]
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
[self addVisibleRows];
[self removeInvisibleRows];
}
Please, don't propose me use UITableView because structure of accordion looks like:
section
- section
-- section
--- row
- section
section
- row
dequeueReusableRow is not part of UIScrollViewController, so I assume dequeueReusableRow is something you implemented yourself. If so, can you show that code? It is likely where we can help with any inefficiencies.
Also, if your scrollview contains rows, why not just use a UITableView which will do much of the work for you? I know you asked not to propose it - can you explain why you need to use a ScrollView so we can help you better?
It's very hard to tell from that code snippet. Some more details would be appreciated.
One minor suggestion in the meantime: Call removeInvisibleRows before addVisibleRows

How can I set a maximum on the number of pages in a TTLauncherView?

I'm using TTLauncherView as a sort of home screen for my app and I only have one page's worth of icons. How can I make it so the TTLauncherView won't let you drag icons to "the next page"? I want to set a maximum number of pages (in this case one.)
(EDIT: long story short, I subclassed beginEditing, see the answer below.)
I see where why it adds an extra page when beginEditing is called, but I don't want to edit the framework code. (That makes it hard to update to newer versions.) I'd also prefer not to subclass and override that one method, if I have to rely on how it's implemented. (I'm not against subclassing or adding a category if it's clean.)
I tried setting scrollView.scrollEnabled to NO in the callback method launcherViewDidBeginEditing in my TTLauncherViewDelegate, but that doesn't work while it's in editing mode and I don't know why.
I tried adding a blocker UIView to the scrollview to intercept the touch events by setting userInteractionEnabled=NO, which works OK. I still have to disable the dragging of TTLauncherItems to the next page somehow.
I also tried setting the contentSize of the scrollview to it's bounds in launcherViewDidBeginEditing, but that didn't seem to work either.
Is there a better way?
Tried to block gestures:
- (void)setLauncherViewScrollEnabled:(BOOL)scrollEnabled {
if (scrollEnabled) {
[self.scrollViewTouchInterceptor removeFromSuperview];
self.scrollViewTouchInterceptor = nil;
} else {
// iter through the kids to get the scrollview, put a gesturerecognizer view in front of it
UIScrollView *scrollView = [launcherView scrollViewSubview];
self.scrollViewTouchInterceptor = [UIView viewWithFrame:scrollView.bounds]; // property retains it
UIView *blocker = self.scrollViewTouchInterceptor;
[scrollView addSubview:scrollViewTouchInterceptor];
[scrollView sendSubviewToBack:scrollViewTouchInterceptor];
scrollViewTouchInterceptor.userInteractionEnabled = NO;
}
}
For reference: TTLauncherView.m:
- (void)beginEditing {
_editing = YES;
_scrollView.delaysContentTouches = YES;
UIView* prompt = [self viewWithTag:kPromptTag];
[prompt removeFromSuperview];
for (NSArray* buttonPage in _buttons) {
for (TTLauncherButton* button in buttonPage) {
button.editing = YES;
[button.closeButton addTarget:self action:#selector(closeButtonTouchedUpInside:)
forControlEvents:UIControlEventTouchUpInside];
}
}
// Add a page at the end
[_pages addObject:[NSMutableArray array]];
[_buttons addObject:[NSMutableArray array]];
[self updateContentSize:_pages.count];
[self wobble];
if ([_delegate respondsToSelector:#selector(launcherViewDidBeginEditing:)]) {
[_delegate launcherViewDidBeginEditing:self];
}
}
I think overriding beginEditing in TTLauncherView is your best bet. Since you'd only really be touching one method (and only a few lines in that method), upgrading it when the time comes shouldn't be too bad. Since that method explicitly adds the extra page, I'm not sure how you'd get around it w/o editing that specific piece of code
As Andrew Flynn suggested in his answer, I was able to make it work by subclassing and overriding the beginEditing method to remove the extra page TTLauncherView adds when it goes into editing mode.
One problem I'm having is I can't figure out how to remove the warning I get for calling the (private) method updateContentSize on my subclass. I tried casting it to id, but that didn't remove the warning. Is it possible?
edit: I was able to remove the warning by using performSelector to send the message to the private class. (I had previously create a category method performSelector:withInt that wraps NSInvocation so that I can pass primitives via performSelector methods, which makes this very convenient.)
// MyLauncherView.h
#interface MyLauncherView : TTLauncherView {
NSInteger _maxPages;
}
#property (nonatomic) NSInteger maxPages;
#end
// MyLauncherView.m
#implementation MyLauncherView
#synthesize maxPages = _maxPages;
- (void)beginEditing {
[super beginEditing];
// ignore unset or negative number of pages
if (self.maxPages <= 0) {
return;
}
// if we've got the max number of pages, remove the extra "new page" that is added in [super beginEditing]
if ([_pages count] >= self.maxPages ) {
[_pages removeLastObject];
[self updateContentSize:_pages.count]; // this has a compiler warning
// I added this method to NSObject via a category so I can pass primitives with performSelector
// [self performSelector:#selector(updateContentSize:) withInt:_pages.count waitUntilDone:NO];
}
}

How do Ioop through all controls and act on certain ones?

I have an iPad application that adds buttons at runtime based on where the user touches within the view.
Now - I need to remove all these buttons at once.
I have set the tag of each button to be very high and grouped by type of button that was dropped.
How do I loop through all the button on the view and remove them if they fall into the right classification??
This removes all UIButtons. Adopt it to your needs. If you want to use tags I would recommend to tag every button that should stay in the view.
for (id object in [self.view subviews]) {
if ([object isKindOfClass:[UIButton class]]) {
[object removeFromSuperview];
}
}
Or you could add each UIButton to an NSMutableSet when you create them, and delete every button of the set if you don't need them anymore.
The only tag-based method is UIView#viewForTag and it returns a single object. (I believe it's the last view you added with that tag). But, you can adapt the above code for your purposes:
for (UIView *iView in [self.view subviews]) {
if (iView.tag == TARGET_CLASSIFICATION_TYPE) {
[iView removeFromSuperview];
}
}

Problem releasing object using "removeFromSuperView" iPhone

I have this concrete problem, but if You find my initial design idea crazy and have a better suggestion, please let me know:)
I have a UIView that acts as a container/background for adding other views. The important thing is that only one view is present at a time. So before doing any adding of views I do this:
for(UIView *v in [self.currentView subviews]) {
[v removeFromSuperview];
}
self.currentView is the view I add my subviews to.
After this I add a new UIView in this manner:
UIView *tempView;
switch (self.currentIndex) {
case 1:
tempView = [[AView alloc] initWithFrame:frame];
[self.currentView addSubview:tempView];
[tempView release];
break;
case 2:
tempView = [[AView alloc] initWithFrame:frame];
[self.currentView addSubview:tempView];
[tempView release];
break;
default:
break;
}
This way I remove all views, since I release the tempView straight after I add it to
the self.currentView I end up with a retain count of one on the the UIView currently living
in the currentView.
This all seems fine, but as I look at it with Instruments I can see that each time I run the above code a new AView object is allocated and the old one keeps hanging around with a retain count of 1, either I am missing some obvious retain action being performed on my object or else the "removeFromSuperView" does not call "release" on my view.
In real life my objects are not of type AView, but of many different types, but this way I can test if there is always only one AView instance allocated.
As I can read from the documentation "removeFromSuperView" should call "release" on the view so I am a bit confused as to why my Views are not deallocated.
Again, maybe I am going about this the wrong way and suggestions are really welcome.
The setup is that there is a number of button at the bottom of the screen and when the user clicks on the view changes.
Thanks for any help or pointers given:)
You are iterating a collection and simultaneously changing it
Try
while ([self.currentView subviews].count>0) {
[[[self.currentView subviews] objectAtIndex:0] removeFromSuperView];
}
instead.
you could try the "bringSubviewToFront" and "sendSubviewToBack" functions instead of creating a new UIView everytime. That ways, you won't be creating uiviews for every action and therefore be less pressing on the memory consumption of your application.