I have a UIPopoverViewController that is displaying a custom UIViewController properly. When I click a button I have an action run and as a result I add a view to the view hierarchy of the UIViewController's view.
The problem is that it is very slow, and takes several seconds for the view to appear. I'm not doing anything out of the ordinary with my UIViewController's code.
- (void)showAccountChooser {
self.twitterAccountPicker = [TwitterAccountPicker new];
[self.view addSubview:self.twitterAccountPicker.view];
self.twitterAccountPicker.view.frame = self.view.bounds;
self.twitterAccountPicker.view.transform = CGAffineTransformMakeScale(.05, .05);
[UIView animateWithDuration:0.5f animations:^{
self.twitterAccountPicker.view.transform = CGAffineTransformMakeScale(1, 1);
} completion:^(BOOL finished) {
//[self.twitterAccountPicker viewDidAppear:YES];
}];
}
The UIViewController that I'm adding is trivial and does not heavy processing in the viewDidLoad or viewWill/DidAppear. I have set break points and verified that it is not doing anything bad.
Anyone else notice this when adding views?
After setting break points trying to debug this, I realized that my showAccountChooser method was being called from a block invoke, which was happening on a background thread. Moving this call to the main thread resolved the issue.
Related
I have a viewController displaying images and text and the images are loaded and being animated every 15 seconds, I'd like to allow the user to swipe on the image view allowing him to change the image without waiting for the time to pass.
this is what I tried the images are loaded and animated but the swipe gesture doesn't work
self.imageView.animationImages = [self loadImages];
self.imageView.animationDuration = 15;
[self.imageView startAnimating];
swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeAction:)];
[swipeRight setDirection:(UISwipeGestureRecognizerDirectionRight)];
[self.imageView addGestureRecognizer:swipeRight];
this code is placed in the viewDidLoad method, I saw a solution adding the gesture to the view but I need it only on the imageView
I'm answering this in case someone else spends too much time on this one it appears i forgot to enable user interaction add this line:
self.imageView.userInteractionEnabled = YES;
I load a view controller in my code using a segue in UIStoryboard. Based on a few user selected options, I then hide or show a UI control using an animation. It all works fine.
- (void)showComments {
NSLog(#"Show Comments");
_commentsTextView.hidden = NO;
_commentsTextView.frame = CGRectMake(435, 266, 475, 134);
[UIView animateWithDuration:1 animations:^{
_commentsTextView.alpha = 1;
_signatureButton.frame = CGRectMake(435, 420, 475, 134);
_cancelButton.frame = CGRectMake(568, 581, 100, 44);
_finishedButton.frame = CGRectMake(676, 581, 100, 44);
}];
}
Then I am presenting a view controller created in UIStoryboard using the following code:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard_iPad" bundle:nil];
SigningViewController *signingVC = (SigningViewController *)[storyboard instantiateViewControllerWithIdentifier:#"SigningViewController"];
signingVC.object = self;
signingVC.signatureProperty = #"employeeSignature";
signingVC.startDate = self.startDate;
signingVC.endDate = self.endDate;
[self presentViewController:signingVC animated:YES completion:nil];
When this code fires all happens as expected except for one thing: All the custom animations that hid or showed a UI control revert back. It is as if by calling the presentViewController method, it is redrawing my existing view from the UIStoryboard.
Is there a way to get it to quit redrawing/reload my existing view from the Storyboard before displaying the new view modally?
I had the same problem too. Whatever I tried to make an animation change whenever a modal closed it seemed to reset back to the original storyboard.
The solution I had to go with was to add any animation view as an outlet to the header file. Take off the view out of the self.view or main view of the view controller on the storyboard and programmatically add it as a subview. Set the frame to where you want it and all the animation positions should be the same after you end the modal. It worked for me if you need more explanation and let me know.
I had just the same problem and posted it here in a more detailed form, A user named kokx helped me a lot and the answer is documented in my question page.
UITableViewCell becomes unresponsive this was a very different problem with a very different solution.
My tableView which is a subView in a UIViewController initially works fine and I can select individual rows in the table. However, I have created my own popup when a row is selected (the popup is a UIView) that appears towards the bottom of the screen. As this pops-up I also create a another UIView which covers the screen behind the popup and it makes the background go dim. The third thing that happens is that i create a UITapGestureRecogniser to keep track of the user's taps, and if they tap outside the UIView then the two UIViews and the TapGestureRecogniser are removed and call the deselectRowAtIndex... method.
However, it is at this point that I cannot use the tableView, as i want to be able to select a different string within the tableView and the popup to appear again (the popup will eventually contain links that will enable the user to move to different viewControllers).
I have tried to reload the data, remove the tableview and replace it, edit the didSelectRowAtIndex, remove the deselectRowAtIndex method, however nothing I tried seems to work and i can't find anything on stackoverflow as my question seems to be quite specific (although I apologise if there is something out there).
I'll add a few parts of my code in, however, I'm not sure where the problem is and I may not have copied the right part in.
The remove overhead is the selector method from the tapGesture
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(_popOverView == nil)
{
_popOverView = [[UIView alloc]initWithFrame:CGRectMake(20, 200, 280, 150)];
_popOverView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"wood.jpeg"]];
}
if(_mask == nil)
{
_mask = [[UIView alloc] initWithFrame:self.view.frame];
[_mask setBackgroundColor:[UIColor colorWithWhite:0.0 alpha:0.78]];
}
if (_tapDetector == nil)
{
_tapDetector= [[UITapGestureRecognizer alloc]initWithTarget:self action:#selector(removeOverHead:)];
}
[self.view addSubview:_mask];
[self.view addSubview:_popOverView];
[self.view addGestureRecognizer:_tapDetector];
}
-(void) removeOverHead:(UITapGestureRecognizer*) sender
{
CGPoint locationOfTap = [_tapDetector locationInView:self.view];
if (locationOfTap.y < (200 + 150) && locationOfTap.y > 200 && locationOfTap.x > 20 && locationOfTap.x < (20 + 280) ) {
NSLog(#"%f,%f",[_tapDetector locationInView:self.view].x,[_tapDetector locationInView:self.view].y);
}
else
{
[_mask removeFromSuperview];
[_popOverView removeFromSuperview];
[_tapDetector removeTarget:self action:#selector(removeOverHead:)];
/*this idea doesn't work :(
[self.tableView removeFromSuperview];
[self.view addSubview:_tableView];*/
}
}
I really hope the answer is in here and is very simple, and thank you in advance for taking the time to read this.
Solved it! Sorry for wasting your time. It was the wrong remove method for the gestureRecogniser. I replaced
[_tapDetector removeTarget:self action:#selector(removeOverHead:)]
with
[self.view removeGestureRecognizer:_tapDetector]
as the UIGestureRecogniser was lingering and obstructing the tableView!!
If you stick a breakpoint or NSLog() inside the else block of that remove method, do you get inside it?
It sounds like your if statement might be off. You should use CGRectContainsPoint(). However if I understand correctly, you're attempting to dismiss everything when the user taps the dimming background view. You could make this view a button or you could compare the touch's view pointer to the pointer to the background view.
i am making a customized back button which works exactly as a real back button does. below is my code
UIButton *cusBack = [UIButton buttonWithType:101];
[cusBack setTitle:#"Back" forState:UIControlStateNormal];
[cusBack addTarget:self action:#selector(clickBack) forControlEvents:UIControlEventTouchUpInside];
self.view addSubView:cusBack;
and here is my selector:
-(void)clickBack{
PrevPage *pPage = [[PrevPage alloc] init];
[self.navigationController pushViewController:pPage animated:YES];
[pPage release];
}
actually, it works but the direction it creates is from RIGHT to LEFT. but I want the page to move from LEFT to RIGHT since it goes back to the recent page
thank you!
If you want to have the same behavior as the back button you should try another approach:
-(void)clickBack{ //Your presenting view controller will always be the last view controller on the stack.
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:self.navigationController.viewControllers.count-1] animated:YES];
}
Also, if you need to do some changes to the previous view controller, all you need to do is import it's header file and then you can use it's properties and public methods before popping the view controller.
#import "MyPreviousViewController.h"
...
-(void)clickBack{
[self.navigationController.viewControllers objectAtIndex:self.navigationController.viewControllers.count-1].title = #"Change title for previous view controller";
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:self.navigationController.viewControllers.count-1] animated:YES];
}
Currently, your back button doesn't work as the real back button does, because, instead of popping the last view controller off the stack(also releasing the objects), you actually keep pushing new view controllers on the stack. You might have some issues if this stack gets too big.
I have a UINavigationController which contains several UIViewControllers. I would like to create a shared "panel" that is displayed at the top of each view. In addition, I would like to make that panel expand and collapse, overlaying the view, when tapped.
View1
-Top Panel (collapsible)
-Main Panel
View2
-Top Panel (collapsible)
-Main Panel
This would be similar to the way the toolbar or navigation panel hide/show for the camera controller, but it would be a custom view. This is an iPhone app.
As a new XCode developer I would appreciate insights as to how this should be approached from an architectural standpoint.
Create a UIViewController subclass, say called PanelStyleUIViewController,
which would be a superclass for all the views that will have the panel. The superclass implements the panel's controller logic, and the view expansion and contraction, which always happens above the children controller's regular view logic.
This is going to be a modestly difficult project for a new iOS/cocoa developer, because:
You probably will end up having to write a lot of the folding panel's view code programmatically. It is possible to design it in interface builder using more advanced techniques but IB's basic usage is to design one view controller at a time. You need to design a partial, parent view controller that then is inherited to a number of different ones.
You need to make sure that the folding view is always above (z-index wise) the regular view content of the lower level view controller classes. This is something that is probably solved by doing a bringSubviewToFront call on the panel view on, say, the viewDidAppear method.
You are going "off road" from how standard iPhone apps behave. Whenever you do this, you make headaches for yourself and might find yourself at a dead end. My recommendation would be to stay "inside the lines" for a while until you are pretty confident with objective C, cocoa touch, etc.
That said, here's some untested code I wrote here in the stack overflow editor which should give you an idea of what I mean for this superclass design:
// PanelStyleUIViewController.h
#interface PanelStyleUIViewController : UIViewController {
UIView *panelView;
}
#property (nonatomic, retain) UIView *panelView;
// PanelStyleUIViewController.m
#implementation PanelStyleUIViewController
#synthesize panelView;
- (void)viewDidLoad {
[super viewDidLoad];
// setup geometry, contents, etc of panelView programmatically...
self.panelView = [[[UIView alloc] init] autorelease];
panelView.frame = CGRectMake(0,0,320,200);
// set resizing mask appropriately for landscape support
panelView.autoresizingMask = UIViewAutoresizingMaskFlexibleWidth | UIViewAutoresizingMaskFlexibleBottomMargin;
// put a button on the panel view so it can be tapped to slide down
UIButton *slidePanelButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
slidePanelButton.frame = CGRectMake(0,160,320,40);
[slidePanelButton addTarget:self action:#selector(slidePanel) forControlEvents:UIControlEventTouchUpInside];
[panelView addSubview:slidePanelButton];
// set panelView with a transform offset to slide it up under the top of the screen
panelView.transform = CGAffineTransformMakeTranslation(0, -160);
// add panelView to regular view controller's view
[self.view addSubview:panelView];
}
- (void)viewWillAppear {
// make sure the panel shows up on top, z-index wise, since subclasses might have created views that overlap it.
[self.view bringSubviewToFront:panelView];
}
- (void)slidePanel {
// remove the panel transform in an animated fashion (slide down).
// TODO: some button or action needs to slide the panel back up...
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3];
[panelView setTransform:CGAffineTransformMakeTranslation(0,0)];
[UIView commitAnimations];
}
- (void)viewDidUnload {
[super viewDidUnload];
// always make sure you clean up progammatically-retained views here
self.panelView = nil;
}
- (void)dealloc {
// and here too
self.panelView = nil;
[super dealloc];
}