【UI控件总结】【UIScrollView】深入理解篇UIScrollerView
【UI控件总结】【UIScrollView】基本方法+基本描述
接下来,我整理一下自己的思路,深入理解 UIScrollView
基本点 :
1 . UIScrollView 是一个UIView。
每个UIView都有一个bounds和frame。当布局一个界面时,我们需要处理视图的frame。这允许我们放置并设置视图的大小。 视图的frame和bounds的大小总是一样的,但是他们的origin有可能不同(bounds的原点是(0,0)点(就是view本身的坐标系统,默认永远都是0,0点,除非调用了setbounds函数),而frame的原点却是任意的(相对于父视图中的坐标位置)。) 弄懂这两个工作原理是理解UIScrollView的关键。
2 . UIView的 bounds和frame 工作原理
这里有个概念 光栅化 和 组合 , 本人的简单理解:
光栅化 : 简单的说就是产生一组绘图指令并且生成一张图片(注意,这些图片并没有被绘制到屏幕上去;它们被自己的视图保持着留到下一个步骤用)
组合 : 光栅化之后,屏幕其实是空的,你什么都看不见,但是其实视图已经出现的了,这个时候这些图片便被一个接一个的绘制,并产生一个屏幕大小的图片,这便是组合, 这个时候,屏幕上就能看到你描绘的东西。再扯一点,视图层级(view hierarchy)对于组合如何进行扮演了很重要的角色:一个视图的图片被组合在它父视图图片的上面。然后,组合好的图片被组合到父视图的父视图图片上 面,就这样。。。最终视图层级最顶端是窗口(window),它组合好的图片便是我们看到的东西了。
小结 : 知道上面两种绘制图像的形式和过程之后 bounds的为什么一般是(0,0) , Frame却是以父控件为坐标原点,相信都有点理解了。
在光栅化步骤中,视图并不关心即将发生的组合步骤,这时视图只关心一件事就是绘制它自己的content。这个绘制发生在每个视图的drawRect:方法中 在drawRect:方法被调用前,会为视图创建一个空白的图片来绘制content。这个图片的坐标系统是视图的bounds。几乎每个视图 bounds的origin都是{0,0}(除非你重写setbounds方法,改动)。因此,当在删格化图片左上角绘制一些东西的时候,你都会在bounds的origin({x:0,y:0}) 处绘制。在一个图片右下角的地方绘制东西的时候,你都会绘制在{x:width, y:height}处。如果你的绘制超出了视图的bounds,那么超出的部分就不属于删格化图片的部分了,并且会被丢弃。
在组合的步骤中,每个视图将自己光栅化图片组合到自己父视图的光栅化图片上面。视图的frame决定了自己在父视图中绘制的位置,frame的 origin表明了视图光栅化图片左上角相对父视图光栅化图片左上角的偏移量。所以,一个origin为{x:20,y:15}的frame所绘制的图片 左边距其父视图20点,上边距父视图15点。因为视图的frame和bounds矩形的大小总是一样的,所以光栅化图片组合的时候是像素对齐的。这确保了 光栅化图片不会被拉伸或缩小。
小结 : bound 和 frame 大小一样,位置不同的深沉原因。
组合的时候,视图图片的左上角会根据它frame的origin进行偏移,并绘制到父视图的图片上:
// 组合点的X值 = 当前视图的frameX值 - 父视图的光栅化X值
CompositedPosition.x = View.frame.origin.x - Superview.bounds.origin.x(一般来说总是0);
// 组合点的Y值 = 当前视图的frameY值 - 父视图的光栅化Y值
CompositedPosition.y = View.frame.origin.y - Superview.bounds.origin.y(一般来说总是0);
3 . UIScrollView的 Content Offset 工作原理
正因为IOS这种组合原理, UIScrollView的工作原理就这样带出来了。
组合点的位置 (CompositedPosition.x , CompositedPosition.y) 就是子视图组合在父视图的位置
(题外话 :其实所有UIView都是这样,光栅化,组合的原理都是一样。 )
根据上面的公式,
改变 View.frame.origin.x 的值 和 Superview.bounds.origin.y的值, 都可以改变组合点值.
说个例子方便理解吧,
UIView *view = [[UIView alloc] init];
view.frame = CGRectMake(,,,);
view.background = [UIColor redcolor];
[self.view addSubviews:view]; UIButton *btn = [[UIButton alloc] init]
btn.frame = (, ,,);
[view addSubviews:btn]; UIButton *btn2 = [[UIButton alloc] init]
btn.frame = (, ,,);
[view addSubviews:btn2]; UIButton *btn3 = [[UIButton alloc] init]
btn.frame = (, ,,);
[view addSubviews:btn3]; /* 简单的步骤
步骤一 光栅化 :首先,view会创建一块 100 * 100 的空白区域,的图像指令, btn,btn2,btn3会创建一块 10 * 10 的空白区域
( 此时 ,屏幕啥都没看见,) 步骤二 组合, view会找到父view,以父view的原点(记得那条公式吗?也就是Superview.bounds.origin ,用自己的 (10 ,10) 减去 父VIew的 (0 , 0)),然后描绘在父view身上。同理 button 也是这样。 试想一下。btn现在是嵌套在哪里? 嵌套在view的 (10,10)(20,20)(30,30)这里,
因为他是用 btn.frame.origin.x, - view.bound.origin.x
假设,现在改变view.bound.origin , 将view的bound点,转移到 (-10,-10),刷新draw:rect方法重新组合的时候,是不是相当于,3个btn的组合点都在view的 {0,0}上了,是不是就相当于整一块向左上角平移了? UIScrollView的原理就是这样!!! */
UIScrollView 的工作原理,就是改变scroll view.bounds的origin。
当你设置它的contentOffset属性时:它改变scroll view.bounds的origin。事实上,contentOffset甚至不是实际存在的。代码看起来像这样:
- (void)setContentOffset:(CGPoint)offset
{
// 这个contentOffset的意义就是设置了bounds能set多小
CGRect bounds = [self bounds];
bounds.origin = offset;
[self setBounds:bounds];
}
ScrollerView三大属性
contentSize: The size of the content view. 其实就是scrollview可以滚动的区域,比如frame = (0 ,0 ,320 ,480) contentSize = (320 ,960),代表你的scrollview可以上下滚动,滚动区域为frame大小的两倍。
contentOffset:The point at which the origin of the content view is offset from the origin of the scroll view. 是scrollview当前显示区域顶点相对于frame顶点的偏移量,比如上个例子你拉到最下面,contentoffset就是(0 ,480),也就是y偏移了480
contentInset:The distance that the content view is inset from the enclosing scroll view.是scrollview的contentview的顶点相对于scrollview的位置,例如你的contentInset = (0 ,100),那么你的contentview就是从scrollview的(0 ,100)开始显示
content offset的最大值是content size和scroll view size的差。这也在情理之中:从左上角一直滚动到右下角,用户停止时,滚动区域右下角边缘和滚动视图bounds的右下角边缘是齐平的。你可以像这样记下content offset的最大值:
contentOffset.x = contentSize.width - bounds.size.width; contentOffset.y = contentSize.height - bounds.size.height;
【UI控件总结】【UIScrollView】深入理解篇UIScrollerView的更多相关文章
- UI控件(UIScrollView)
@implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; //创建一个scrollview UIScrollV ...
- UI控件之UIScrollView
UIScrollView:提供了滚动功能,用来显示超过一屏的视图 创建滚动视图 UIScrollView *scrollView=[[UIScrollView alloc]initWithFrame: ...
- 《深入理解Windows Phone 8.1 UI控件编程》基于最新的Runtime框架
<深入理解Windows Phone 8.1 UI控件编程>本书基于最新的Windows Phone 8.1 Runtime SDK编写,全面深入地论述了最酷的UI编程技术:实现复杂炫酷的 ...
- Cocos2d-x3.0游戏实例之《别救我》第六篇——从代码中获取UI控件
这篇的内容非常easy,获取UI控件,然后使用它. 还记得我们在UI编辑器中给三个button分别命名了吧? 如今要用上了. 笨木头花心贡献,啥?花心?不呢,是用心~ 转载请注明,原文地址: http ...
- 理解SynchronizationContext,如何在Winform里面跨线程访问UI控件
SynchronizationContext 类是一个基类,可提供不带同步的自由线程上下文. 此类实现的同步模型的目的是使公共语言运行库内部的异步/同步操作能够针对不同的异步模型采取正确的行为.此模型 ...
- Silverlight项目笔记1:UI控件与布局、MVVM、数据绑定、await/async、Linq查询、WCF RIA Services、序列化、委托与事件
最近从技术支持转到开发岗,做Silverlight部分的开发,用的Prism+MVVM,框架由同事搭好,目前做的主要是功能实现,用到了一些东西,侧重于如何使用,总结如下 1.UI控件与布局 常用的主要 ...
- UI控件概述
常见UI控件 UIKit框架提供了非常多功能强大又易用的UI控件,以便于开发者打造出各式各样的App 以下列举一些在开发中常见的UI控件(稍后补上图片示例) 1.UILabel– 文本标签:作用是显示 ...
- ANDROID L——Material Design详解(UI控件)
转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! Android L: Google已经确认Android L就是Android Lolli ...
- 富客户端 wpf, Winform 多线程更新UI控件
前言 在富客户端的app中,如果在主线程中运行一些长时间的任务,那么应用程序的UI就不能正常相应.因为主线程要负责消息循环,相应鼠标等事件还有展现UI. 因此我们可以开启一个线程来格外处理需要长时间的 ...
随机推荐
- 51nod 棋盘问题(博弈论)
题目链接: 棋盘问题 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 上帝创造了一个n*m棋盘,每一个格子都只有可能是黑色或者白色的. 亚当和夏娃在玩一个游戏,每次寻找边长为x的正方 ...
- BZOJ 3083: 遥远的国度 dfs序,树链剖分,倍增
今天再做一天树的题目,明天要开始专攻图论了.做图论十几天之后再把字符串搞搞,区域赛前再把计几看看. 3083: 遥远的国度 Time Limit: 10 Sec Memory Limit: 128 ...
- CS异步下载
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...
- WCF之错误和异常
CLR异常无法跨越服务边界,所有的异常都被封装(序列化)为SOAP Fault,可以让所有平台的用户接收到. SOAP1.1只有Body.1.2中含有Header+Body. 未捕获异常 异常会从逻辑 ...
- ListView 总结----持续中
ListView是常用的显示控件,默认背景是和系统窗口一样的透明色,如果给ListView加上背景图片,或者背景颜色时,滚动时listView会黑掉, 原因是,滚动时,列表里面的view重绘时,用的依 ...
- trigger()的event事件对象之坑
问题引入,先贴一段有问题的代码,如果你对 trigger() 这个函数了解不透彻,还真看不出这段代码错在哪.完成的功能是样式转换器,想让页面在加载后自行触发点击事件隐藏三个按钮,但是效果如图并没有隐 ...
- 8款给力HTML5/CSS3应用插件 可爱的HTML5笑脸
1.HTML5/CSS3实现笑脸动画 非常可爱 今天我们要分享一款基于纯CSS3实现的笑脸动画,我们只要在面部滑动鼠标,即可让人物的眼睛嘴巴动起来,实现微笑的效果,还挺可爱的. 在线演示 源码下载 2 ...
- 杭电2034——人见人爱A-B
#include <stdio.h> #include <algorithm> using namespace std; int main () { int a[110],b[ ...
- SNRO:Number Range
业务对象是在一定的编号范围内分配编号的,编号既可以是内部分配也可以是外部分配.对于外部分配,用户输入编号,系统检查这个编号是否被占用.对于内部分配,系统会自动的把编号分配给业务对象.所以内部分配和外部 ...
- ADO.NET笔记——利用Command对象的ExecuteScalar()方法返回一个数据值
相关知识: 有些SQL操作,例如SUM,只会从数据库返回一个数据值,而不是多行数据 尽管也可以使用ExecuteReader()返回一个DataReader对象,代表该数据值,但是使用Command对 ...