zoukankan      html  css  js  c++  java
  • 【View层】界面绘制

    【引用】:http://www.jianshu.com/p/c5fc8c6b967a

    【View层】IOS纯代码绘制界面(一)

    字数2303 阅读385 评论2 喜欢16

    IOS开发中界面绘制占据了绝大部分的工作量,当前可以使用StoryBoard,xib以及代码三种方式定制所需要的界面。在这三种方式中代码是最灵活,最具有扩展性的,而特别是多人合作的大项目中StoryBoard,xib不利于代码合并。
    接下来对之前项目的的界面开发做一些总结。

    • UIViewController和重要子类
      • UINavigationController
    • UIView和重要子类
      • UIControl
      • UIScrollView
    • 各种常用控件的注意点(后续介绍)
    • 应用约束Masonry库(后续介绍)
    • 常用的Code Snippet(后续介绍)

    UIViewController和重要子类

    UINavigationController
    打交道最多的类无疑是这两个,一般我们采用UINavigationController(导航控制器,navi)作为UIViewController(vc)的容器,最常用的方法是

    //用指定的vc创建,该vc位于栈底。
    -(instancetype)initWithRootViewController:(UIViewController *)rootViewController; 
    
    //向栈里push一个vc,位于栈顶
    -(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated;
    
    //从栈里pop一个vc。
    -(nullable UIViewController *)popViewControllerAnimated:(BOOL)animated;

    一般app中只需要用到一个navi,在AppDelegate中完成初始化即可,后续的界面迁移都是push和pop。值得注意的是使用了navi之后,每个界面会产生一个navigationBar,即位于界面顶部的导航条。导航条的作用是显示当前的界面title和返回按钮,并支持自己添加需要的辅助功能。在任何vc中可以通过

    self.navigationController.navigationBar或者self.navigationItem

    访问这个组件,如设置背景色,添加按钮等:

    [self.navigationController.navigationBar setTitleTextAttributes:@{NSFontAttributeName : [UIFont systemFontOfSize:19], NSForegroundColorAttributeName : someColor}];
    [self.navigationController.navigationBar setBackgroundColor:[UIColor whiteColor]];
    UIBarButtonItem  * activityDetail = [[UIBarButtonItem alloc] initWithTitle:@“帮助” style:UIBarButtonItemStylePlain target:self action:@selector(helpButtonClicked)];
    self.navigationItem.rightBarButtonItem = activityDetail;
    UIViewController

    作为视图控制器基类,我们一般在里面添加view代码,显示逻辑,包括按钮事件、代理方法(比如tableView的代理等)。不注意的话vc会变得很大,如果行数过多则不易维护,所以说复杂的页面应该做架构上的区分,如MVVM模式将view,viewModel抽离出来。这里暂不细讲。
    vc最重要的方法包括:

    生命周期相关的方法

    //重写该方法意味着不加载外部的xib文件,自己绘制界面
    -(void)loadView; 
    -(void)viewDidLoad; 
    -(void)viewWillAppear:(BOOL)animated;   
    -(void)viewDidAppear:(BOOL)animated;

    以上方法在view加载过程中依次调用。一般在loadView或者viewDidLoad中添加自定义的view,但不能添加过于耗时的操作,以避免界面加载被阻塞导致的卡顿。一般把如网络操作,数据库操作加载viewDidAppear中,界面加载可见之后执行。

    UIView和重要子类

    UIView

    先总结UIView的通用方法和属性,然后介绍常用view控件的使用经验。
    初始化方法,以一个frame作为参数。

    • (instancetype)initWithFrame:(CGRect)frame

    基本

    • userInteractionEnabled
      默认YES,代表是否具有用户可操作性,设为NO时任何手势都不生效。在视图重叠的时候,用户的触摸会到达第一个开启了userInteractionEnabled=YES的视图。这个特性有两种用法:穿透和拦截,前者可以制作透明的不可交互背景,后者可以做比如加载中这种遮罩。
    • layer
      UIView内部实现,类型是CALayer,并封装了许多未暴露到UIView中的内容,如cornerRadius属性实现圆角只能调用view.layer.cornerRadius。
    • tag
      结合viewWithTag使用,类似于android中的findViewById,类似于JavaScript中的getElementById的用法。但不是全局使用,而是在一个view的子视图中查找目标tag。典型场景如两个控件绑定了一个vc作为delegate,实现的协议中可以通过tag来判断是来自哪个控件的事件。

    位置与空间相关:

    • frame
    • bounds

    每个UIView有frame 和bounds两个属性,分别代表相对父容器的矩形和相对本容器的矩形(有点难理解)

    struct CGRect { 
      CGPoint origin; 
      CGSize size; 
    };

    bound一般用来修改view的相对位置,类似于css中的相对布局,frame类似绝对布局。如图


    Paste_Image.png
    • center
      中心点CGPoint
    • transform
      视图的仿射变换,默认是CGAffineTransformIdentity,解释为原始变换,意思就是维持原样。通过修改这个值可以改变view的外观,尤其在动画中常用。
    • contentScaleFactor
      缩放比例CGFloat
    • -sizeThatFits:
      方法,返回适合其中子类的大小。

    view的层次

    • subviews
      返回所有的子视图
    • superview
      返回父视图
    • window
      返回view的window对象
    • -(void)removeFromSuperview;
      把自己从父view中删掉
    • -(void)addSubview:(UIView *)view;
      添加子view
    • -(void)bringSubviewToFront:(UIView *)view;
      把子view拉到最前(重叠的情况下,默认按照添加顺序来一层层盖住之前的view)
    • -(void)sendSubviewToBack:(UIView *)view;
      把子view放到最后
    • -(void)layoutSubviews;
      override point. called by layoutIfNeeded automatically. As of iOS 6.0, when constraints-based layout is used。该方法的调用时机:
      addSubview会触发layoutSubviews
      设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化
      滚动一个UIScrollView会触发layoutSubviews
      旋转Screen会触发父UIView上的layoutSubviews事件 -改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件

    view的绘制

    • (void)drawRect:(CGRect)rect;
      由setNeedsDisplay来触发调用,可以重写该方法来实现一个自定义view,例如在里面执行
    - (void)drawRect:(CGRect)rect {  
        // Drawing code.  
        //获得处理的上下文    
        CGContextRef context = UIGraphicsGetCurrentContext();    
        //设置线条样式    
        CGContextSetLineCap(context, kCGLineCapSquare);     
        //设置线条粗细宽度    
        CGContextSetLineWidth(context, 1.0);     
    
        //设置颜色    
        CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0);     
        //开始一个起始路径    
        CGContextBeginPath(context);     
        //起始点设置为(0,0):注意这是上下文对应区域中的相对坐标,    
        CGContextMoveToPoint(context, 0, 0);     
        //设置下一个坐标点    
        CGContextAddLineToPoint(context, 100, 100);     
        //设置下一个坐标点    
        CGContextAddLineToPoint(context, 0, 150);    
        //设置下一个坐标点    
        CGContextAddLineToPoint(context, 50, 180);    
        //连接上面定义的坐标点    
        CGContextStrokePath(context);  
     }

    调用时机drawRect是在Controller.loadView,viewDidLoad 两方法之后掉用的.所以不用担心在控制器中,这些View的drawRect就开始画了.这样可以在控制器中设置一些值给View(如果这些View draw的时候需要用到某些变量值).

    • clipsToBounds
      默认NO,代表子元素显示时可以超出该view的边界。
    • backgroundColor
      背景颜色
    • alpha
      透明度,默认为1.0代表不透明,注意当alpha为0时等同于hidden,控件无法接收到点击事件。注意该值会影响子视图的绘制,但子视图的alpha不受影响,子视图绘制时的alpha实际效果等于包含链上的所有alpha之乘积。
    • opaque
      不透明,默认为YES
    • hidden
      隐藏,默认为NO
    • contentMode
      参考UIViewContentMode,有多重展示的模式,如图:

    Paste_Image.png

    动画相关

    - +(void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^ )(void))animations completion:(void (^ __nullable)(BOOL finished))completion

    方法接受几个参数:duration, delay, options, animations, completion。duration代表执行多久delay代表延迟多少时间开始执行,option参考UIViewAnimationOptions(篇幅过大此处略过),animation和completion各为一个block,代表执行的动画和完成后执行的代码。一段示例代码(慢慢放大后迅速缩小的提示效果):


    Paste_Image.png


    其他方法和该方法类似,实际使用时根据实际情况决定。

    手势相关
    添加和删除手势,不过多介绍。

    • -(void)addGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer;
    • -(void)removeGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer;
    UIControl

    子类包括:


    Paste_Image.png


    其中UIButton和UITextField,UISwitch都是平时十分常用的控件,作为他们的基类有必要介绍一下。

    重要的属性与方法:

    • enabled
      是否激活,默认YES,设为NO在视觉上会变为灰色
    • selected
      是否选中,默认NO,参考UIControlState
    • highlighted
      是否highlighted,默认NO,参考UIControlState
    • state
      UIControlState类型

    UIControl 基本的 State 变化过程如下
    1.什么都没干的时候:Normal
    2.当你的手指按下去,还没放的时候:Highlighted
    3.当手指放开的时候:如果这个 UIControl 有 Selected 状态的话,就会变成: Selected
    再重复上述过程一次,就会从 Selected->Highlighted-> Normal
    但是普通的 UIButton 这个 UIControl 的 subclass,是没有 Selected 状态的,它就只有 Normal 和 Highlighted,只会在这两个状态间切换。(正常情况下,如果你设置了 disable 的话,还会变到 Disabled)

    按钮事件

    - (void)addTarget:(nullable id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents;

    普通的按钮通过该方法绑定事件即可,其中sel是一个方法指针,UIControlEvents定义了可发送事件的几种类型。按钮点击一般使用UIControlEventTouchUpInside。代表在控件范围内按下去并放开。其余的属性可参考UIControlEvents。

    自定义事件实现

    - (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(nullable UIEvent *)event;
    - (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(nullable UIEvent *)event;
    - (void)endTrackingWithTouch:(nullable UITouch *)touch withEvent:(nullable UIEvent *)event;

    通过以上三个方法可以实现自定义的控件,比如要自己实现滑块效果,先调用begin,然后在continue中利用touch.locationInView的值来改变滑块代表的数值,在end中完成网络,数据库等操作。 

  • 相关阅读:
    JavaScript之函数(上)
    JAVA 遍历文件夹下的所有文件(递归调用和非递归调用)<转>
    Mac配置环境变量注意点
    netty tcp拆包
    mybatis注解方式批量插入数据
    JMX超详细解读<转>
    使用EmbeddedValueResolverAware读取配置文件内容
    线程的几种状态转换<转>
    Java线程池关闭1-shutdown和isTerminated<转>
    Maven项目编译后classes文件中没有.xml问题
  • 原文地址:https://www.cnblogs.com/lucky-star-star/p/5664942.html
Copyright © 2011-2022 走看看