27
2017
09

搭积木布局

**

搭积木布局

**

前言

为了防止在一处中积累过多的代码,我们常常使用类似mvp,mvc等设计模式,来把不同职责的代码分开。而我们的blockLayout(积木布局)也是如此,只是区分的粒度不一样。

mvp按“视图-模型-展现”分三层,blockLayout按功能来分N层,有多少功能就可以有多少层

如何使用

整个框架简单来说就两个东西, BlockLayout 和 BlockView, 其他的都是为了更好的使用它们而服务的

BlockLayout是一个ViewGroup, 作为容器,它管理了所有的BlockView(积木),使用时只需要把BlockLayout加入xml布局即可。
<com.lemon.faceu.block.BlockLayout
         android:id="@+id/blockLayout"
         android:layout_width="match_parent"
         android:layout_height="match_parent"/>
有了容器后,我们还需要有积木BlockView,需要注意的是BlockView不是一个View,并没有继承View类,只不过BlockView的职责之一是需要提供布局,给BlockLayout加载并展示

BlockLayout可以理解为父,它管理着所有的孩子BlockView,BlockView只有被关联到BlockLayout才会有意义。 如何关联,最容易想到的无外乎BlockLayout提供一个接口来把BlockView集合设置进去,实际上BlockLayout也确实提供了addBlock方法,用于添加blockView
mBlockLayout = $(mRootView, R.id.blockLayout);
mFakeBlock = new CameraFakeBlockView();
mBlockLayout.addBlock(0, mFakeBlock);

BlockInject注解

此外,还提供一种更灵活的关联方式,使用BlockInject注解给BlockView添加关联信息,BlockLayout在初始化时会主动去寻找它们
@BlockInject(zOrder = 1, manager = "camera")
public class CameraTypeBlockView extends IBaseBlockView {
}
mBlockLayout = $(mRootView, R.id.blockLayout);        
// inject调用后,所有注解时表明manager为camara的积木都会加载进来
mBlockLayout.inject("camera", this);

依赖注入

通过BlockInject关联父子时,BlockLayout寻找到BlcokView后,是使用BlockView的默认无参构造函数生成对象的,如果BlockView需要一些依赖,比如activity或者fragment,就可以用BlockContext和BlockContextProvider注解,来进行注入依赖
@BlockInject(zOrder = 1, manager = "manager")
public class CameraTypeBlockView extends IBaseBlockView {
    // 告诉BlockLayout父亲,我需要Activity
    @BlockContext
    public Activity mActivity;
}

public class MyFragment extends Fragment {
    // 告诉BlockLayout,我有Activity可以提供
     @BlockContextProvider
    public Activity getActivityForBlock() {
        return getActivity();
    }

    public void initView(View mRootView) {
        mBlockLayout = $(mRootView, R.id.blockLayout);        
        // inject时,通过第二个参数provider告诉BlockLayout
        // 能提供依赖的对象, blockLayout会查询该provider注解
        // 了BlockContextProvider的方法,以便为注解了BlockContext
        // 的孩子提供依赖
        mBlockLayout.inject("camera", this);
    }
}

布局共享

最理想的情况是每个BlockView的layout没有互相作用,这样BlockView提供layoutid, BlockLayout负责按zOrder顺序一层层往上搭即可,实际上一个BlockView的的布局会受到其他BlockView的影响, 比如 相册导入按钮和多格按钮 一起居中显示,而相册导入和多格在不同的层,如果相册导入层和多格层还是各自提供layoutid,那么必然要有一个新的东西站出来,协调他们的UI, 这个过程会比较复杂,为了简化多个BlockView的布局有相互作用的问题, BlockLayout支持不同的BlockView返回相同的layoutId, 这样一来多个BlockView就可以做到布局共享,所有的相互作用就在一个布局文件中被定义了。

当然只是布局被共享了,不同blockView的逻辑还是分开的,结构依然清晰

小建议:不管是多小的功能,能单独成BlockView就单独出来,不用觉得这个功能点小,就并入已有的不相干的BlockView, 小而独立反而更好的实现抽插

触屏管理

想象以下场景:有两个BlockView,一个BlockView监听点击事件,而另外一个BlockView监听左右滑事件

我们知道如果某个View接受了ACTION_DOWN事件后,正常情况下后面一系列的ACTION_MOVE事件会一直发往该View,同理一个BlockView的布局接受了ACTION_DOWN事件后,其他兄弟BlockView的布局没有机会收到Touch事件了, 为此BlockLayout提供给BlockView拦截机制,即使某个BlockView的布局已经接受ACTION_DOWN,其他的BlockView还是可以拦截Touch事件,BlockView只需要重写onTouchEvent,如果该方法返回为true,后续touch事件就会被拦截

所以,我们可以重写这两个BlockView的onTouchEvent,分别判断是否点击和是否左右滑了,在任何一个的onTouchEvent中没有返回true之前,双方都有机会获得touch事件

能力导出与事件传递

BlockLayout在加载BlockView会通过BlockView的getAbilities查询它提供的能力,以便Blockview通过BlockLayout的queryAbility,查询是否有特定能力被提供了

此外Blockview也可以通过BlockLayout的broadst发送消息,BlockLayout会负责广播给其他blockview
上一篇:android开发笔记之APK反编译(一)ClassyShark 下一篇:React Native 第十三天