I have a UIview that is just a semi-transparent screen cover with the word "Loading" on it. and one of those spinning activity icons.
After loading, I need to remove the loading view from the UI, but for whatever reason, this is not happening. Here's the method in question.
- (void) readyForRoomDisplay
{
[_loadingIcon stopAnimating]; //_loadingIcon is the activity spinner
[self.view sendSubviewToBack:_loadingView]; // an attempt to hide
[_loadingView setHidden:YES]; // an attempt to hide
[_loadingView removeFromSuperview];// an attempt to hide
[self nextRoom:_roomImageButton];//should refresh the whole view
[self.view setNeedsLayout];
[self.view setNeedsDisplay];
}
The kicker is, after this happens, the contents of the VC's main view (while obscured) are clickable!!!
Some screenshots:
Normal Loading Image before AND after it should be destroyed
Somehow, I'm able to click THROUGH the loading screen!
This is the normal app main screen and appears when the button is clicked to swap calendars (refreshing the screen)
I feel like I've done everything that one can possibly do to get this out of here. It appears that the view is not updating after getting these commands. Is there anything else I can do?
looked here: Async UIView content not showing up when coming back to main thread
Apparently this update was not happening on the main thread, I just needed to push it back to the main thread an all was saved! Huzzah!
Related
I have a UIPagesViewController with 2 pages. One page is shown here:
The pages can be switched by gesture or by clicking a button in the toolbar.
Switching by button works always correctly using the method
-(void)switchViewControllers
{
if (self.pageIndex == 1) {
self.pageIndex = 0;
[self setViewControllers:#[self.gameControllers[0]] direction:UIPageViewControllerNavigationDirectionReverse animated:YES completion:nil];
} else {
self.pageIndex = 1;
[self setViewControllers:#[self.gameControllers[1]] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];
}
}
However switching by gesture works only most of the time correctly, but sometimes the resulting scene looks like one of the following images:
If the scene looks like the left image above, the half button visible does not work. But the page can still be switched by gesture, and everything works again.
The problem happens on the simulator and on the device.
I have no idea what could be wrong, nor how to avoid the problem. Any hint is highly welcome.
EDIT (due to Bartek's answer):
The problem occurs even if the pages are never switched programmatically.
UPDATE:
I realized now the following: If the page view is in the state shown in the left one of the 3 faulty scenes, and I drag it a few pixels right and let go, the vertical bar that can be seen on all 3 images right disappears, and the image is shown correctly and is shifted back to the correct position. If I then drag it a little left and let go, that vertical bar is shown again. So this obviously a UIPageViewController bug.
Here is the solution that worked for me:
Actually I had 2 separate problems.
1) The vertical stripes that you can see in the images above.
My view controllers that are presented by the UIPageViewController have an UIImageView subview that covers the whole view, used for a background image (the dotted background above). I used during development an image of size 2480x3507 with file name "Fond1.jpg". When I instead assign an image of size 640x1092 with file name "Fond1#2x.png", the stripes are gone.
2) The black images shown above.
This apparently happened when I did page switching very fast, i.e. so fast that the 1st switching animation was not yet finished when the 2nd one was initiated. I found here a solution that apparently works also for me (I did not have such problems since then).
Actually I think both problems are caused by bugs in iOS: When it is possible to use jpg images, they should be handled correctly. And the UIPageViewController should be able to handle the situation that one tries very fast page switching by itself.
UIPageViewController is buggy as hell, especially if you mix switching pages by gesture with switching from code.
What you might want to try is to force UIPageViewController to reload its cache when switching pages by code (not by gesture). So, for example:
-(void)switchViewControllers
{
// Resetting dataSource will cause UIPageViewControllerDataSource to rebuild its view controller stack cache
id<UIPageViewControllerDataSource> dataSource = self.dataSource;
self.dataSource = nil;
self.dataSource = dataSource;
if (self.pageIndex == 1) {
self.pageIndex = 0;
[self setViewControllers:#[self.gameControllers[0]] direction:UIPageViewControllerNavigationDirectionReverse animated:YES completion:nil];
} else {
self.pageIndex = 1;
[self setViewControllers:#[self.gameControllers[1]] direction:UIPageViewControllerNavigationDirectionForward animated:YES completion:nil];
}
}
This looks hideous, but does the trick.
To elaborate, UIPageViewController seems to have some sort of underlying cache for view controllers stack. This cache appears to go out of sync when we switch pages not by gesture but by code. I wouldn't be surprised if it were a bug, singe UIPageViewController is full of those.
So, forcing UIPageViewController to reload its cache when settings viewControllers helps. The best way to achieve that is to reset the dataSource, as in the example above.
I hope this helps.
And that you don't rely on UIPageViewController too much :)
Sorry if my question seems stupid but I've been trying everything to get it to work for several days now and nothing comes to my mind anymore.
I'm trying to use SVPullToRefresh on a UIScrollView which is, in my storyboard, fixed to the main view of my View Controller (space constraints to superview 0,0,0,0).
Code is pretty straightforward :
__weak ALExploreViewController *weakSelf = self;
[self.globalScrollView addPullToRefreshWithActionHandler:^{
[weakSelf refreshData];
}];
[self.globalScrollView triggerPullToRefresh];
The thing is, when I launch the app, the pull to refresh appears as I triggered it in code. Then I make it disappear when my data are updated (self.globalScrollView.showsPullToRefresh = NO;). And then when I scroll up to refresh, the "pull to refresh" view won't show. If I deactivate bouncing, the view won't event scroll upper than y=0, and if I activate it, it bounces but no sign of the P2R view.
Any ideas ? Please ?
You should not use self.globalScrollView.showsPullToRefresh = NO;, this is used to disable the refreshView.
When your data is updated, you can call
- (void)stopAnimating;
Try it!
When I slowly pull down to refresh, I see the UIActivityIndicator circle slowly get more complete before it starts the refresh. Just before the circle is complete and the refresh actually triggers, the content jumps/jerks down and then the circle starts spinning. I only notice this when I pull down slowly.
I'm using the pull to refresh inside a scroll view called mainSV
self.refresh = [[UIRefreshControl alloc] init];
[self.refresh addTarget:self action:#selector(handleRefresh) forControlEvents:UIControlEventValueChanged];
[self.mainSV addSubview:self.refresh];
Why does this jump/jerk happen?
It's probably a bug in iOS. Your setup is correct, and I see the same thing in my app.
I suspect the jump/jerk is due to a "double" action.
There was a change to refresh implementation following the release of Xcode 5.
As such, the requirement to set a target action as described in the Apple Documentation is no longer necessary.
As you are using a Storyboard, in your Interface Builder / Storyboard file, select your storyboard scene (table view controller).
In the attributes inspector, under the subheading Table View Controller, select the item "Refreshing" and change the setting from "Disabled" to "Enabled".
Delete or comment out the three lines of code you have included in your question. (When it was required, i.e. prior to Xcode 5, I placed this code in my viewDidLoad TVC lifecycle method.)
If not automatically inserted into your code, then add this as either a public or private IBAction...
- (IBAction)refresh:(UIRefreshControl *)sender;
and wire to your scene / table view controller to the Sent Event "Value Changed".
Ensure your refresh action is properly configured...
- (IBAction)refresh:(UIRefreshControl *)sender {
[self.refreshControl beginRefreshing];
// Refresh code for your TVC
[self.refreshControl endRefreshing];
}
Note that no property is required to be set for refreshControl - I suspect there is a trigger to automatically synthesise this when you choose the setting Refreshing [Enabled] in your TVC attributes in the storyboard.
If you need to call the refresh from in your code, use this line...
[self refresh:self.refreshControl];
I would need to see the rest of your code (or at least the scrolling + refreshing methods) to diagnose the problem.
Here's our tutorial for implementing custom pull to refresh controls in objective-c and swift. If you follow this tutorial you shouldn't see any jumping or jerking.
http://www.jackrabbitmobile.com/design/ios-custom-pull-to-refresh-control/
Hope it helps!
Old questions but if someone still has this issue and you are using NavigationController just make your NavigationBar "Translucent".
Using non translucent NavigationBar causes the tableview to jump slightly when UIControlEventValueChanged is fired for some reason.
XCode 10.1
In my app I have two methods to hide and show a subview of a view controller called
-(void)hideCurrentView
-(void)showCurrentView
They are always called together. When calling hideCurrentView I want to start showing a loading screen and then hide this loading screen when showCurrentView has shown all necessary ui elements. My loading screen is a view with an activity indicator as a subview. The problem is that I have to do all the actions that happen in hideCurrentView and showCurrentView on the main thread. That is why my loading screen will never show up. :-(
I tried to put the show loading screen method to a background thread:
-(void)hideCurrentView {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, (unsigned long)NULL), ^(void) {
[self showLoadingScreen];
});
[self performSelectorOnMainThread:#selector(hideCurrentViewOnMainThread) withObject:nil waitUntilDone:YES];
}
-(void)showCurrentView {
[self performSelectorOnMainThread:#selector(showCurrentViewOnMainThread) withObject:nil waitUntilDone:YES];
}
That does not work. The loading screen never shows up because the main thread is blocked. I also tried showing the loading screen directly on the main thread but it doesn´t work too.
Can anyone tell me hoew to show the loading screen before doing the ui actions and then hide it again when all ui actions have finished?
Thanks for your help!
You should not call showLoadingScreen in a background thread if you are just adding a subview. (or more generally manipulating the UI)
I'm guessing you have something in your hideCurrentViewOnMainThread that is not UI related and blocks the main thread and it's that part of the code that should be run in another thread.
Ok, so I have this piece of code:
- (void) searchBarSearchButtonClicked:(UISearchBar *)aSearchBar
{
[_activity startAnimating];
[self.searchBar bringSubviewToFront:_activity];
[self.searchBar resignFirstResponder];
if([_activity isAnimating]){
NSLog(#"its animating!");
}
dispatch_queue_t background = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
dispatch_async(background, ^{
[self performSelectorOnMainThread:#selector(filter:) withObject:aSearchBar.text waitUntilDone:YES];
dispatch_async(dispatch_get_main_queue(), ^{
[_activity stopAnimating];
if(![_activity isAnimating]){
NSLog(#"its not animating anymore!");
}
[self.tableView reloadData];
});
});
}
what i'm trying to do is start an activity indicator which I added as a subview to the search bar. In this code, I start the animation (logging for test) on the main thread, then set up a background asynchronous thread which runs the method that generates the new data set which will reload the tableview. I wait for this to return, and which point, I stop animation and reload the tableview on the main thread.
the result is this...when the application runs, I go to the table view, and I type a word in the search bar. When I hit enter, the activity indicator shows up, the table loads, and the activity indicator stops. This is great.
Then, I click on the search bar again, start a new search, only this time, the activity indicator does not show itself, but the NSLog shows that it IS animating. The tableview reloads as expected, but no activity indicator on the UI, but based on the NSLog, it seems to working.
Finally, if I wait about a minute, and search again, it works fine. What I'm suspecting is that that the background thread is not completing maybe, and the main thread continues doing what it needs to do.
Honestly, I've been beating my head for two days now, can someone explain what I'm doing wrong?
There's a chance that this has something to do with the view hierarchy, depending on where you added the UIActivityIndicatorView to. If you added it directly to the search bar, it might reorganize the subviews in a way you don't expect (and move the activity indicator behind some of them, blocking it from being visible, even though it's animating.)
A good option might be to embed the search bar within a toolbar, and then have the activity indicator on the left (or right) with flexible space separating it from the search bar.