在滚动视图上拖动视图:touchchesBegan已收到,但没有touchesEnded或touchesCancelled [英] Dragging views on a scroll view: touchesBegan is received, but no touchesEnded or touchesCancelled

查看:151
本文介绍了在滚动视图上拖动视图:touchchesBegan已收到,但没有touchesEnded或touchesCancelled的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

作为iOS编程新手,我正在努力使用中实现的可拖动字母拼贴。



我使用 touchesBegan,touchesMoved,touchesEnded,touchesCancelled 而不是手势识别器(正如Stac经常建议的那样) kOverflow用户),因为我在 touchesBegan 上显示带阴影的较大字母图块图像( bigImage )。



我的拖动按以下方式实现:


  1. touchesBegan 我从 contentView 中删除​​了磁贴(并将其添加到主应用视图中)并显示 bigImage 带阴影。

  2. touchesMoved 我移动磁贴

  3. touchesEnded touchesCancelled 我再次显示带有阴影的 smallImage - 添加图块到 contentView 或将其保留在主视图中(如果图块位于应用程序的底部)。

我的问题:



大多数情况下这都有效,但有时(通常)我看到只有 touchesBegan 被调用,但其他 touchesXXXX 方法永远不会被调用:

  2014-03-22 20:20:20.244 ScrollContent [807 5:60b]  -  [Tile touchesBegan:withEvent:]:Tile J 10 {367.15002,350.98877} {57.599998,57.599998} 

相反, scrollView 会被手指滚动,位于大牌区域下方。



这导致我的应用程序的屏幕上有许多带有阴影的大瓷砖,而滚动视图正在其下方拖动:





如何解决此问题?



<我肯定知道我的应用程序结构(自定义 UIView 被拖入/拖出 UIScrollView )是可能的 - 通过查看流行的文字游戏。



我使用 tile.exclusiveTouch = YES 和它显示了手势识别器的问题:瓷砖尺寸变化太晚 - 当用户开始移动瓷砖而不是在他触摸瓷砖时,它会发生:



解决方案

这里的问题是从视图层次结构中删除视图会使系统混乱,触摸会丢失。这是同一个问题(内部手势识别器使用相同的 touchesBegan: API)。



https://github.com/LeoNatan/ios-newbie/commit/4cb13ea405d9f959f4d438d08638e1703d6c0c1e
(我创建了拉取请求。)



我改变的是在触摸开始时不从内容视图中移除图块,而只是在触摸结束时移动或取消。但这会产生一个问题 - 当拖动到底部时,图块隐藏在视图下方(由于滚动视图剪切到其边界)。所以我创建了一个克隆的tile,将其添加为视图控制器视图的子视图,并将其与原始tile一起移动。当触摸结束时,我删除克隆的图块并将原始图块放在应该去的位置。



这是因为底部栏不是scrollview层次结构的一部分。如果是,则不需要整个瓷砖克隆。



我还简化了瓷砖的定位。


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:

  1. In touchesBegan I remove the tile from contentView (and add it to the main app view) and display bigImage with shadow.
  2. In touchesMoved I move the tile
  3. In touchesEnded or touchesCancelled I display smallImage with shadow again and - add the tile to the contentView 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 UIViews 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:

解决方案

The problem here is that removing a view from the view hierarchy confuses the system, the touch is lost. It is the same issue (internally gesture recognizers use the same touchesBegan: API).

https://github.com/LeoNatan/ios-newbie/commit/4cb13ea405d9f959f4d438d08638e1703d6c0c1e (I created a pull request.)

What I changed was to not remove the tile from the content view when touches begin, but only move on touches end or cancel. But this creates a problem - when dragging to the bottom, the tile is hidden below the view (due to scrollview clipping to its bounds). So I created a cloned tile, add it as a subview of the view controller's view and move that together with the original tile. When touches end, I remove the cloned tile and place the original where it should go.

This is because the bottom bar is not part of the scrollview hierarchy. If it was, the entire tile cloning would not be necessary.

I also streamlined the positioning of tiles quite a bit.

这篇关于在滚动视图上拖动视图:touchchesBegan已收到,但没有touchesEnded或touchesCancelled的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆