I would like to know how to implement an animation where the user can slide one view over another using his finger. To simplify things I will post some pictures to explain what I mean.
At first we have a view which has a settings icon (that pink thingie in the upper left corner). The view can can be manipulated by any means necessary - including swiping. See picture 1.
When the user presses the settings button the view slides away and reveals settings view underneath. To do this I just use [UIView beginAnimations:nil context:nil] adjust the main view frame and commit animations. The situation looks like this: (settings are purple, main view is still the same colour)
Now when the user decides he want the main screen back he will have to grab it and slide it back into its place. HOW? Now I have been using UITapGestureRecognizer which would trigger a reverse animation so that the view slid back in its original place. That was messy and the user was still able to manipulate that small section of the view visible.
I want the view to follow the user's finger and slide and scale its way back in its place. The main view should not be manipulatable while moving. To understand what I mean you can check the Yahoo Weather app which has a similar thing going on - except that my view would also shrink a bit vertically. The third picture shows things "in motion":
Please provide links or code that can help me accomplish this.
Cheers, Jan.
Look at this code:
MMDrawerController
MSMatrixController
And you can try this
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[touches allObjects] objectAtIndex:0];
CGPoint touchPt = [touch locationInView:self];
float deltaX = touchPt.x - beginPt.x; //where beginPt is CGPoint variable which was set in touches began
float deltaY = touchPt.y - beginPt.y;
if (deltaX < 0) {
deltaX = -deltaX;
}
if (deltaY < 0) {
deltaY = -deltaY;
}
CGPoint toPt;
toPt.x = deltaX;
toPt.y = deltaY;
yourMovedView.center = toPt;
}
Related
I'm writing a radial menu, where when you long press (UILongPressGestureRecognizer) on the screen, it pops out a menu of buttons, and I can drag my finger (which is already touching the screen) over one of the buttons, which selects, then when I let go, it performs an action specific to that button.
I currently have the radial menu as a UIControl subclass, and I'm trying to override beginTrackingWithTouch: and continueTrackingWithTouch:, but the long press that shows the menu (adds it to the superview), does not get transferred to a touch recognized by the UIControl.
Any ideas how I can "forward" this touch event from the UIControl's superview to it?
Thanks!
Not a direct answer, but you should really watch the WWDC session about scrollviews of this year. And then watch it again. It contains a fantastic amount of information, and most certainly an answer to your question. It is session 235: advanced scrollviews and touch handling techniques.
I would do this...
The long press handler:
-(IBAction)onLongPress:(UILongPressGestureRecognizer*)recognizer
{
CGPoint point = [recognizer locationInView:self.view];
if (recognizer.state == UIGestureRecognizerStateBegan) {
//create the radial view and add it to the view
CGSize radialViewSize = CGSizeMake(80, 80);
radialView = [[RadialView alloc] initWithFrame:CGRectMake(point.x - radialViewSize.width/2, point.y - radialViewSize.height/2, radialViewSize.width, radialViewSize.height)];
[self.view addSubview:radialView];
radialView.backgroundColor = [UIColor redColor];
} else if (recognizer.state == UIGestureRecognizerStateEnded) {
[radialView onTouchUp:[radialView convertPoint:point fromView:self.view]];
[radialView removeFromSuperview];
radialView = nil;
}
}
In your radial view: (I suppose that the radial view keeps the buttons in an array)
-(void)onTouchUp:(CGPoint)point
{
for (UIButton *button in buttons) {
if ([button pointInside:[self convertPoint:point toView:button] withEvent:nil]) {
//This button got clicked
//send button clicked event
[button sendActionsForControlEvents:UIControlEventTouchUpInside];
}
}
}
I know it's not perfect, since the touch events don't get forwarded to the radial view (as you asked), but it let's you click the buttons. Hope it helps!
I'm not sure if this is the same behavior you're looking for, but I recently had to overcome the exact same issue when developing my Concentric Radial Menu. The thing I discovered very quickly was that views added to the view hierarchy during the touch event do not get re-hit-tested and therefore seem unresponsive until the next event comes around.
The solution I used, which I can't say I love, was to implement a custom UIWindow subclass that intercepts - (void)sendEvent:(UIEvent *)event and forwards those events to the "active" radial menu.
That is, the menu registers with the window upon activation, then unregisters when being unloaded. If done atomically, this is actually a pretty safe technique, I just wish it were cleaner than it is.
Best of luck!
So I'm making a minesweeper clone for iOS, and I have an array of UIButtons containing 135 buttons (the minesweeper board). It looks great and theoretically should work great. But I was having trouble detecting which button was being hit. I tried working around the problem by using this code;
UITouch *touched = [[event allTouches] anyObject];
CGPoint location = [touched locationInView:touched.view];
NSLog(#"x=%.2f y=%.2f", location.x, location.y);
int pointX = location.x;
int pointY = location.y;
My goal was to grab the coordinates of the touch and then use some basic math to figure out which button was being pressed. However, it doesn't work. At all. No button is pressed, no function runs, essentially nothing happens. I'm left with a minesweeper board that you can't interact with. Any ideas?
Assign a separate number to the tag of each button. Use the button's target, not the UITouch code. When you get a buttonPress, query the tag.
You could subclass the buttons and then program the what needs to happen when a touch occurs in a button inside of that subclass.
The UIButton * can be accessed by calling:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
on self (a UIView * I imagine). So I suppose you can set the button to the pushed state, and when touchesEnded: is called, set it back.
How would I create a program so a dot starts in the center, and when I click the screen the dot follows where I clicked? Not as in teleports to it, I mean like changes it's coordinates towards it slightly every click. I get how I could do it in theory, as in like
if (mouseIsClicked) {
[mouseX moveX];
[mouseY moveY];
}
And make the class that mouseX and mouseY are have some methods to move closer to where the mouse is, but I just don't know any specifics to actually make it happen. Heck, I don't even know how to generate a dot in the first place! None of those guides are helping at all. I really want to learn this language though. I've been sitting at my mac messing around trying to get anything to work, but nothing's working anywhere near how I want it to.
Thanks for helping a total newbie like me.
If you are going to subclass UIView, you can use the touchesBegan/touchesMoved/touchesEnded methods to accomplish this. Something like:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint p = [touch locationInView:self];
//slightly update location of your object with p.x and p.y cgpoints
[self setNeedsDisplay];
}
-(void)drawRect{
//draw your object with updated coordinates
}
You can create a dot and move it around based on taps all within your UIViewController subclass.
Make your dot by creating a UIView configured to draw the way you want - look into CALayer and setting dotview.layer.cornerRadius to make it be round (alternately you can make a UIView subclass that overrides drawRect: to make the right CoreGraphics calls to draw what you want). Set dotview.center to position it.
Create a UITapGestureRecognizer with an action method in your view controller that updates dotview.center as desired. If you want it animated, simply set the property within a view animation call & animation block like this:
[UIView animateWithDuration:0.3 animations:^{
dotview.center = newposition;
}];
You can download the sample code here that will show you general iOS gestures. In particular it has a sample that shows how to drag and drop UIViews or how to swipe them around. The sample code includes both driven and fire-n-forget animations. Check it out, its commented and I'd be happy to answer any specific questions you have after reviewing the code.
Generating a simple circle
// Above Implementation
#import <QuartzCore/QuartzCore.h>
// In viewDidLoad or somewhere
UIView *circleView = [[UIView alloc] initWithFrame:CGRectMake(32.0, 32.0, 64.0, 64.0)];
[circleView setBackgroundColor:[UIColor redColor]];
[circleView.layer setCornerRadius:32.0];
self.view addSubview:circleView];
I'm using Xcode to develop an app for iOS where the user can rate some content by touching the corresponding smiley icon (from frown to big smile). At the moment, each smiley icon behaves as a single button: when one of the smileys is touched, its color changes to show the user his/her choice.
However, being the icons small in the iPhone display, it is not easy to touch with precision the desidered smiley, and the user is likely to make errors.
I would like improve my rating system to mimic the behavior of the IOS keyboard for iPhone when it shows on top of the finger the selected character, and inputs the character just when the user releases the finger.
More precisely, I would like my 5 smiley items to behave not as separated buttons, but as a slider with 5 discrete points: when the user's finger is held on an item (covering it), a zoomed version on top appears, the user can continue sliding and when he/she releases the finger the selected item is chosen. I created a small animation to show what I would like to achieve:
Which method or class would you recommend to use to achieve this effect?
You don't need to go for popover controller. Here is what you can do.
Implement this method in your ViewController:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint point = [[[event allTouches] anyObject] locationInView:self.view];
for (UIImageView *sView in self.smileyImages)
//smileyImages is outletCollection of smileyImageViews.
{
if (CGRectContainsPoint([sView frame], point))
{
[self.popupView setHidden:NO];
//popupView is the popup view you want to show.
[self.popupImage setImage:[sView image]];
//popupImage is enlarged image of smiley in popup view you want to show.
CGPoint newCenter= CGPointMake(sView.center.x, sView.center.y-40);
//This fixes position of your popupView.
[self.popupView setCenter:newCenter];
}
}
}
Here is the Github of the code. I've just implemented popup for you. Rest you can do I think. If not, Let me know.
Update:
Add this method for desired results
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
CGPoint point = [[[event allTouches] anyObject] locationInView:self.view];
for (UIImageView *sView in self.smileyImages)
{
if (CGRectContainsPoint([sView frame], point))
{
self.selectedImage= sView.image;
[self.popupView setHidden:YES];
break;
}
}
}
Update2:
Previous update has some issues, go for this code instead:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
self.selectedImage= self.popupImage.image;
[self.popupView setHidden:YES];
}
I am an iOS programming newbie (reading several books on the subject simultaneously) and I would like to develop a (yet another) word game.
Coming from Flash/Flex programming background I was first expecting the tiles to be best bundled as gif or png assets.
But then I have taken a look (by using iFunbox) at the popular word games (Lexulous, Wordament, Words with Friends, Ruzzle, ...) and none of them is doing that:
That is none of the many apps I've looked at includes any letter pieces as images.
So my question is what would be the recommended approach (in Xcode 5 and with no additional SDKs like Cocos2d or Sparrow) to create a letter tile for a word game?
On a tile I'd like to have
the center-aligned letter (obviously!),
then an index in a corner displaying the letter value
and then another index for a total word value
When touched I'd like to make the tile a bit larger and add a shadow underneath it.
Should my tile class be a UIView (can they be dragged around, grow and have shadows?)
Should I use a .nib file for the tile?
For dragging I have found a good suggestions already: Dragging an UIView inside UIScrollView
But what I really would like to know here is: if UIView would make a good tile (performance- and feature-wise) or should I go for another base class (like maybe some shapes)?
Yes UIView would be a good container.
Create a subclass of UIView, say TileView, put in some labels, image view and a button over it, override buttons UIControlEventTouchDown, UIControlEventTouchUpInside, UIControlEventTouchDragInside events to help U navigate the view in its parent. Put the TileView in some container (your view controller view or where U would like it to be) and this is basically it.
-(void)btnPressed:(id)sender withEvent:(UIEvent *) event
{
CGPoint point = [[[event allTouches] anyObject] locationInView:self.view];
dx = 0;
dy = 0;
oldPoint = point;
}
-(void)btnRelesed:(id)sender
{
// stop moving code
}
-(void)btnDragged:(id)sender withEvent:(UIEvent *)event
{
CGPoint point = [[[event allTouches] anyObject] locationInView:self.view];
dx = point.x - oldPoint.x;
dy = point.y - oldPoint.y;
oldPoint = point;
// set tile view center position using
CGPoint ptCenter;
ptCenter = self.view.center;
ptCenter.x = ptCenter.x + dx;
ptCenter.y = ptCenter.y + dy;
self.view.center = ptCenter;
}
self.view is your TileView and its self.view cause U have ovrriden UIView class ;)