您的位置:首页 > 产品设计 > UI/UE

【转】UIButton 在 UIScrollView 中的 高亮延迟 和 滑动冲突

2015-02-09 11:10 288 查看
最近做项目遇见一个问题:UIScrollView上有许多UIButton,要实现既能点击UIButton,又能滑动UIScrollView,这个实现没有问题,不需要做额外的touch管理,UIScrollView能识别是点击的UIButton还是滑动本身,但是有一个效果上的问题,就是点击UIButton时间短的话,不会高亮,但是确实是触发点击了,这样就造成了假象,给人一种UIButton没有被点击的感觉。如果点击时间长的话没有问题,会高亮。

这么看来,导致这样现象应该就是时间长短的问题,顺着这个问题想下去,就追寻到UIScrollView的touch原理,当UIScrollView接收到一个touch时,它会在一段时间(好像是150ms)内监听该touch是否移动了,假如移动了(应该有一个移动范围),则取消将touch发送到其子视图(例如UIButton),UIScrollView自身接受该touch,进行滑动。看来应该就是这段判断时间惹的祸了(这里其实我还想不明白为什么明明点击了Button,也确实触发了点击,却没有高亮状态,哪位大神知道的话请指教),那要解决问题是不是就应该把这段时间取消掉呢,不要这个判断时间,那么UIButton应该就会立即响应并产生高亮状态吧。正好UIScrollView中有一个属性叫delaysContentTouches,官方文档对它的解释是:If
the value of this property is YES, the scroll view delays handling the touch-down gesture until it can determine if scrolling is the intent. If the value is NO , the scroll view immediately calls touchesShouldBegin:withEvent:inContentView:. The default value
is YES.意思就是设置为NO就不会存在那个150ms的判断时间了,直接执行后续操作。那么咱们设置为NO来试试呗。结果确实如所想那样,UIButton立即响应并高亮。

但是…..别高兴太早,虽然这个问题解决了,但是新的麻烦又产生了,螳螂捕蝉黄雀在后!你会发现UIScrollView滑动不像以前那样了,假如touch down的那点落在UIButton上然后再滑动手指,UIScrollView不会滑动,但是UIButton仍然触发,当然,这样的结果也是应该的,你想想,设置delaysContentTouches为NO后,只要手指点在UIButton上,UIScrollView就会立即判定为这是点击UIButton,而不会再等待看手指是否移动来决定是否要滑动本身了。

那么如何解决这个问题呢?你会想,有没有什么方法可以在touch到UIbutton上并滑动时不触发UIButton而让UIScrollView自己滑动呢,强大的iOS没有让你失望,UIScrollView中有一个方法:touchesShouldCancelInContentView:,来看它的解释:The
scroll view calls this method just after it starts sending tracking messages to the content view. If it receives NO from this method, it stops dragging and forwards the touch events to the content subview. The scroll view does not call this method if the value
of the canCancelContentTouches property is NO.意思就是当UIScrollView将touch事件交给子view后,当手指发生滑动时,调用此方法,假如返回NO,则将touch事件交给子view,如果返回YES,则交给UIScrollView处理,产生滑动。(但是前提是UIScrollView的canCancelContentTouches属性是YES才会调用这个方法,只要不是UIControll的子类,这个属性默认是YES。)所以只要重写UIScrollView的这个方法并返回YES就可以啦,到此问题就解决了。既能立即响应UIButton,也能自由滑动UIScrollView。

举例:

首先定义一个继承UIScrollView的View。

fsScrollView.h

复制代码

//

// fsScrollView.h

// mbaby

//

// Created by fanpingyang on 14-10-13.

// Copyright (c) 2014年 moogeek. All rights reserved.

//

#import <UIKit/UIKit.h>

@interface fsScrollView : UIScrollView <UIScrollViewDelegate>

@end

重写touchesShouldCancelInContentView:

fsScrollView.m

复制代码

//

// fsScrollView.m

// mbaby

//

// Created by fanpingyang on 14-10-13.

// Copyright (c) 2014年 moogeek. All rights reserved.

//

#import "fsScrollView.h"

@implementation fsScrollView

- (BOOL)touchesShouldCancelInContentView:(UIView *)view

{

//NO scroll不可以滚动 YES scroll可以滚动

return YES;

}

@end

然后在需要创建UIScrollView的ViewController中定义ScrollView

.h文件

复制代码

#import <UIKit/UIKit.h>

#import "fsScrollView.h"

@interface fsSelectViewController : UIViewController<UIScrollViewDelegate>

{

NSMutableArray *classArray;

fsScrollView *classScrollView;

}

@property(nonatomic,strong) NSMutableArray *classArray;

@property(nonatomic,strong) fsScrollView *classScrollView;

@end

.m文件

复制代码

- (void)viewDidLoad

{

[super viewDidLoad];

//初始化 辅食分类

[self initClassArray];

classScrollView=[[fsScrollView alloc] initWithFrame:CGRectMake(0,0,classCenterView.bounds.size.width,classCenterView.bounds.size.height) ];

classScrollView.delegate = self;

classScrollView.backgroundColor = [UIColor clearColor];

classScrollView.pagingEnabled = NO;

classScrollView.showsHorizontalScrollIndicator = NO;

classScrollView.showsVerticalScrollIndicator = NO;

classScrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth;

classScrollView.userInteractionEnabled=YES;

[classScrollView setContentOffset:CGPointMake(0, 0)];

classCurrentPage = 0;

classPageControl=[[UIPageControl alloc]initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 0)];

classPageControl.numberOfPages = [classArray count];

classPageControl.currentPage = 0;

classPageControl.backgroundColor = [UIColor whiteColor];

[self initClassScrollView];

}

-(void) initClassArray

{

classArray=[[NSMutableArray alloc] init];

[classArray addObject:@"粥类"];

[classArray addObject:@"果蔬"];

[classArray addObject:@"蛋类"];

[classArray addObject:@"汤类"];

[classArray addObject:@"糕点"];

[classArray addObject:@"其他"];

[classArray addObject:@"其他"];

[classArray addObject:@"其他"];

[classArray addObject:@"其他"];

[classArray addObject:@"其他"];

}

-(void) initClassScrollView

{

for (int i=0; i<[classArray count]; i++)

{

UILabel *lblTitle=[[UILabel alloc] initWithFrame:CGRectMake(i*48+2, 0, 48, 34)];

[lblTitle setText:[classArray objectAtIndex:i]];

[lblTitle setTextColor:[UIColor colorWithRed:23.0f/255.0f green:23.0f/255.0f blue:23.0f/255.0f alpha:1.0] ];

[lblTitle setTextAlignment:NSTextAlignmentCenter];

[lblTitle setFont:[UIFont systemFontOfSize:13.0f]];

UIButton *btnItem=[[UIButton alloc] initWithFrame:CGRectMake(i*48+2, 0, 48, 34)];

[btnItem setBackgroundColor:[UIColor clearColor]];

[btnItem setTitle:@"" forState:UIControlStateNormal];

btnItem.tag=[[NSString stringWithFormat:@"1000%d",i] intValue];

[btnItem addTarget:self action:@selector(classItemClickListener:) forControlEvents:UIControlEventTouchUpInside];

btnItem.userInteractionEnabled=YES;

[classScrollView addSubview:lblTitle];

[classScrollView addSubview:btnItem];

//[self adjustScrollViewContentX:btnItem];

}

classScrollView.contentSize = CGSizeMake(48 * [classArray count], classScrollView.frame.size.height);

}

-(void) classItemClickListener:(UIButton *)button

{

int itemIndex=0;

NSString *buttonTagStr=[NSString stringWithFormat:@"%d",button.tag];

itemIndex=[[buttonTagStr substringFromIndex:4] intValue];

NSLog(@"click item num: %d",itemIndex);

}

有需要的同学借鉴一下吧。

摘录:
http://blog.sina.com.cn/s/blog_71715bf80101ie1e.html http://www.cocoachina.com/bbs/read.php?tid=234183
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: