iOS中UIScrollerView的用法及基于AotoLayout的控件悬停_IOS

UIScrollView为了显示多于一个屏幕的内容或者超过你能放在内存中的内容。Scroll View为你处理缩小放大手势,UIScrollView实现了这些手势,并且替你处理对于它们的探测和回应。其中需要注意的子类是UITableView以及UITextView(用来显示大量的文字)。还有一个UIWebView,尽管那不是UIScrollView的直接子类,它适用UIScrollView去显示网页内容contentsize是内容的宽和高,contentsize.width是内容的宽度,contentsize.heght是高度,contentsize是UIScrollView的一个属性,它是一个CGSize,是由核心图形所定义的架构,那定义了你可以滚轴内容的宽度和高度,你也可以添加可以上下滚动的额外区域。第一种方法是你可以通过添加内容的大小来完成。另外一个比较动态的选择是UIScrollView的另一个属性contentInset,contentInset增加你在contentsize中指定的内容能够滚动的上下左右区域数量contentInset.top以及contentInset.buttom分别表示上面和下面的距离。

在滚轴视图中,有一个叫做ContentOffset的属性跟踪UIScrollView的具体位置,你能够自己获取和设置它,ContentOffset是你当前可视内容在滚轴视图边界的左上角那个点。如图:

可以看出,ContentOffset内容中的那个点不是从contentInset的左上角开始的,而是内容的左上角,此时的ContentOffset是正值,但有时也是负值,如下图所示:

使用一个ScrollView
创建一个UIScrollView

复制代码 代码如下:

CGRectframe = CGRectMake( 0, 0, 200, 200);
scrollView= [[UIScrollView alloc] initWithFrame: frame];

添加子视图(框架可以超过scroll view的边界)

复制代码 代码如下:

frame= CGRectMake( 0, 0, 500, 500);
myImageView= [[UIImageView alloc] initWithFrame: frame];
[scrollViewaddSubview:myImageView];

设置内容尺寸

复制代码 代码如下:

scrollView.contentSize= CGSize(500,500);

扩展Scroll View 的行为

  • 应用程序通常需要知道有关的滚图的事件
  • scrolloffset改变的时候
  • 拖动开始和结束
  • 减速的开始和结束

通过子类化扩展Scroll View 的行为

  • 创建一个子类
  • 重写一些功能并改变行为
  • 关于这种方式的争议

应用程序的逻辑和行为变成了视图本身的一部分,就像,你可能有一些定制的滚轴逻辑,,在那你只在意一个视图控制,但你想在不同地方重复使用你的滚轴视图,如果你必须为每个都子类化,你最后会有很多不同的滚轴视图子类以及在视图中的特定应用逻辑。

编写很多子类是很沉闷的事情,你最后会有很多无法重复使用的单独视图,而MVC的视图部分的一个重点是视图是可以在不同的控制器和不同的模式之中重复使用的,如果我们把所有逻辑都放在视图中,它减少了可复用性。

你的代码变得很牢固地配对在一起,它实际上变成了超类的一部分,你无法从UIScrollView中析取它,之后用其它东西代替,如果它在你控制器中且为控制器的一部分,在之后更容易改变它工作的方式和重新安排你应用程序的一些部分。

通过委派来扩展Scroll View 的行为(常用的)
委派是一个单独的对象,协议,定义了委派会实现的一系列功能的Objective-C协议,它创建了一系列很清晰的撤销点,在那里你能定制行为和外观。它在这些对象之间保持了松散的配对,视图本身与视图控制器或任何其它的控制器对象,委派不是滚轴视图的直接子类,它比起牢固配对的子类更加的松散。


理论篇
在滚动的过程中,实际上就是contentOffset的值在不断变化,当手指触摸后,UIScrollView会暂时拦截触摸事件,使用一个计时器。假如在计时器到点后没有发生手指移动事件,那么UIScrollView发送 tracking events 到被点击的 subview 上面。如果在计时器到点前发生了移动事件,那么UIScrollView取消 tracking 然后自己发生滚动。

可以重载子类

复制代码 代码如下:

- (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view;

决定自己是否接受 touch 事件

复制代码 代码如下:

- (BOOL)touchesShouldCancelInContentView:(UIView *)view;

开始发送 tracking messages 给 subview 的时候调用这个方法,决定是否发送 tracking messages 消息到 subview。
返回NO -> 发送,表示不取消
返回YES -> 不发送,表示会取消

属性篇

复制代码 代码如下:

@property(nonatomic,readonly,getter=isTracking) BOOL tracking;

当 touch 后还没有拖动的时候值是YES,否则NO

复制代码 代码如下:

@property(nonatomic,readonly,getter=isZoomBouncing) BOOL zoomBouncing;

当内容放大到最大或者最小的时候值是YES,否则NO

复制代码 代码如下:

@property(nonatomic,readonly,getter=isZooming) BOOL zooming;

当正在缩放的时候值是YES,否则NO

复制代码 代码如下:

@property(nonatomic,readonly,getter=isDecelerating) BOOL decelerating;

当滚动后,手指放开但是还在继续滚动中。这个时候是YES,其他时候是NO

复制代码 代码如下:

@property(nonatomic) CGFloat decelerationRate;

设置手指放开后的减速率

复制代码 代码如下:

@property(nonatomic) CGFloat maximumZoomScale;

表示放大的最大倍数

复制代码 代码如下:

@property(nonatomic) CGFloat minimumZoomScale;

表示缩小的最小倍数

复制代码 代码如下:

@property(nonatomic,getter=isPagingEnabled) BOOL pagingEnabled;

当值为YES的时候,就会产生翻页那种效果

复制代码 代码如下:

@property(nonatomic,getter=isScrollEnabled) BOOL scrollEnabled;

决定是否可以滚动

复制代码 代码如下:

@property(nonatomic) BOOL delaysContentTouches;

当值为YES的时候,用户一旦触碰,然后再一定时间内没有移动,UIScrollView会发送 tracking events,然后用户移动手指足够长度触发滚动事件,这个时候,UIScrollView发送了-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event到 subview,然后UIScrollView开始滚动。假如值为NO,UIScrollView发送 tracking events 后,就算用户移动手指,UIScrollView也不会滚动。

复制代码 代码如下:

@property(nonatomic) BOOL showsHorizontalScrollIndicator;

滚动时是否显示水平滚动条

复制代码 代码如下:

@property(nonatomic) BOOL showsVerticalScrollIndicator;

滚动时是否显示垂直滚动条

复制代码 代码如下:

@property(nonatomic) BOOL bounces;

默认是YES,就是滚动超过边界会有反弹回来的效果,如果设置为NO,那么滚动到边界就会立刻停止

复制代码 代码如下:

@property(nonatomic) BOOL bouncesZoom;

这个效果反映在缩放上面,如果缩放超过最大缩放,就会有反弹效果,加入设置为NO,则达到最大或者最小的时候立刻停止

复制代码 代码如下:

@property(nonatomic,getter=isDirectionalLockEnabled) BOOL directionalLockEnabled;

默认是NO,可以在垂直和水平方向同时运动。当值为YES的时候,加入一开始是垂直或者水平运动,那么接下来会锁定另外一个方向的滚动。加入一开始是对角方向滚动,则不会禁止某个方向

复制代码 代码如下:

@property(nonatomic) UIScrollViewIndicatorStyle indicatorStyle;

滚动条的样式,基本只是设置颜色

复制代码 代码如下:

@property(nonatomic) UIEdgeInsets scrollIndicatorInsets;

设置滚动条的位置

方法篇
直接上代码看

复制代码 代码如下:

#pragma mark UIScrollViewDelegate
//只要滚动了就会触发
- (void)scrollViewDidScroll:(UIScrollView *)scrollView;  
{
//    NSLog(@" scrollViewDidScroll");
    NSLog(@"ContentOffset  x is  %f,yis %f",scrollView.contentOffset.x,scrollView.contentOffset.y);
}
//开始拖拽视图
- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView;  
{
   NSLog(@"scrollViewWillBeginDragging");
}
//完成拖拽
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate;
{
   NSLog(@"scrollViewDidEndDragging");
}
//将开始降速时
- (void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView;  
{
   NSLog(@"scrollViewWillBeginDecelerating");
}

//减速停止了时执行,手触摸时执行
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView;  
{
   NSLog(@"scrollViewDidEndDecelerating");
}

//滚动动画停止时执行,代码改变时出发,也就是setContentOffset改变时
- (void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView;
{
   NSLog(@"scrollViewDidEndScrollingAnimation");
}

//设置放大缩小的视图,要是uiscrollview的subview
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView;  
{
   NSLog(@"viewForZoomingInScrollView");
    return viewA;
}

//完成放大缩小时调用
- (void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale;
{
    viewA.frame=CGRectMake(50,0,100,400);
   NSLog(@"scale between minimum and maximum. called after any 'bounce' animations");
}// scale between minimum and maximum. called after any 'bounce' animations

//如果你不是完全滚动到滚轴视图的顶部,你可以轻点状态栏,那个可视的滚轴视图会一直滚动到顶部,那是默认行为,你可以通过该方法返回NO来关闭它
- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView;  
{
    NSLog(@"scrollViewShouldScrollToTop");
   returnYES;
}

- (void)scrollViewDidScrollToTop:(UIScrollView *)scrollView;    
{
    NSLog(@"scrollViewDidScrollToTop");
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
   // Return YES for supported orientations
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

@end

基于AotoLayout的控件悬停

在很多的电商类的APP中我们经常会用到一种滑动悬停的效果,所以这次尝试着利用AutoLayout来实现这种效果。话不多说先上图
效果:

效果上过了,还是理顺下思路上吧。从效果图上不难发现我们的程序是基于UIScrollerView的。界面上的展示同样都是UIScrollView的子控件。当然了难点也就是基于UIScrollerView的内部子控件的布局以及AutoLayout约束的修改。
我们看一下我们的需要的一些基本的控件布局:

好了,现在开始开始搭建新的项目了,首先在Storyboard上搭建最基本的布局,并将控件基本布局到相应的位置,以备我们更方便的添加约束。

到了这里就开始对我们的控件添加基本的约束了从上开始吧。上面的控件我们能确定是UIImageView的heigth以及top、left以及rihgt。至于bottom到了后面会着重设置的。

然后继续来操作悬停的View。这个View因为处在两个view的中间所以我们要暂时确定height以及left和right的约束就足够了了

终于到最后一个UIImageView了,同样的能确定的是height、right、left以及bottom这四项。

到了这里针对单个的控件的布局基本完成了,细心的你可能会发现以上的操作都没有进行关联以及没有对width进行约束。那么下面我们就要开始进行三者的关联以及width上的设置。
因为悬停的view处与两个imageView的中间,所以我们只需要对它进行处理就好了

其实这两个约束完全是可以在设置悬停view的时候的添加,之所以在这里添加是我们在后面的控制器会用到这两个约束,为了好辨认我们就给他们定义上别名:

然后我们按住command选择我们的三个控件然后按住control拖向scrollView的父控件view设置等width。

好了,到了这里我们的约束已经不会再报错了,然后在逻辑上也是基本是通顺的了,但是对于我们悬停的功能来说就少了关键的一个环节那么就是一旦悬停view悬停了,那么它与上下两个imageView的约束要怎么处理呢?所以我们还需要一个辅助的约束用来悬停之后的关联处理

添加之后我们给这个约束起个别名hidden悬停,不过细心的你一定会发现添加之后会sb会提示出有冲突的约束,那么我们只需要对我们刚刚添加的约束进行一下操作就OK了

好了,到了这里我们在AutoLayout上要做的事情就这些了,下面我们就可以安心的写代码了。

复制代码 代码如下:

@interface ViewController ()/**中间的View*/@property (weak, nonatomic) IBOutlet UIView *centreView;/**上面的ImageView*/@property (weak, nonatomic) IBOutlet UIImageView *topImageView;/**centreView的top约束*/@property (weak, nonatomic) IBOutlet NSLayoutConstraint *topConstraint;/**centreView的bottom约束*/@property (weak, nonatomic) IBOutlet NSLayoutConstraint *bottomConstraint;/**topImageView暂禁用的约束*/@property (weak, nonatomic) IBOutlet NSLayoutConstraint *hiddenConstraint;
@end

然后在scrollView的滑动代理方法中实现

复制代码 代码如下:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
    //获得top图片的高度
    CGFloat imageH = self.topImageView.frame.size.height;
    //获取偏移量
    CGFloat offsetY = scrollView.contentOffset.y;
    //centrView的frame
    CGRect centreFrame = self.centreView.frame;
    if (offsetY>=imageH) {
        //将centreView的向上和向下的约束禁用
        self.bottomConstraint.active = NO;
        self.topConstraint.active = NO;
        //将topImageView与bottomImageView的约束使用关联
        self.hiddenConstraint.active = YES;
        //悬停在位置
        centreFrame.origin.y = 0;
        self.centreView.frame = centreFrame;
        //添加在scrollView的父控件
        [self.view addSubview:self.centreView];
    }else{
        //添加在topIamgeView的下面
        centreFrame.origin.y = imageH;
        self.centreView.frame = centreFrame;

        [scrollView addSubview:self.centreView];
        //记住一定要先添加到scrollView上之后在修改约束的内容,不然添加的约束会不成,因为系统无法建立他们之间的联系。
        self.hiddenConstraint.active = NO;
        self.topConstraint.active = YES;
        self.bottomConstraint.active = YES;

    }
    //等比例的伸缩
    CGFloat scale= 1-(offsetY/60);
    scale = (scale>=1)?scale :1;
    self.topImageView.transform = CGAffineTransformMakeScale(scale, scale);

}

最后补充:

在子控件的尺寸不能通过UIScrollView来计算,可以通过以下方式计算

  • 设置固定值(width==100,height==300)
  • 相对于UIScrollView以外的其他控件来计算尺寸

在UIScrollView里面布局子控件,sb里面默认是是需要子控件的尺寸以及子控件与UIScrollView之间的间距来计算出scroller的conentSize的。所以这就是上面的子控件要与父控件来等宽的原因了。
UIScrollView的frame应该通过子控件以外的其他控件来计算。

时间: 2024-07-28 23:14:07

iOS中UIScrollerView的用法及基于AotoLayout的控件悬停_IOS的相关文章

error-请教iOS中CMPedometer的用法

问题描述 请教iOS中CMPedometer的用法 10C #import @implementation FirstViewController (void)viewDidLoad { [super viewDidLoad]; [CMPedometer isStepCountingAvailable]; CMPedometer *pedonmeter = [[CMPedometer alloc] init]; [pedonmeter startPedometerUpdatesFromDate:

基于JS分页控件实现简单美观仿淘宝分页按钮效果_javascript技巧

最新版本代码请移步到https://github.com/pgkk/kkpager 在线测试链接:http://pgkk.github.io/kkpager/example/pager_test.html 分页按钮思想: 1.少于9页,全部显示 2.大于9页,1.2页显示,中间页码当前页为中心,前后各留两个页码 附件中有完整例子的压缩包下载.已更新到最新版本 先看效果图: 01输入框焦点效果 02效果 模仿淘宝的分页按钮效果控件kkpager JS代码: Js代码 var kkpager = {

C#中如何让工具栏ToolStrip能触发焦点控件

C#中如何让工具栏ToolStrip能触发焦点控件的Leave.Validating.DataError等事件以验证数据 如题,Winform码农大概都知道这样一个问题,就是当输入焦点仍处在TextBox.DataGridViewCell等控件中时,如果单击普通Button.CheckBox等控件,那么该验证的会得到验证,该提交的会提交,该报错的会报错,该被阻止的操作会被阻止.但如果单击的是工具栏上的项目(如ToolStripButton,之所以说项目而不是控件,你懂的),是不会触发焦点控件的验

谁在java项目中在jsp页面加载gis视频控件,谁用过??

问题描述 谁在java项目中在jsp页面加载gis视频控件,谁用过?? 为什么在本地html上可以加载上,但是部署到项目上 通过jsp去打开 就无法加载到,显示不出视频呢.求大神 解决方案 视频指定的路径对不对?

mfc-MFC、dll库中的对话框,无法用Tab键控件之间切换

问题描述 MFC.dll库中的对话框,无法用Tab键控件之间切换 在控件风格中已经加了tab相关的风格,控件属性Tabstop也改成了true,也Ctrl+D设置了控件响应tab键的顺序,可是按tab键就是不切换,同时上下键和回车键也没用,求大神解答

如何从数据库中读取图片并显示在MFC picture控件当中?

问题描述 如何从数据库中读取图片并显示在MFC picture控件当中? 如何从sqlite读取图片并显示在MFC picture控件当中?新手啊,不知道大概怎么弄,如果能给几行代码,感激不尽! 解决方案 参考:http://blog.csdn.net/zhangyulin54321/article/details/8098484 解决方案二: MFC picture控件中显示图片MFC picture控件中显示图片MFC picture控件显示图片(新手)

listview-在Activity中调用Adapter.getView更改不了某控件的状态

问题描述 在Activity中调用Adapter.getView更改不了某控件的状态 在activity中调用adapter.gerView方法(此adapter是继承baseAdapter的而来的),得到了某个控件在listView列表项中的View,然后通过这个View.FindViewByID找到这个控件,最后更新控件的状态,但是为什么不起作用? PS : 下面那个state的值是在广播中收到的消息,由于太多就不一一贴出来了. MyAdapter adapter = new MyAdapt

edittext bitmap-我想在Android中利用EditText(TextView)实现在控件的最右边添加一张位图。。

问题描述 我想在Android中利用EditText(TextView)实现在控件的最右边添加一张位图.. 解决方案 外面一个FramLayou框起来就解决了 解决方案二: 最好的是自定控件,通过canvas画上去,或者再简单点就是做个背景图你懂的 解决方案三: 给你的edittext设置一个下面这个属性,试试 android:drawableRight="@drawable/right_icon" 解决方案四: Android控件之TextView和EditTextAndroid系统

view类中怎么访问属性栏上的属性网格控件?

问题描述 view类中怎么访问属性栏上的属性网格控件? 小弟在做一个MFC绘图的程序,需要在绘图区中点击相应的图形,如直线,在右侧的属性栏上显示对应图形的参数,使用成员变量的形式访问会出现内存冲突的问题,求高手解答,O(∩_∩)O谢谢! 解决方案 可以通过主框架窗口来中转,在View中很容易访问主框架窗口(比如通过AfxGetMainWnd() SDI程序),在CMainFrame类中肯定定义了相关的属性类的对象成员.