美文网首页iOS视图
iOS中的Flex布局-FlexLib的使用

iOS中的Flex布局-FlexLib的使用

作者: QiShare | 来源:发表于2022-03-17 14:11 被阅读0次

    一. 概述

    进行iOS项目开发时,常用的布局方式有两种:Frame布局和AutoLayoutFrame布局没啥可说的,直接设置控件的横纵坐标,并指定宽高。AutoLayout是通过设置控件相对位置的约束进行布局。AutoLayout的本意是好的,但是由于他的语法实在不怎么友好,导致我们在实际项目开发中用的并不多,只能靠Masonry这样的第三方库来使用它。Masonry布局虽然容易理解,但是它的代码量太大,每一个控件都要对其进行block设置。
    在前端开发中,Flex布局使用尤为普遍,那么iOS端有没有类似前端Flex布局的方案呢?答案是肯定的,除了在 Weex 以及 React Native 两个著名的跨平台项目里有用到 Flex布局外,AsyncDisplayKit 也同样引入了 Flex布局,它们都是基于 FacebookYoga 的二次开发。而今天我们要介绍的 FlexLib 同样如此。

    二. Flex布局与相关属性介绍

    先来了解一下Flex布局:
    Flex布局又叫弹性布局,是一种为一维布局而设计的布局方法。一维的意思是你希望内容是按行或者列来布局。你可以使用display:flex来将元素变为弹性布局。我们直接看例子:
    实现7个item横向排列

    image
    <!DOCTYPE html>
    <html>
        <head>
            <title>flex布局2</title>
            <meta charset="UTF-8">
            <style>
                * {
                    margin:  0;
                    padding: 0;
                    box-sizing: border-box;
                }
                .container {
                    display: flex;
                    flex-direction: row;
                    justify-content: flex-start;
                    align-items: flex-end;
                    background-color: wheat;
                    flex-wrap: wrap;
                }
               .item {
                   width: 100px;
                   height: 100px;
                   border: 1px solid royalblue;
                   text-align: center;
                   line-height: 100px;
                   margin: 10px 10px;
               }
               .item6 {
                   flex: 1;
               }
               .item7 {
                   flex: 2;
               }
            </style>
        </head>
    
        <body>
            <div class="container">
                <div class="item0 item">item0</div>
                <div class="item1 item">item1</div>
                <div class="item2 item">item2</div>
                <div class="item3 item">item3</div>
                <div class="item4 item">item4</div>
                <div class="item5 item">item5</div>
                <div class="item6 item">item6</div>
                <div class="item7 item">item7</div>
            </div>
        </body>
    </html>
    

    上面是前端代码,看不懂没关系,这里重点是借这个例子来熟悉一下Flex布局的一些常用属性。Flex属性分类两类:一类是作用在容器上的,另一类是作用在子Item上的。

    1. 作用在容器上的属性
    • display:flex: 设置container容器为弹性布局

    • flex-direction:决定主轴的方向,项目横向或是纵向排列
      取值:row | row-reverse | column | column-reverse;
      row(默认值):主轴为水平方向,起点在左端。
      row-reverse:主轴为水平方向,起点在右端。
      column:主轴为垂直方向,起点在上沿。
      column-reverse:主轴为垂直方向,起点在下沿。

    • justify-content: 定义Item在主轴上如何对齐。
      取值:flex-start | flex-end | center | space-between | space-around;
      flex-start(默认值):左对齐
      flex-end:右对齐
      center: 居中
      space-between:两端对齐,项目之间的间隔都相等。
      space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。

    • align-items:定义Item在交叉轴上如何对齐。
      取值:align-items: flex-start | flex-end | center;
      flex-start:交叉轴的起点对齐。
      flex-end:交叉轴的终点对齐。
      center:交叉轴的中间点对齐。

    • flex-wrap:一条轴线上放不下,决定其是否换行
      取值: nowrap(不换行) | wrap(换行)

    • align-content:也是控制Flex Item 在交叉轴上的对齐方式,只不过是以一整行作为最小单位。注意,如果Flex Item只有一行,该属性不起作用的。调整 flex-wrap 为 Wrap,效果才显示出来。
      取值:flex-start | flex-end | center | space-between | space-around;

    1. 作用在Item上的属性
    • align-self:可以让单个 Flex Item 与其它 Flex Item 有不一样的对齐方式,覆盖 align-items属性。默认值为auto,表示继承Flex容器的align-items属性。

    • flex 属性:flex属性是flex-grow, flex-shrinkflex-basis的简写,默认值为0 1 auto
      flex-grow: 属性定义项目的放大比例,默认为0,即如果存在剩余空间也不放大。 取值越大,占用剩余空间越大。
      flex-shrink: 属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。
      flex-basis:属性指定了flex元素在主轴方向上的初始大小

    这里设置item6item7 的flex为1和2,表示当前轴剩余的空间item6占1/3,item7占2/3.
    更多的关于flex的属性可以查看这里:Flex布局

    三. FlexLib的使用

    1.使用方式

    CocoaPods引入FlexLib:

    pod 'FlexLib'
    

    使用:

    • 创建视图控制器继承FlexBaseVC,或者创建视图继承FlexCustomBaseView
    • 创建与视图控制器或视图同名的xml文件
    • 在xml文件中添加控件进行布局
      例子:
    image

    TestLoginVC.h

    @interface TestLoginVC : FlexBaseVC
    @end
    

    TestLoginVC.m

    #import "TestLoginVC.h"
    
    @interface TestLoginVC ()
    {
        UIScrollView* scroll;//自动绑定name属性的值
        UIView* close;
    }
    
    @end
    
    @implementation TestLoginVC
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.navigationItem.title = @"Touch Demo";
    }
    
    - (void)tapTouchAction
    {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@""
                                                        message:@"You pressed"
                                                       delegate:nil
                                              cancelButtonTitle:@"Cancel"
                                              otherButtonTitles:@"OK",nil];
        
        [alert show];
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
    }
    @end
    

    TestLoginVC.xml

    <?xml version="1.0" encoding="utf-8"?>
    <UIView
        layout="
        flex:1,
        alignItems:center"
        attr="bgColor:white">
        <FlexScrollView name="scroll"  layout="padding:50,flex:1,width:100%,alignItems:center" attr="bgColor:white,vertScroll:true,">
            <FlexTouchView onPress="tapTouchAction" attr="underlayColor:blue">
                <UIImageView layout="width:100,height:100" attr="borderRadius:50,clipsToBounds:true,source:qrcode.png">
                    <FlexTouchMaskView attr="bgColor:red,alpha:0.7"/>
                </UIImageView>
            </FlexTouchView>
            <UIView layout="height:20"/>
            <FlexTouchView onPress="tapTouchAction" layout="height:100,width:100%,alignItems:center,justifyContent:center" attr="bgColor:#e5e5e5,borderRadius:8,underlayColor:darkGray">
                <UILabel layout="width:100%" attr="fontSize:16,textAlign:center,color:red,text:Please touch me and move\,\r\n这是测试touch功能的控件,linesNum:0"/>
            </FlexTouchView>
            <UIView layout="height:20"/>
            <UILabel layout="width:100%" attr="fontSize:20,linesNum:0,color:#333333,text:You can press the buttons above to see the effect. We use FlexTouchView to provide more powerful function and better flexibility than button."/>
        </FlexScrollView>
    </UIView> 
    
    

    说明:

    • 默认视图从上到下进行排列,在视图标签内添加其他视图,相当于为视图添加子视图

    • FlexLib支持两种类型的属性:布局属性(Layout)和视图属性(attr),布局属性与yoga所支持的属性一致,视图属性除了文档中所列的属性以外,还可以使用FLEXSET宏对现有属性进行扩展。你可以在这里查看它所支持的 layout attributesview attributes

    • FlexScrollView(UIScrollView的子类)可以自动管理滚动范围,FlexTouchView类似于UIButton,内置onPress属性,可以设置其触发方法。

    • 可以设置控件的name属性,name属性的值会自动绑定代码中具有相同名称的成员变量,你可以直接在代码中使用它。

    • 你可以预定义一些属性值,将其放入全局xml文件中,在AppDelegate进行初始化

    全局xml文件 system.style 的格式类似这样:

    <?xml version="1.0" encoding="utf-8"?>
    <styles>
        <style name="buttonAttrStyle">
            <attr name="bgColor">black</attr>
            <attr name="color">white</attr>
            <attr name="borderRadius">4</attr>
            <attr name="underlayColor">darkGray</attr>
            <attr name="shadowColor">red</attr>
            <attr name="shadowOffset">5/5</attr>
            <attr name="shadowOpacity">0.2</attr>
            <attr name="shadowRadius">3</attr>
        </style >
        <style name="buttonLayoutStyle">
            <attr name="height">44</attr>
            <attr name="width">150</attr>
            <attr name="alignItems">center</attr>
            <attr name="justifyContent">center</attr>
            <attr name="margin">20</attr>
        </style>
    </styles>
    

    导入系统样式文件

    NSString *path = [[NSBundle mainBundle]pathForResource:@"system" ofType:@"style"];
    [[FlexStyleMgr instance] loadClassStyle:path];
    

    使用:

    <UILabel attr="@:system/buttonAttrStyle" layout="@:system/buttonLayoutStyle" />
    
    • FlexLib支持运行时更新界面,具体的配置方式那你可以看这里

    • FlexLib支持Cell高度自动计算,并且适配iPhone X等机型,实际开发中自定义UITableViewCell需要继承FlexBaseTableCell,自定义UICollectionViewCell需要继承FlexCollectionCell

    2.FlexXmlBaseView、FlexFrameView、FlexCustomBaseView 的使用

    在使用xml进行布局时,不可避免的要用到自定义视图,如果自定义视图也想要用xml进行布局,此时需要继承FlexXmlBaseViewFlexFrameViewFlexCustomBaseView这三种视图中的一种。

    (1)自定义视图使用xml布局

    • 继承FlexXmlBaseView的视图:能在xml文件中使用,可以通过initWithRootView方式创建,但不能通过initWithFrame创建,也不能能直接设置frame,优点是更加轻量级,不会增加额外的视图层级.

    • 继承FlexFrameView的视图:可以直接设置frame,但是不能用在xml文件中。例如

    FlexFrameView *frameView = [[FlexFrameView alloc] initWithFlex:@"CustomFrameView" Frame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 0) Owner:self];
    frameView.flexibleHeight = YES;//设置高度自适应
    [_scrollView addSubview:frameView];
    

    CustomFrameView.xml是这个视图对应的xml布局文件

    • 继承FlexCustomBaseView的视图:既可以用在xml中,也可以像传统的UIView派生类那样使用initWithFrame创建,缺点是会额外的增加多余的视图层级.

    注意:继承FlexCustomBaseViewFlexFrameView的视图必须要设置以下两个属性

    //宽和高是否可变?缺省值均为NO
    @property(nonatomic,assign) BOOL flexibleWidth;
    @property(nonatomic,assign) BOOL flexibleHeight;
    

    (2)自定义视图不使用xml布局,但是也想用在xml文件中

    此时我们的自定义视图需要满足以下两个条件就可以用于xml文件中:

    • 所有的初始化必须在init方法中完成。任何其他的init函数,比如initWith…不会被调用。
    • 你可以用FLEXSET宏扩展视图属性,然后你可以在xml文件中设置属性。

    直接在父视图中使用

    <?xml version="1.0" encoding="utf-8"?>
    <UIView layout="flex:1,alignItems:center" attr="bgColor:white">
      <!-- 无xml对应的,自定义View 这么使用 -->
      <ComplateCustomView layout="width:100%,height:80"/>
    </UIView>
    
    

    3.其他设置

    • 缩放因子
      在进行页面布局时,如果想让不同尺寸的屏幕共用一套设计,随着屏幕尺寸的变化,页面控件的大小随之缩放,这时候会用到缩放因子。设置缩放因子:
     // 设置缩放因子,使用方法 在xml 布局中 *16 ==> 16*factor + 1
     float factor = [UIScreen mainScreen].bounds.size.width/375;
     FlexSetScale(factor, 1);
    

    在布局xml中使用,数字前面加上*

    <UILabel attr="fontSize: *16"/>
    

    这表示:Label的fontSize为16*factor + 1

    • 在属性中使用表达式
      在布局属性和视图属性中添加表达式,属性名前要加$,ScreenWidth是系统预定义的宏,你也可以用自定义的宏。目前支持的运算符+, -, *, /, (, ),
    <UIView layout="$width:ScreenWidth*0.6,height:50,alignItems:center,justifyContent:center" attr="bgColor:#e5e5e5,borderRadius:6">
         <UILabel attr="@:system/buttonText,text:表达式计算,屏幕宽度的60%"/>
    </UIView>
    
    • FlexTextView
      它是另外一个系统提供的类,能够自动根据输入的文字调整其高度,且保证其高度不会超出最小(minHeight)和最大高度(maxHeight)。
     <FlexTextView layout="flex:1,minHeight:40,maxHeight:95" attr="borderColor:red,borderWidth:1,borderRadius:4,fontSize:18,color:darkGray,text:这是一个能自动根据字数调整高度的文本输入框,placeholder:我是占位,placeholderColor:red"/>
    

    四. 总结

    FlexLib 可能对有前端开发经验的同学比较友好,对原生开发同学而言,学习一下他的语法也没坏处。在日常开发中,我们可以有选择的使用这个布局,熟悉了这个布局后,会极大的提升我们页面布局效率,从而让我们将精力集中到更加核心的功能上。

    参考:
    https://github.com/zhenglibao/FlexLib

    相关文章

      网友评论

        本文标题:iOS中的Flex布局-FlexLib的使用

        本文链接:https://www.haomeiwen.com/subject/mzpvdrtx.html