UITabBar / UIToolBar overlap problem (iphone sdk) - iphone

I have a custom button in another view directly above my UITabBar. It seems like there's a hidden "hit area" above the UITTabBar that is preventing me from hitting the bottom half of my custom button in another view. The button subview is on top of all other views including the custom UITabBar.
It's really easy to notice this effect in the simulator using the UICatalog sample code. Head to the toolbar section. Position your mouse cursor about 5-10 pixels above the tool bar items on the bottom and click to see that you can trigger the touch event way above the button.
I need to figure out how to restrict this hit area to the bounds of the uitoolbar or uitabbar itself and not let the iPhone do any sort of hit accessibility magic.
I think I've exhausted all options :\ I thought clipsToBounds (on the UITabBar) would do the trick, but apparently not.
Also I'm doing this completely in code, so no Interface Builder...

For anyone who stumbles across this question, I have a solution for this, although it falls well into "dirty hack" territory, and may break with newer (than 3.0) iPhone OS releases... use at your peril!
I created a UITabBar category with a hitTest:withEvent: implementation, and noticed when I set a breakpoint in the body of this method that the x,y values in the supplied CGPoint struct were rather odd - when touching in the ~15px or so ABOVE the tab bar the values look something like (x=23.482749, y=12.938475), whereas if you touch within the tab bar the values were nicely rounded to the nearest integer, e.g. (x=23, y=12).
Now, for some reason I was expecting the touches in the ~15px "hit zone" above the tab bar to be negative for the y axis (which is why I started down this path in the first place), but alas, no. You can touch in two different places and get similar coordinates, such as in the example above.
So, my "solution": I'm relying on a touch in the tab bar itself always having an integer-rounded value for the y axis, otherwise I'm assuming it's in the overlap zone above the tab bar. I tested this for quite a while, and it seems to consistently behave this way.
The code:
#implementation UITabBar (Me)
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if ([[NSString stringWithFormat:#"%.6f", point.y] hasSuffix:#".000000"])
{
return [super hitTest:point withEvent:event];
}
else
{
return nil;
}
}
#end

Related

Navigation bar title jumping right after flip transition

I have a simple UIViewController with a simple view. As a result of a user interaction, a new UINavigationViewController is instantiated and its view is being added as a subview to the view of the UIViewController. This takes place as part of an aninmation transition (flip).
This works quite well and the first view is flipped over in favor of the second view. But when the animation comes to an end (the UINavigationViewController's view fills the whole screen) the navigation bar items jump, i.e. the title jumps about 5-10 pixel from right to left, the buttons' jump depending on which side (left / right) they are positioned. During the animation you can see that the buttons are misplaced and that the jumping movement is kind of a repositioning.
Could anyone tell me the reason for this and give me some advice how to avoid this?
This is a little late, but there's no accepted answer and I've encountered this issue even fairly recently (albeit with an older app running on iOS 8).
If you encounter this issue and also see a warning along the lines of the following, it may be that you haven't properly set your root view controller in the app delegate:
Application windows are expected to have a root view controller at the
end of application launch
Modifying the app delegate as follows recently remedied the issue for me:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Other logic goes here
// ...
self.window.rootViewController = myRootViewController; // This was missing
[self.window makeKeyAndVisible];
return YES;
}
(I previously had some nearly-equivalent code that was setting up the view so everything displayed correctly on launch, but was not specifically setting the window's root view controller.)
I know it's annoying, but I have no idea why it happens, but in my experience, it happens in one of two cases:
Translucent navigationBar: maybe it had something to do with the fact that a translucent navigationBar sometimes sets a view's wantsFullScreen property (the view will then extend below the navigationBar).
During transitions: as you have described.
To avoid it, maybe a nice animation to fade it on an off screen before and after animation so as not to give the illusion of low quality.
OR
In viewWillAppear, assign the pixel value it's jumping to the navigationBar's origin.y. It's sad that it happens, but sometimes it just can't be fixed any other way.
This can be caused by partially-corrupt PNGs used for navigation bar buttons when the UIImages are resizableWithEdgeInsets:. If you're using custom button item images, try exporting them again using techniques known to produce reliable images (See blog posts by Marc Edwards at Bjango for a good start).
I recently had a problem that sounds identical to what you were experiencing. I found that using the [UIView performWithoutAnimation:^{}] block inside of transitionWithView fixed it.
During custom segue transition, view's navigation bar items are misplaced.

hide keyboard by dragging finger like sms app in iOS 5

I have a chat feature in my app and I am trying to hide the keyboard by dragging the finger downward just like how you can hide the keyboard in the sms app in IOS 5.
I have subclassed UITableView, however as soon as scrolling starts I no longer get calls to
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
I am wondering how I can get scrolling and find out where the finger is during scrolling so that if it starts to get close to the keyboard I can start to hide it.
I think this is a feature lots of people will want, any ideas on how to make it?
DAKeyboardControl it an MIT Licensed code source for what you are looking for.
Further googling revealed that this question is a duplicate of:
How to move iPhone keyboard down like in Messages.app?
I had enabled this feature in my app, with the help of Daniel's DAKeyboardControl library. You can implement the iMessage style keyboard hiding acidity with just one line of statement:
[self.view addKeyboardPanningWithActionHandler:^(CGRect keyboardFrameInView) {
// Move interface objects accordingly
// Animation block is handled for you
}];
UITableView inherits from UIScrollView, so you can detect the scroll position with UIScrollViewDelegate methods like - (void)scrollViewDidScroll:(UIScrollView *)scrollView
Luckly in iOS 7 Apple added the handy property keyboardDismissMode on UIScrollView. Now your app can behave like Messages just by changing a single property on your Storyboard, or by adding a single line of code.
This property uses the new ScrollViewKeyboardDismissMode enum. The possible values for the enum are as follows.
UIScrollViewKeyboardDismissModeNone
UIScrollViewKeyboardDismissModeOnDrag
UIScrollViewKeyboardDismissModeInteractive
Here is the storyboard property do dismiss the keyboard on scroll

Custom Scrollbar for iPhone's UIView (Making Long Scrolls Not Suck)

In a post, Making Long Scrolls on the iPhone Not Suck, Aza Raskin describes an alternative scrollbar control that's better at getting around on very long pages:
It's not important that the scrollbar "remains for some amount of time" to activate it; I'm fine with simply swiping along the right edge of the iPhone's screen to grab hold of the scrollbar handle. The idea is that if I drag the handle 3/4 of the way down on the physical screen, I'd be 3/4 of the way down on the page.
Tthe Dropbox iPhone app (it's great, btw!) has exactly this kind of scrollbar for long PDF documents. Regular scrolling is done by dragging anywhere but on the handle; dragging the handle moves the view to that location. This seems to have been implemented "from scratch", as I don't think the SDK is flexible enough to customize the behavior of the existing scrollbar.
However, Dropbox uses the native document viewers to show documents on the iPhone, so somehow they add the scrollbar functionality to it. See the scrollbar handle? You can drag that to quickly get somewhere else in the document.
This concept is very similar to how index bars work in UITableView (ie. Contacts.app); the index appears as a bar on the right hand side of the table (for example, "a" through "z"), and you can touch a particular label to jump to the target section. In this case, however, a very long page doesn't have sections, and it should work for general-purpose scrolling, not jumping to sections.
So how can I go about implementing this method of scrolling? I'm looking for general ideas and specific implementation details. I'm also interested if an open-source implementation exists (this seems like a general-purpose problem/solution).
A general idea:
I grabbed the dropbox app (it is awesome) and played around with a bit. It looks like pdf viewing takes a bit from the photo app in that it conditionally displays a translucent navbar and toolbar on touches, in addition to supporting the scrollbar. I'm pretty sure what's going on is that they have a custom view controller intercepting touches and reacting accordingly.
On a touch:
If it's a tap, show/hide the
navbar and toolbar.
If it's on
the scrubber, begin tracking the
touch and scrolling the
scrollview/webview (whatever they're
displaying with). I'm sure the
scrolling is something simple like
scrollView.contentOffset =
CGPointMake(0, (scrubber.y / [UIScreen mainScreen].bounds.size.height) *
scrollView.contentSize.height). 3)
Else, pass the touch on to the
enclosed view.
There may be other hidden magic with PDF displaying (I've never done it in cocoa touch) but something tells me this is their basic process.
I don't know of any iPhone specific solutions, but this is an old and well travelled topic in the world of Flash development... and you could probably extract a ton of pseudo code from that realm.
If you know the height of your window, and the height of your content, and the current offset of the content (which you do), then you have all the tools you need to create a custom UIView which can serve as a touch-responding slider. And then just paint it over the default scroller.
There's probably an open source implementation for this. I don't know any. Maybe shoot an email to Dropbox developers?
Anyway, the way I'd do this is:
#interface UICustomisedScrollView : UISCrollView
{
BOOL showingScroller;
UIView scroller; //Customise this, either in IB or in viewDidLoad
}
#implementation UICustomisedScrollView
- (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view {
showingScroller = !showingScroller;
if(showingScroller)
scroller.hidden = NO;
else
scroller.hidden = YES;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if(showingScroller) {
if(/*the touch is on the scroller*/) {
/* scrollview.setContentOffset(...) we want to scroll according to how much the user scrolls here */
}
//move scroller.frame.origin to where the touch is.
}
}
I'm guessing it won't be too difficult... But I haven't tested the above code yet. That's the general idea anyway =)
Try using a UIPanGestureRecognizer. In your action, can use the locationInView to determine the point the user is touching. Do this when the state is UIGestureRecognizerStateBegan and if it's close enough to the side of the view implement fast scrolling. Otherwise, implement slow scrolling.

iPhone - adjusting the size of a UIActionSheet

I need to present a UIActionSheet that will show 10 buttons. When I do that on iPad, the UIActionSheet shows on a popover that is very long vertically (not aesthetically pretty). Is that possible to specify the UIActionSheet size to a maximum size?
I have tried this
myActionSheet.frame = CGRectMake(0,0,300,300);
myActionSheet.bounds = CGRectMake(0,0,300,300);
and have also tried to put these lines inside
- (void)willPresentActionSheet:(UIActionSheet *)actionSheet {
without success.
any clues?
thanks
I think this is one of the cases where you can't really use a built-in class like the UIActionSheet to accomplish your goal. I don't think it is designed to be used for cases where you have as many buttons as 10. It just doesn't scale very well, just as you have discovered.
But let's pretend that it would be possible to change the size. What should happen when you change the size? There is a minimum size for each button for it to be tapable. And you also need some space between the buttons as to not cause a misstap. So even if you could change the size it couldn't be reduced by very much. And since it's not intended to be able to change the size you would have to try and access all the buttons and resize and move them as well. One could argue that perhaps the buttons could be placed in columns but since that is not implemented it would still not help if you made the UIActionSheet any wider.
I would recommend that you either:
Create your own custom view with all 10 buttons placed just as you liked.
Use a table view to present the options. Since the table view can be scrolled you can get the size you like.
If you set modalInPopover to YES on the UIViewController you present in the popover the user must make a choice before she can move on.
try with `- (void)showFromRect:(CGRect)rect inView:(UIView *)view animated:(BOOL)animated
because in apple documentation they said:
"On iPad, this method displays the action sheet in a popover whose arrow points to the specified rectangle of the view. The popover does not overlap the specified rectangle."
`

How to display a progress indicator overlay/HUD on iPhone?

I want to display a progress indicator in a semi-transparent box that floats over a table view. In other words, when the table contents are being downloaded, I want an "Updating" label to appear over it.
I have seen this in several apps in the store, notably Facebook (when you shake to reload) and Darkslide.
My first impulse is to create a semi-transparent UIView, place a UILabel and a UIProgressIndicatorView inside it, and add it to the view hierarchy... but where? A UIView may not overlap its siblings, so I can't make it a subview of the window. I also can't make it a subview of the table, because then it will scroll up and down with the table content.
I thought about creating a new UIWindow, but the documentation basically says don't.
I know CALayers can overlap each other, so that would be an option, but I can't put a progress indicator inside a CALayer, can I? Should I roll my own progress indicator that animates a CALayer instead of a UIView?
I'm not interested in hearing about private APIs.
Edit: The question was based on a faulty assumption. NSViews (on Mac OS X) may not overlap, but UIViews on the iPhone may.
I've just posted a HUD version of mine :
https://github.com/y0n3l/LGViewHUD
you can get this result very easily :
#import "LGViewHUD.h"
....
LGViewHUD* hud = [LGViewHUD defaultHUD];
hud.activityIndicatorOn=YES;
hud.topText=#"The longer....";
hud.bottomText=#"The better !";
[hud showInView:self.view];
Once the task is ended, just invoke
[[LGViewHUD defaultHUD] hideWithAnimation:HUDAnimationHideFadeOut];
and that's it !
You can definitely overlap views. Just add the transparent overlay as a subview in the tableView.
From UIView's documentation:
UIView objects are arranged within an UIWindow object, in a nested hierarchy of subviews. Parent objects in the view hierarchy are called superviews, and children are called subviews. A view object claims a rectangular region of its enclosing superview, is responsible for all drawing within that region, and is eligible to receive events occurring in it as well. Sibling views are able to overlap without any issues, allowing complex view placement.
Also there are the quite famous MBProgressHUD & SVProgressHUD
They are the same kind as #yonel 's HUD
Example
[SVProgressHUD show];
[SVProgressHUD dismiss];
MBProgressHUD seems now more popular (if we base on github stars)
Any object that lives in your MainWindow.xib can get access to the application window via an outlet. The application delegate in the standard projects already has it, but you'll probably want to add the outlet to your view controller that needs to show the progress overlay.
Since in UIKit the UIWindow is a UIView (unlike NSWindow vs. NSView in Cocoa), you can simply add your progress view as a subview of the window:
[window addSubview:progressView];
progressView will cover the entire application UI.
This example uses the technique to fade out the Default.png splash image:
http://michael.burford.net/2008/11/fading-defaultpng-when-iphone-app.html
With relation to the recent edit, as of MacOS X 10.5 Leopard NSView overlapping is deterministic (they always could overlap, you just got undetermined results), though it has a different front-to-back ordering depending on whether the containing view is layer backed or not. This is most likely a side effect of integrating CALayers into the OS X view system.
Answer: Apples docs are pretty awesome.
http://developer.apple.com/iphone/library/featuredarticles/ViewControllerPGforiPhoneOS/Introduction/Introduction.html
Currently I'm into over laying transparent views (at least on the back of a napkin at this point). You can use them to hold menu buttons, move them in 3D space, just get nuts.
I mean is this a religious tract of or what? Amazing stuff from the guys at NEXT:
UIView objects are arranged within an UIWindow object, in a nested hierarchy of subviews. Parent objects in the view hierarchy are called superviews, and children are called subviews. A view object claims a rectangular region of its enclosing superview, is responsible for all drawing within that region, and is eligible to receive events occurring in it as well. Sibling views are able to overlap without any issues, allowing complex view placement.