I added one UIScrollView in my project... and I added 10 more button "fieldButton" once, then the same UIScrollView I want add other 5 button. it I try to do this first added 10 button also coming in the scrollview .. how to remove first added 10 button before adding other item. in the same scrollview...
if(a == 1){
for(int i = 0; i< 10; i++){
UIButton *fieldButton_area = [[Mos_component alloc]getComboButton:title andFrame:CGRectMake(0, y, 180, 40)];
[fieldButton_area addSubview:cid];
[fieldButton_area addTarget:self action:#selector(get_Area:) forControlEvents:UIControlEventTouchUpInside];
[state_scroll addSubview:fieldButton_area];
}
}
else{
UIButton *fieldButton_state = [[Mos_component alloc]getComboButton:title andFrame:CGRectMake(0, y, 180, 40)];
[fieldButton_state addSubview:cid];
[fieldButton_state addTarget:self action:#selector(get_Area:) forControlEvents:UIControlEventTouchUpInside];
[state_scroll addSubview:fieldButton_state];
}
If you want just to clear your scrollview (i.e. remove all its subviews) then you can do that following way:
for (UIView* subView in [state_scroll subviews])
[subView removeFromSuperView];
If you want to remove some specific views you can check its types:
for (UIView* subView in [state_scroll subviews])
if ([subView isKindOfClass:[Mos_component class]]) // remove Mos_components only
[subView removeFromSuperView];
You can also assign tag property to you views and remove them following way:
[[fieldButton_area viewWithTag:yourTag] removeFromSuperView];
Also note that you must release your buttons somewhere or you will get memory leak.
You could also try animating the button(s) off of the screen or set the alpha's to 0 then add the new UIButton's to the view. This may use more memory, but in some cases look better.
[UIView BeginAnimation];
// set time and speed here
// Perform animation here
[UIView setAnimationDidStopSelector /* here call the method for the new button's animation into the view*/];
[UIView CommitAnimations];
// Then set the button's enabled property to NO
button.enabled = NO;
I hope this is of some assistance
Related
I want to have precise control over the custom view I add to my UINavigationController toolbar. More specifically.. i want to display a UILable ontop of the items in my toolbar.
I have a toolbarItems initially set up with some UIBarButtonItems. The effect I'm trying to achieve is programmatically expand the height of the toolbar, and then display a UILabel ontop of the rest of the buttons.. this is what I currently have:
-(void)expandToolBar:(NSString *)title {
UIToolbar* toolBar =self.navigationController.toolbar;
CGRect toolbarFrame = toolBar.frame;
[UIView animateWithDuration:0.25f delay:0
options:UIViewAnimationOptionLayoutSubviews animations:^{
// expand toolbar frame vertically
[toolBar setFrame:
CGRectMake(toolbarFrame.origin.x,
toolbarFrame.origin.y-15,
toolbarFrame.size.width,
toolbarFrame.size.height + 15)];
} completion:^(BOOL finished){
[UIView animateWithDuration:0.50f animations:^{
// some code here to move the existing toolbar items lower
// ie to make space for the label
UILabel* label = [[UILabel alloc] initWithFrame:labelFrame];
[label setBackgroundColor:[UIColor clearColor]];
label.text = title;
UIBarButtonItem *labelItem = [[UIBarButtonItem alloc]
initWithCustomView:label];
// add label to toolbar
NSMutableArray *newItems = [self.toolbarItems mutableCopy];
[newItems addObject:labelItem];
self.toolbarItems = newItems;
}];
}];
}
the result of this is that all the existing buttons get squashed, and the label takes their place. The problem is that If I try to get a little too creative and start manually messing with the subviews of the toolbar, I start wandering into undocumented API land, something Apple won't tolerate. Ideas?
What's your actual question? If what you're doing is legal or not? I use some similar tricks to get from the UIBarButtonItem to the view that is represented from it, and it has never been a problem.
For example, I use following snippet without any issues. Technically this isn't using private API per so, but relying on undocumented view structure and here also part of the class names, so you really should know what you're doing. Please also file a radar that UIBarButtonItem is messed up and misses an obvious flag to get to the actual view.
static UIView *PSToolbarViewForBarButtonItem(UIToolbar *toolbar, UIBarButtonItem *barButtonItem) {
UIView *barButtonView = nil;
for (UIControl *subview in toolbar.subviews) {
if ([NSStringFromClass([subview class]) hasPrefix:#"UIToolbarB"] && [subview isKindOfClass:[UIControl class]]) {
for (UIBarButtonItem *aBarButtonItem in [subview allTargets]) {
if (barButtonItem == aBarButtonItem) { barButtonView = subview; break; }
}
}
}
return barButtonView;
}
Also, if you go that route, write code that will fail gracefully if for any reason the view for the toolbar can't be found. I know some apps that go my route, while lots of others don't even bother and simply write their own code to create a toolbar.
I've added a UIView (which contains the UIImageView for the background, three UIButtons which say "Test" and the final UIButton to dismiss the view called "Finished") as a subview of my UIActionSheet.
Why won't any of these buttons detect touches? My UIView has User Interaction Enabled checked.
I'd appreciate some help with this as I've been pulling my hair out (not literally of course)!
Here's my set up:
If you're just looking mimic the UIActionSheet, I'd just create a UIVew subclass called something like "CoolActionSheet" and programatically place the buttons on there. Then, when you press the buttons it triggers a delegate method in a protocol which will be implemented in your main view controller so do something.
To show and hide the action picker use UIView animations in the CoolActionSheet class like so:
-(void)showSheet {
NSLog(#"Showing sheet...");
//Set the x/y position of the action sheet to JUST off-screen
CGFloat xPos = parentView.frame.origin.x;
CGFloat yPos = parentView.frame.size.height+kActionSheetHeight;
[self setFrame:CGRectMake(xPos, yPos, kActionSheetWidth, kActionSheetHeight)];
/*Here is where you would add your other UI objects such as buttons
and set their #selector to a method in your CoolActionSheet protocol. You could then implement this delegate method in
your main view controller to carry out a custom action. You might also want to add a background image to the view or something else.
For example: */
UIButton *coolButton = [[UIButton alloc] initWithFrame:buttonDimensions];
[coolButton addTarget:self action:#selector(didDismissActionSheet) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:coolButton];
[self.parentView addSubview:self.view];
//Slide the sheet up from the bottom of the screen
[UIView animateWithDuration:0.2 animations:^(void) {
//Slide banner in from left to right
[self setFrame:CGRectMake(0, yPos-kActionSheetHeight, kActionSheetWidth, kActionSheetHeight)];
}];
}
And to hide:
-(void)hideSheet {
NSLog(#"Hiding");
CGFloat xPos = parentView.frame.origin.x;
CGFloat yPos = parentView.frame.size.height+kActionSheetHeight;
[UIView animateWithDuration:0.2 animations:^(void) {
[self setFrame:CGRectMake(xPos, yPos, 320, 65)];
}completion:^(BOOL finished) {
[self removeFromSuperview]; //Clean up
}];
}
You may also want to grey-out the parent view. Again, in the CoolActionSheet.m:
-(void)shadeParentView {
UIView *shadedView = [[UIView alloc] initWithFrame:CGRectMake(, 0, 320, 480)];
[shadedView addGestureRecognizer:gestureRecognizer];
[shadedView setBackgroundColor:[UIColor blackColor]];
[shadedView setAlpha:0.0];
[self addSubview:shadedView];
[UIView animateWithDuration:0.5 animations:^{
[shadedView setAlpha:0.5];
}];
}
You would need to set your parentView to the view controller's view. So, to call the action sheet in your main view controller you would:
CoolActionSheet *coolSheet = [[CoolActionSheet alloc] init];
[coolSheet setParentView:self.view];
[coolSheet setSheetDelegate:self]; //set the delegate to implement button press methods in this view controller
This might seem a bit long-winded, but it's a good MVC pattern to separate it out into another view class like this. And you now have a custom class that you can just import into any other project and it'll work!
I haven't had a chance to test out this specific code, but the whole approach is good. Points to take away from this:
Use a custom UIView class
Implement delegate methods to execute tasks in your main view controller when a button is pressed in your subview.
Implement a good MVC structure to avoid spaghetti code.
Let me know if this helps :)
Try This:
[actionSheet showInView:self.view.window];
I have created buttons are programmatically and set the button tags.
View Did Load:
I have created one view and added the buttons are sub view into that view.
-(void) viewDidLoad
{
self.answerSubview = [[UIView alloc] initWithFrame:CGRectMake(0, 100, 320, 230)];
self.answerSubview.backgroundColor = [UIColor clearColor];
[self.view addSubview:answerSubview];
[self buttonCreation];
}
-(void) buttonCreation{
int x =100;
for(i = 0; i < 4; i++) {
UIButton *answerBtn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[answerBtn setFrame:CGRectMake(40, x, 260, 40)];
answerBtn.tag = ar[i];
[answerBtn setTitle:[answerList objectAtIndex:i] forState:UIControlStateNormal];
[self.answerSubview addSubview:answerBtn];
x = x+50;
}
}
And i want to set the background image for the certain index of the button, when the time is finished,
-(void) timerFinished
{
for (UIView* view in [self.answerSubview subviews]) {
if([view isKindOfClass:[UIButton class]]){
UIButton *btn = (UIButton*)view;
NSLog(#"button value %d", btn.tag);
if(btn.tag == correctIndex)
{
[btn setBackgroundImage:[UIImage imageNamed:#"selected_correct_answer.png"] forState:UIControlStateNormal];
}
}
}
}
But every time,the tag values are added into the stack,I have randomly generated numbers and set it into the button tags, so now it comes like,
REsult:
First time, Second time,
0 0
1 1
3 3
2 2
3
1
2
0
(Actually my expected result is 3 1 2 0).
So how could i remove the previous tag values and get the correct tag values at a time.
Please help me out.
There are two things you can consider doing. Since the only thing that changes on every iteration is the text on the button. You could probably reuse them. Setup once and put them in ivars. On every iteration, change the text and tag of the button.
If that is not the route you're interested in, you can probably send removeFromSuperview message to those four button objects.
However, the first method is a better approach in my opinion because it will do away with continuous creation-destruction cycle.
I am attempting to create a transition between two subviews (view1 and view2). When a button is pressed I want view1 (front) to flip and show view2 (back). I have tried both transitionFromView and transitionWithView. Each works - but each has a problem.
transitionFromView - flips the superview (the whole window view flips, not the subviews). When this flip happens - one subview is on the front of the superview before the flip, and the other subview is on the back of the flip - as it should be. But I don't want the superview to flip, just the subviews.
transitionWithView - flips only the subviews - but the 'to' view gets displayed before the transition happens.
Anyone have a suggestion?
-(IBAction) button1action:(id) sender {
if ([sender tag] == 0) {
[UIView transitionFromView:view2 toView:view1 duration:2.0
options:UIViewAnimationOptionTransitionFlipFromLeft
completion:nil];
}
else {
[view1 removeFromSuperview];
[self.view addSubview:view2];
[UIView transitionWithView:view2
duration:2.0
options:UIViewAnimationOptionTransitionFlipFromRight +
UIViewAnimationOptionShowHideTransitionViews
animations:^{}
completion:nil];
}
}
You need to remove and add the subviews in the animation block. Also, I think that transitionWithView is supposed to take the super view as argument. I think what you need to do to get this right is to use a container view that is the same size as the views you want to flip.
This is copied from the documentation:
[UIView transitionWithView:containerView
duration:0.2
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:^{ [fromView removeFromSuperview]; [containerView addSubview:toView]; }
completion:NULL];
I have run into this exact same problem, and I agree with the earlier answer. It seems you must have a container view for animating a transition from one subview to another subview.
I'm using the transitionFromView approach. To have a background behind the animation, you will also need a superview with the background for the container view.
My code looks like:
[UIView transitionFromView:view1
toView:view2
duration:0.5
options:UIViewAnimationOptionTransitionFlipFromRight |
UIViewAnimationOptionAllowUserInteraction |
UIViewAnimationOptionBeginFromCurrentState
completion:nil];
Here's my working solution stub, a simple thing that took 2 hours, damn:
we got 1 button to flip things, a UIView called panel that holds the 2 views I want to swap with a flip animation.
-(void)viewDidLoad{
[super viewDidLoad];
UIButton *btnFlip = [UIButton buttonWithType:UIButtonTypeRoundedRect];
btnFlip.frame = CGRectMake(10, 10, 50, 30);
[btnFlip setTitle:#"flip" forState:UIControlStateNormal];
[btnFlip addTarget:self action:#selector(flip) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btnFlip];
panel = [[UIView alloc] initWithFrame:CGRectMake(10, 40, 300,300)];
panel.backgroundColor = [UIColor darkGrayColor];
[self.view addSubview:panel];
panelBack = [[UIView alloc] initWithFrame:CGRectMake(10, 40, 280, 200)];
panelBack.tag = 1;
panelBack.backgroundColor = [UIColor brownColor];
[panel addSubview:panelBack];
panelFront = [[UIView alloc] initWithFrame:CGRectMake(10, 40, 280, 200)];
panelFront.tag = 2;
panelFront.backgroundColor = [UIColor whiteColor];
[panel addSubview:panelFront];
displayingFront = TRUE;
}
-(void)flip{
[UIView transitionWithView:panel
duration:0.5
options:(displayingFront ? UIViewAnimationOptionTransitionFlipFromRight : UIViewAnimationOptionTransitionFlipFromLeft)
animations:^{
if (displayingFront) {
//panelFront.hidden=TRUE;
//panelBack.hidden = FALSE;
[panelFront removeFromSuperview];
[panel addSubview:panelBack];
}else{
//panelFront.hidden=FALSE;
//panelBack.hidden = TRUE;
[panelBack removeFromSuperview];
[panel addSubview:panelFront];
}
}
completion:^(BOOL finished){
displayingFront = !displayingFront;
}];
}
Having run into the same problem I agree with Eric and Sam:
either transitionWithView or transitionFromView will both do what you want as given above as long as you create a container view of the appropriate size that you wish to flip. Otherwise the whole window view will flip.
So if view1 is the subview you begin with and you want to flip to view2 then add
UIView *containerView = [[UIView alloc] initWithFrame:appropriateSize];
[containerView addSubview:view1];
And then the simplest way to animate is probably:
[UIView transitionFromView:view1
toView:view2
duration:2.0
options:UIViewAnimationOptionTransitionFlipFromLeft
completion:nil];
I had the same requirement, and saw many approaches -- from using layers (which ends up very complicated if you just want to deal with a UIView) to suggestions that i needed a "container" to then transition between to sub-views. But if you just want to swithc something front to back, like flipping over a playing card or a game tile, i made a one line change:
(note: i have an array of UIViews (tiles[x][y]) in a grid (for a game). i have all my imagefilenames in database tables / arrays, which dynamically are loaded into the UIImages of the UIImageViews. The image for the "back" of a card or tile in a UIImage named "tileBackPicImageNM".
so my code that simply swapped the front image out for an image of the back was:
[tiles[indexX][indexY] setImage:[UIImage imageNamed:tileBackPicImageNM]];
which works fine.
but and now, to show a flipping action, it is:
[UIView transitionWithView:tiles[indexX][indexY] duration:0.3 options:UIViewAnimationOptionTransitionFlipFromLeft
animations:^{
[[indexX][indexY] setImage:[UIImage imageNamed:tileBackPicImageNM]];
}
completion:NULL];
I experimented with different "duration" parameters -- subsequently made it a float that I set in the viewDidLoad routine. Faster than 0.3 is almost not visible, and a value of 1 or 2 is very slow...
This does not involve two sub-views, which is my case is a lot more useful since i didn't want to have an array of containers containing a hierarchy of views, etc... and on new levels etc i always reload the arrays anyway...
Keep in mind that the container view requires a solid background color.It means anything else than clear color.This was my mistake and spent quite long time to figure it out.
using transitionFromView, both front and back view should be inside another view(not the super view). this way it will not flip the whole screen.
> superview
> another view
> backview
> frontview
UIView.transitionFromView(frontView, toView: backView, duration: 0.5, options: .TransitionFlipFromLeft | .ShowHideTransitionViews) { finished in
}
You might want to make the (another view) equal to the size of the frontView
Basically I want to remove all objects from a UIScrollView and I haven't yet found a solution to it because a simple "removeAllObjects" command doesn't work. Does anyone have an idea how to do it?
Even easier:
[[scrollView subviews] makeObjectsPerformSelector:#selector(removeFromSuperview)];
The easiest way:
for(UIView *subview in [scrollView subviews]) {
[subview removeFromSuperview];
}
Two solutions would be, without removing the scrollbars:
Add a tag to all of your subviews, remove them by using those tags.
Implementation:
Place this above your class
#define XPScrollViewSubviewStartTag 100
When you add the objects
for(NSInteger = 0;i<[viewArray count];i++){
UIView* view = [viewArray objectAtIndex:i];
view.tag = XPScrollViewSubviewStartTag + i;
[scrollView addSubview:view];
}
When you later want to delete the views use
for(UIView* view in [scrollView subviews]){
if(view.tag >= XPScrollViewSubviewStartTag)
[view removeFromSuperview];
}
Create a custom UIView class
When you want to remove the views
for(id view in [scrollView subviews]){
if(![view isKindOfClass:[CustomView class]])
continue;
//not necessary, but just to make things understandable
CustomView* customView = (CustomView*)view;
[customView removeFromSuperview];
}
Oritm's solution is nice, but if you don't want to bother using tags, you can manually remove which views you want to remove from the scrollview. This will assume that you know which view to remove. For example, my scrollview only has UILabels so when I run the following:
// This will remove the scrollview but the scrollbars will remain
for (UIView *subview in [self.detailsExpander.scrollView subviews]) {
if ([NSStringFromClass([subview class]) isEqualToString:#"UILabel"])
[subview removeFromSuperview];
}
This will only remove all the labels but keep the scrollbars (which are image views). Note: this won't work if you want to keep specific image views while at the same time you want to keep the scrollbars.