As an iOS programming newbie I am struggling with a word game for iPhone.
The app structure is: scrollView -> contentView -> imageView -> image 1000 x 1000
(here fullscreen):
I think I have finally understood how to use an UIScrollView
with Auto Layout enabled in Xcode 5.1:
I just specify enough constraints (dimensions 1000 x 1000 and also 0 to the parent) for the contentView
and this defines the _scrollView.contentSize
(I don't have to set it explicitly) - after that my game board scrolls and zooms just fine.
However I have troubles with my draggable letter tiles implemented in Tile.m.
I use touchesBegan, touchesMoved, touchesEnded, touchesCancelled
and not gesture recognizers (as often suggested by StackOverflow users), because I display larger letter tile image with shadow (the bigImage
) on touchesBegan
.
My dragging is implemented in the following way:
- In
touchesBegan
I remove the tile fromcontentView
(and add it to the main app view) and displaybigImage
with shadow. - In
touchesMoved
I move the tile - In
touchesEnded
ortouchesCancelled
I displaysmallImage
with shadow again and - add the tile to thecontentView
or leave it in the main view (if the tile is at the bottom of the app).
My problem:
Mostly this works, but sometimes (often) I see that only touchesBegan
was called, but the other touchesXXXX
methods are never called:
2014-03-22 20:20:20.244 ScrollContent[8075:60b] -[Tile touchesBegan:withEvent:]: Tile J 10 {367.15002, 350.98877} {57.599998, 57.599998}
Instead the scrollView
is scrolled by the finger, underneath the big tile.
This results in many big tiles with shadows sitting on the screen of my app, while the scroll view is being dragged underneath them:
How to fix this please?
I know for sure that my structure of the app (with custom UIView
s dragged in/out of a UIScrollView
) is possible - by looking at popular word games.
I use tile.exclusiveTouch = YES
and a custom hitTest method for the contentView - but this doesn't help:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView* result = [super hitTest:point withEvent:event];
return result == self ? nil : result;
}
UPDATE 1:
I've tried adding the following code to handleTileTouched
:
_contentView.userInteractionEnabled = NO;
_scrollView.userInteractionEnabled = NO;
_scrollView.scrollEnabled = NO;
and then set it back to YES
in handleTileReleased
of ViewController.m - but this does not help and also looks more like a hack to me.
UPDATE 2:
Having read probably everything related to UIScrollView
, hitTest:withEvent:
and pointInside:withEvent:
- on the web (for ex. Hacking the responder chain and Matt Neuburg's Programming iOS book), StackOverflow and Safari, it seems to me, that a solution would be to implement the hitTest:withEvent:
method for the main view of my app:
If a Tile
object is hit, it should be returned. Otherwise - the scrollView
should be returned.
Unfortunately, this doesn't work - I am probably missing something minor.
And I am sure that a good solution exists - by studying popular word games for iOS. For example dragging and placement of letter tiles works very smooth in Zynga's Words with Friends ® app and in the screenshots below you can see them probably using UIScrollView
(the scroll bars are visible in the corner) and displaying a tile shadow (probably in touchesBegan
method):
UPDATE 3:
I've created a new project to test gesture recognizer suggested by TomSwift and it shows the problem I have with gesture recognizers: the tile size changes too late - it happens, when the user starts moving the tile and not at the moment he touches it:
:-)
I had the same phase with my (mobile and desktop) card game and now (since 4y) it just works: facebook.com/appcenter/video-preferans I just have to pass a critical mass of stupid questions and I then am good. Please have some patience with my iOS newbiness. – Procurator