zoukankan      html  css  js  c++  java
  • [ios]自定义UI

    参考:http://blog.sina.com.cn/s/blog_7b9d64af0101edqf.html

    回忆一下,这么个场景。
    我们在一个界面上,要排列多个相同的元素。你马上就可以想到:
    1.如果要用按钮,可以使用来UIButton布局。
    如:
     

    - (void) showSectionListbyCount:(float)totalCount everyColCount:(float)paramColCount{

        

        int curNum=1;

        

        int TotalRow= ceilf(totalCount/paramColCount);// 总行数

        

        for (int curRow=0; curRow

        

            for (int curCol=0; curCol// 列数

                

                if (totalCount

                    return;

                }

                

                UIButton *btn=[UIButton buttonWithType:UIButtonTypeCustom];

                [btn setFrame:CGRectMake(10+(67+10)*curCol, (30+10)*curRow, 67, 30)];

                

                [btn setTitle:[NSString stringWithFormat:@"%d",curNum]forState:UIControlStateNormal];

                [btn setBackgroundImage:[UIImage imageNamed:@"btn_tv_n"]forState:UIControlStateNormal];

                [btn setBackgroundImage:[UIImage imageNamed:@"btn_tv_h"]forState:UIControlStateHighlighted];

                [btn setTitleColor:[UIColor blackColor]forState:UIControlStateNormal];

                [btn setTitleColor:[UIColor whiteColor]forState:UIControlStateHighlighted];

                [btn addTarget:self action:@selector(ClickControlAction:)forControlEvents:UIControlEventTouchUpInside];

                

                [btn setTag:curNum];

                

                [self.view addSubview:btn];

                curNum++;

                

            }

            

        }

    }

    如果,我们想用表格,那么每个元素可以使用UITableViewCell来定义相近的项。

    很简单是吧,因为,xCode,为我们提供了这些UI控件供我们使用!所以,我们只需要用!

    那么,今天的问题也就来了!如果,我想搞一个能够满足自己的一些UI元素。别急,也就是这样:

    比如,我要搞这么一个界面!

    重写UIView-让我们随心所欲的定制属于自己的UI控件

    我想,首先可以肯定,苹果不可能为我量身定制了这么一个控件。并且,如果,我用苹果的默认控件来写,那么我肯定会崩溃的。。

    也就是说,我们将每一项,写成单独的一个UI控件。那么,可以根据数据进行填充!那就酷毙了!

    绕了,一大圈,也就是要引用出来今天要学习的,东西!

    自定义UI!!!

    说起来,很牛X。其实很简单,说白了,就是子类化(重写)UIView。

    我们常常重写,UIButton,UIImageView,UITableView 等等。因为,可能我们用到的跟这些已有控件很相似,稍微修改一些就能够满足我们。

    但是,出入大的时候,我们就不能简单的继承于一个已有控件了!

    那就是完全重写!就是子类化UIView

    开始动手吧!!!

    1.定义一UIView个的子类。

    这个不解释!

    2.重写drawRect方法。或者重写layoutSubviews方法、

    1. drawRect方法:

    - (void)drawRect:(CGRect)rect

    {

        // Drawing code

        for (int i=0; i<<span style="color: #2f2fd0">10; i++) {

            UIButton *btn=[UIButton buttonWithType:UIButtonTypeCustom];

            [btn setFrame:CGRectMake(10, 10+i*40, 67, 30)];

            [btn setBackgroundImage:[UIImage imageNamed:@"btn_n"] forState:UIControlStateNormal];

            [btn setBackgroundImage:[UIImage imageNamed:@"btn_h"] forState:UIControlStateHighlighted];

            [btn addTarget:self action:@selector(ClickControlAction:)forControlEvents:UIControlEventTouchUpInside];

            [btn setTag:i];

            

            [self addSubview:btn];

        }

        

    }

    2. layoutSubviews 方法

    - (void)layoutSubviews{

        

        [super layoutSubviews];

        

        [self setBackgroundColor:[UIColor clearColor]];

        [_imgPic setFrame:CGRectMake(7, 6, 86, 108)];

        [_imgPic setImage:[UIImage imageNamed:[self.dictData objectForKey:@"img_content"]]];

        [_imgPic.layer setShouldRasterize:NO];

        [_imgPic.layer setBorderColor: [[UIColor whiteColor] CGColor]];

        [_imgPic.layer setBorderWidth: 1.0];

        [[_imgPic layer] setShadowRadius:2];

        [[_imgPic layer] setShadowOpacity:1];

        [[_imgPic layer] setShadowColor:[UIColor blackColor].CGColor];

        [[_imgPic layer] setShadowOffset:CGSizeMake(0, 1)];

        [self addSubview:self.imgPic];

        

    }

    可见,这两种方法都可以的。具体的区别,就是drawRect方法和layoutSubviews方法之间的区别了。

    但是,经过测试,我发现,应该使用drawRect方法,来完成界面的绘制。因为,如果我们使用的是layoutSubviews方法,那么每一次改变frame的时候,layoutSubviews都将重新执行。显然不科学。

    在网上,我看到,大部分例子使用的是drawRect方法,来重绘界面。(绘制界面)

    我使用了layoutSubviews方法。在frame改变时,会自动调用。(重定向子视图)

    根据需要选择使用哪一种方法!

    关于两种方法,在网上搜了一下,总结如下:

    layoutSubviews在以下情况下会被调用:

    1、init初始化不会触发layoutSubviews。

    2、addSubview会触发layoutSubviews。

    3、设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化。

    4、滚动一个UIScrollView会触发layoutSubviews。

    5、旋转Screen会触发父UIView上的layoutSubviews事件。

    6、改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件。

    7、直接调用setLayoutSubviews。

    drawRect在以下情况下会被调用:

    1、如果在UIView初始化时没有设置rect大小,将直接导致drawRect不被自动调用。drawRect 掉用是在Controller->loadView, Controller->viewDidLoad 两方法之后掉用的.所以不用担心在 控制器中,这些View的drawRect就开始画了.这样可以在控制器中设置一些值给View(如果这些View draw的时候需要用到某些变量 值).

    2、该方法在调用sizeToFit后被调用,所以可以先调用sizeToFit计算出size。然后系统自动调用drawRect:方法。

    3、通过设置contentMode属性值为UIViewContentModeRedraw。那么将在每次设置或更改frame的时候自动调用drawRect:。

    4、直接调用setNeedsDisplay,或者setNeedsDisplayInRect:触发drawRect:,但是有个前提条件是rect不能为0。

    以上1,2推荐;而3,4不提倡

    drawRect方法使用注意点:

    1、 若使用UIView绘图,只能在drawRect:方法中获取相应的contextRef并绘图。如果在其他方法中获取将获取到一个invalidate 的ref并且不能用于画图。drawRect:方法不能手动显示调用,必须通过调用setNeedsDisplay 或 者 setNeedsDisplayInRect,让系统自动调该方法。

    2、若使用calayer绘图,只能在drawInContext: 中(类似于drawRect)绘制,或者在delegate中的相应方法绘制。同样也是调用setNeedDisplay等间接调用以上方法

    3、若要实时画图,不能使用gestureRecognizer,只能使用touchbegan等方法来掉用setNeedsDisplay实时刷新屏幕

    3.自定义UIView的初始化方法。

    我们常常在UIViewController中,看到initWithNibName方法:

    - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

    {

        self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];

        if (self) {

            // coding

        }

        return self;

    }

    这是xCode给我们定义好的初始化方法。

    既然,我们要自定义UIView,那么最好,根据自己的业务逻辑,来完成子类化UIView的初始化方法:

    #pragma mark - Initialization 根据业务逻辑,传入数据,初始化自己

    - (id)initItemWithFram:(CGRect)frame andData:(NSMutableDictionary *)paramData{

        

        self = [super initWithFrame:frame];

        if (self) {

            // Initialization code

            _dictData=[[NSMutableDictionary alloc] init];

            _imgPic=[[UIImageView alloc] init];

            _imgCover=[[UIImageView alloc] init];

            _btnClick=[[UIButton alloc] init];

            _btnDel=[[UIButton alloc] init];

            _lblTips=[[UILabel alloc] init];

            _lblName=[[UILabel alloc] init];

            

        }

        self.dictData=paramData;

        return self;

        

        

    }

    + (id) initItemWithFrame:(CGRect)frame andData:(NSMutableDictionary *)paramData{

        WTVTVCollectionItem *tmpInstance=[[WTVTVCollectionItem alloc] initItemWithFram:frameandData:paramData];

        return tmpInstance;

    }

    这样,就可以初始化:

    NSMutableArray *items = [NSMutableArray array];

        

        [items addObject:[WTVTVCollectionItem initItemWithFrame:CGRectMake(10, 10, 100, 150)andData:dict]];

        [items addObject:[WTVTVCollectionItem initItemWithFrame:CGRectMake(10, 10, 100, 150)andData:dict]];

        [items addObject:[WTVTVCollectionItem initItemWithFrame:CGRectMake(10, 10, 100, 150)andData:dict]];

    4.为UIView加入一些动画

    动画是UI操作的灵魂!给予动画效果,就看上去有神了。

    添加动画,一般也用2种方法:

    1.重写UIView的方法,在调用时,进行动画操作。

    # pragma mark - 重写父类的removeFromSuperview方法,在删除时,使用相应的动画效果

    - (void) removeFromSuperview {

        

        [UIView animateWithDuration:0.2 animations:^{

            self.alpha = 0.0;

            [self setFrame:CGRectMake(self.frame.origin.x+50, self.frame.origin.y+50, 0, 0)];

            [_btnDel setFrame:CGRectMake(0, 0, 0, 0)];

        }completion:^(BOOL finished) {

            [super removeFromSuperview];

        }];

    }

    2.直接在UIView元素上,进行动画对象的添加

    - (void) enableEditing {

        

        if (self.isInEditingMode == YES)

            return;

        

        // 设置为编辑状态

        self.isInEditingMode = YES;

        [_btnDel setHidden:NO];

        

        // 开始晃动动画

        CATransform3D transform;

        // 获取0到x-1之间的整数

        if (arc4random() % 2 == 1)

            transform = CATransform3DMakeRotation(-0.08, 0, 0, 1.0);

        else

            transform = CATransform3DMakeRotation(0.08, 0, 0, 1.0);

        

        CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"];

        animation.toValue = [NSValue valueWithCATransform3D:transform];

        animation.autoreverses = YES;

        animation.duration = 0.1;

        animation.repeatCount = 10000;

        animation.delegate = self;

        [[self layer] addAnimation:animation forKey:@"wiggleAnimation"];

        [(WTVTVSprintBoard*)self.delegate enableEditingMode];

        

    }

     

    5.子类化UIView的交互

    如何将操作链接起来!?就是说,在控件外,对我们自定义的控件进行操作?!

    也有2种方法:

    1.消息

    2.代理

    总结:

    我想,我过多的将思路就可以了,因为业务需求不同,控件的自定义需求也不同,所以,不能用具体来固定!但是,思路是想通的,知道了原理,我们就可以发挥我们的聪明智慧,创造出千变万化的控件来!

    希望对你有所帮助!!!

  • 相关阅读:
    beforeRouteLeave 实现vue路由拦截浏览器的需求,进行一系列操作 草稿保存等等
    VUE 路由变化页面数据不刷新问题
    vue 监听 watch 使用
    vue-cli配置文件详解
    vue-cli脚手架中webpack配置基础文件详解
    Dbus组成和原理
    NUMA架构的优缺点
    define 的全部使用方法
    敏捷(Agile)——“说三道四”
    Linux 内核模块编译 Makefile
  • 原文地址:https://www.cnblogs.com/lyggqm/p/4813407.html
Copyright © 2011-2022 走看看