美文网首页人猿星球
UITableView或UIScrollVIew上的UIButt

UITableView或UIScrollVIew上的UIButt

作者: Marc丶 | 来源:发表于2016-07-21 20:37 被阅读968次

    最近做项目的时候发现,UIScrollView上的UIButton点击的时候没有高亮状态,但是确实触发了点击事件,不过这样会造成一个假象,给用户看来UIButton没有被点击的感觉。 但是要是长时间点击的话,则会高亮。于是我发现,导致这种现象应该就是时间长短的问题。顺着这个问题想下去,就追寻到UIScrollView的touch原理,UIScrollView有一个delaysContentTouches的属性。

    苹果官方的文档解释:default is YES. if NO, we immediately call -touchesShouldBegin:withEvent:inContentView:. this has no effect on presses

    很明显,delaysContentTouches 默认值为YES,即UIScrollView会在接受到手势是延迟150ms来判断该手势是否能触发UIScrollView的滑动事件;反之值为NO时,UIScrollView会立马将接受到的手势分发到子视图上。

    当然,delaysContentTouches设置为NO是远远不够的,因为这样的话你想要拖动UIScrollView而七点落在替他有手势识别的视图上是会拖不动的。 于是我们要重载touchesShouldCancelInContentView,此方法决定手势是否取消传递到View上,拖动UIScrollView是触发。返回NO时,拖动手势将留在UIScrollView上;返回YES时,则传到View上。

    现在,方案就很明确了,我们只要将UIButton所有属于UIScrollView的父视图的delaysContentTouches属性设置成为NO且重写touchesShouldCancelInContentView方法就行。下面直接贴代码

    - (instancetype)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];
    if (self) {
        self.delaysContentTouches = NO;
    }
    return self;
    }
    
    - (instancetype)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        self.delaysContentTouches = NO;
    }
    return self;
    }
    
    - (BOOL)touchesShouldCancelInContentView:(UIView *)view {
    if ([view isKindOfClass:[UIButton class]]) {
        return YES;
    }
    return [super touchesShouldCancelInContentView:view];
    }
    

    这就是UIScrollView的让UIButton高亮方法,然而UITableview相比更加复杂些
    UITableView:

    在iOS7和iOS8中的视图结构是不同的,且存在着很多我们在编码时永远接触不到的视图,但我们可通过Debug将其subviews逐个逐个找出来。这关系到我们这个问题坑比较深的层次。

    iOS7:UITableView中存在n+1个UIScrollView,一个是UITableView本身,另外n个村在于UITableViewCell月cell的contenView之间,类名为UITableVieCellScrollVIew,在iOS8已经移除。

    iOS8:UITableView中存在2个UIScrollView,一个是UITableView本身,另外一个存在于UITableView与UITableViewCell之间,类名为UITableViewWrapperView。需要注意的是,UITableViewWrapperView在iOS7中并不是一个UIScrollView。

    理解后直接贴代码

    @implementation ResponseTableView
    
    - (instancetype) initWithCoder : (NSCoder *) aDecoder
    
    {
    self = [super initWithCoder:aDecoder];
    if (self) {
        self.delaysContentTouches = NO;
        //因为 UITableViewWrapperView 在iOS7不属于UIScrollView
        //iOS7
        for (id obj in self.subviews) {
            if ([NSStringFromClass([obj class]) isEqualToString:@"UITableViewCellScrollView"]) {
                UIScrollView *scrollView = (UIScrollView *) obj;
                scrollView.delaysContentTouches = NO;
                break;
            }
        }
        //ios 8
        for (id view in self.subviews) {
            if ([NSStringFromClass([view class]) isEqualToString:@"UITableViewWrapperView"]) {
                if ([view isKindOfClass:[UIScrollView class]]) {
                    UIScrollView *scrollView = (UIScrollView *) view;
                    scrollView.delaysContentTouches = NO;
                }
                break;
            }
        }
    }
    return self;
    }
    
    - (BOOL) touchesShouldCancelInContentView : (UIView *) view {
    if ([view isKindOfClass:[UIButton class]]) {
        return YES;
    }
    return [super touchesShouldCancelInContentView:view];
    }
    

    以上,就能解决Button延迟高亮的方法.

    相关文章

      网友评论

      • 只有NO1:感谢 ,解决了我的问题
        哈哈哈我的简书账号:@只有NO1 - (instancetype) init
        {
        self = [super init];
        if (self) {
        self.delaysContentTouches = NO;
        //因为 UITableViewWrapperView 在iOS7不属于UIScrollView
        //iOS7
        for (id obj in self.subviews) {
        if ([NSStringFromClass([obj class]) isEqualToString:@"UITableViewCellScrollView"]) {
        UIScrollView *scrollView = (UIScrollView *) obj;
        scrollView.delaysContentTouches = NO;
        break;
        }
        }
        //ios 8
        for (id view in self.subviews) {
        if ([view isKindOfClass:[UIScrollView class]]) {
        UIScrollView *scrollView = (UIScrollView *) view;
        scrollView.delaysContentTouches = NO;
        }
        }
        }
        return self;
        }

        - (BOOL) touchesShouldCancelInContentView : (UIView *) view {
        if ([view isKindOfClass:[UIButton class]]) {
        return YES;
        }
        return [super touchesShouldCancelInContentView:view];
        }
        只有NO1:@哈哈哈我的简书账号 用他的方法继承UITableView重写他给的方法就可以了啊. 如果还是 不行 我还有另一个更好的方法你试试吧,写到工程里不用做任何操作直接就可以了
        extension UIButton {
        open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesBegan(touches, with: event)
        OperationQueue.main.addOperation {
        self.isHighlighted = true
        }
        }

        open override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesCancelled(touches, with: event)
        self.perform(#selector(setDefault), with: nil, afterDelay: 0.1)
        }

        open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesEnded(touches, with: event)
        self.perform(#selector(setDefault), with: nil, afterDelay: 0.1)
        }

        @ObjC func setDefault() {
        OperationQueue.main.addOperation {
        self.isHighlighted = false
        }
        }
        }
        哈哈哈我的简书账号:你怎么解决的,我的怎么不行呢

      本文标题:UITableView或UIScrollVIew上的UIButt

      本文链接:https://www.haomeiwen.com/subject/vlnbjttx.html