linking UIProgressView with IBAction - ios

Perhaps I'm missing something here, but I want the user to be able to select a UIProgressView and thus have an IBAction function call (essentially make it behave like a UIButton).
This can't be rocket science, but I can't figure it out.
BTW, I have xCode 4.

Add a gesture recognizer. With UITapGestureRecognizer you can make any UIView (or subclass) instance respond to taps. You'll have to do it in code instead of in IB, which means you'll need an IBOutlet connection to the progress view. You might need to set userInteractionEnabled to YES to make it work.
It's kind of hard to imagine a scenario where this makes sense, but I'll just assume you have a good reason and leave it at that.

Related

How to respond to a very quick touch?

I found that touchDown event is kind of slow, in that it requires a major, fairly long touch and does not respond to a light tap. Why is that?
Whereas, touchesBegan responds just when I need it to, i.e. responds even to very light, quick touches. But that's not an event but a method that can be overridden.
Problem is, touchesBegan apparently requires me to either 1) subclass a label (I need to respond to touching a label), or 2) analyze the event to figure out whether it came from the right label. I am wondering whether it's a code smell and whether there should be an event for simple touch.
Try to add a UITapGestureRecognizer to your label.
First of all, allow label to handle user interaction:
label.userInteractionEnabled = true
You can assign tap gesture to label. Then in handler method you need to switch over state property of recognizer. If it is .Began, you got the event that you need.
The cool thing about this approach that you could use this one handler for all of your labels. Inside handler, you can get touched label like this:
let label = tapRecognizer.view as! UILabel
"Code smell"? No, it's a user interface smell. A user interface stink.
If you make a button in your user interface behave different from buttons in any other application, people will hate your app. Do what people are used to.

Gestures that steal touches like iOS multitasking swipe

I know what I want to do, but I'm stumped as to how to do it: I want to implement something like the iOS multitasking gestures. That is, I want to "steal" touches from any view inside my view hierarchy if the number of touches is greater than, say, two. Of course, the gestures are not meant to control multitasking, it's just the transparent touch-stealing I'm after.
Since this is a fairly complex app (which makes extensive use of viewController containment), I want this to be transparent to the views that it happens to (i. e. I want to be able to display arbitrary views and hierarchies, including UIScrollViews, MKMapViews, UIWebViews etc. without having to change their implementation to play nice with my gestures).
Just adding a gestureRecognizer to the common superview doesn't work, as subviews that are interaction enabled eat all the touches that fall on them.
Adding a visually transparent UI-enabled view as a sibling (but in front) of the main view hierarchy also doesn't work, since now this view eats all the touches. I've experimented with reimplementing touchesBegan: etc. in the touchView, but forwarding the touches to nextResponder doesn't work, because that'll be the common superview, in effect funnelling the touches right around the views that are supposed to be receiving them when the touchView gives them up.
I am sure I'm not the only one looking for a solution for this, and I'm sure there are smarter people than me that have this already figured out. I even suspect it might not actually be very hard, and just maybe my brain won't see the forest for the trees today. I'm thankful for any helpful answers anyway :)
I would suggest you to try using method swizzling, reimplementing the touchesbegan on UIView. I think that the best way is to store in a static shared variable the number of touches (so that each view can increment/decrement this value). It's just a very simple idea, take it with a grain of salt.
Hope this helps.
Ciao! :)
A possible, but potentially dangerous (if you aren't careful) approach is to subclass your application UIWindow and redefine the sendEvent: method.
As this method is called for each touch event received by the app, you can inspect it and then decide to call [super sendEvent:] (if the touch is not filtered), or don't call it (if the touch is filtered) or just defer its call if you are still recognizing the touch.
Another possibility is to play with the hitTest:withEvent: method but this would require your stealing view to be placed properly in the subview, and I think it doesn't fit well when you have many view controllers. I believe the previous solution is more general purpose.
Actually, adding a gesture recognizer on the common superview is the right way to do this. But it sound like you may need to set either delaysTouchesBegan or cancelsTouchesInView (or both) to ensure that the gesture recognizer handles everything before letting it through to the child views.

Using a UIView as a button

I'm trying to use a UIView I've created in Storyboard as a button. I assumed it would be possible to use a UIButton, setting the type to custom. However I was unable to add subviews to a custom UIButton in Storyboard.
As such I've just spent the last hour reinventing the wheel by making my own custom gesture recoginizers to reimplement button functionality.
Surely this isn't the best way of doing it though, so my question - to more experienced iOS developers than myself - is what is the best way to make a custom button?
To be clear it needs to:
Use the UIView I've created as it's hittable area.
Be able to show a
different state depending on whether is currently highlighted or not
(i.e. touch down).
Perform some action when actually tapped.
Thank you for your help.
You can use a UIButton, set the type to custom, and then programmatically add your subviews...
Change your UIView into a UIControl in the storyboard. Then use the method [controlViewName addTarget:self action:#selector(*click handler method*) forControlEvents:UIControlEventTouchDown];. click handler method is a placeholder for the method name of your handler. Use this method except change out the UIControlEventTouchDown for UIControlEventTouchInside and UIControlEventTouchDragExit to call a method when the user finishes their click and drags their finger out of the view respectively. I used this for something I'm working on now and it works great.
In Touch down you will want to: highlight all subviews
In Touch up inside you will want to: unhighlight all subviews and perform segue or do whatever the button is supposed to do
In Touch Drag Exit you will want to: unhighlight all subviews
See second answer by LiCheng in this similiar SO post.
Subclass UIControl instead. You can add subviews to it and it can respond to actions
Why are you implementing your own GestureRecognizer? I recommend using the UIView so you can add subviews in the interface builder and adding a UITapGestureRecognizer. You can even do this graphically since you don't care about IOS4 support.

UIView with UIButtons not showing up prior to click or rotate

I've been banging my head with this issue for the last two days. Googled a lot but wasn't able to find the answer yet, so I decided to request some help here. Let's see if I get any luck.
I'm coding a reusable control that consists of an UIView with a variable number of customized UIButtons. I implemented initWithFrame:, initWithCoder: and drawRect: where the buttons (which are built prior to drawing) are actually added to the view. Everything is done programmatically since the UIButton content should be supplied when using the control, so there's no XIB for this UIView.
This UIView, let's call it CustomizableBarButton is then used in an UIViewController, let's call it MyTestViewController with a view on it, let's call it customizableBarButtonView.
MyTestViewController's GUI was set on IB where an UIView was tied to customizableBarButtonView (the class was matching accordingly).
MyTestViewController's is a pretty standard class except for the viewWillAppear: that initializes the buttons and passes them to the CustomizableBarButton along with some other options.
The issue is that everything works perfectly...except for the first time!
I mean, when I run the app on the simulator (I haven't tried it on the iPhone yet but I strongly believe that it's not an hardware issue) the MyTestViewController shows the customizableBarButtonView background but not the buttons. Now when you click on the place where a button should be all the buttons suddenly appear!
I'm puzzled since the CustomizablebarButton drawRect: runs before the strange "click n'appear" effect and the buttons are actually added to the subview.
Another hint that my help: if you don't click on the buttons (so you still got no buttons yet) but rotate the device they will also appear as if by magic!
It is probably something very simple but I'm missing it and I'm going nuts...
Can someone lend a hand on this, please?
Thanks in advance!
You said you're adding the buttons in drawRect:. Don't do that. You need to add the buttons in your init methods.

How can I create a dynamic overlay for a UIButton?

My application has a few portions that have really big buttons (640x130, 230x150, etc.) What I need is to have a way to update different portions of the button, with different text. Initially, I assumed that in my code I could create various UILabels and then add them as subviews to my button. However, as soon as I try to add a UILabel to the button as a sub-view, my app crashes.
What is the easiest way to create an overlay for a button, that I can completely layout myself, without preventing button taps from being interested using overlay controls?
I imagine there are multiple ways to solve this problem. However, the best solution for my case should use the fewest lines of code (I have quite a few of these types of buttons) and I'd like to be able to continue using some form of configurable button within IB.
I'm not opposed to subclassing UIButton but, if I do, I would like to be able to use it in IB. I've never created a custom UIView for such a circumstance, so I'd need help defining that type of subclass so that it will work correctly in IB.
You need to add the subview to the containing view - not the button. To ensure that is doesn't interfere with button presses, be sure to set it to:
[myCustomTextOverlay setUserInteractionEnabled:NO];

Resources