代替fragment的轻量级解耦UI的类:UIBlock
UIBlock
代替fragment的轻量级解耦UI的类
添加依赖
1.在项目外层的build.gradle中添加JitPack仓库
repositories { maven { url "https://jitpack.io" } }
2.在用到的项目中添加依赖
dependencies { compile 'com.github.tianzhijiexian:UIBlock:1.0' }
准备工作
在项目中建立一个BaseActivity,让它实现ContainUIBlockActivity接口:
public class BaseActivity extends AppCompatActivity implements ContainUIBlockActivity{ private UIBlockManager mUIBlockManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mUIBlockManager = new UIBlockManager(this); } @Override public UIBlockManager getUIBlockManager() { return mUIBlockManager; } @Override public void onBackPressed() { boolean handled = mUIBlockManager.onBackPressed(); if (!handled) { super.onBackPressed(); } } @Override public void onDestroy() { super.onDestroy(); mUIBlockManager.onDestroy(); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); mUIBlockManager.onActivityResult(requestCode, resultCode, data); } }
可以看到这里面就是在activity的回调时调用mUIBlockManager的对应的方法。这里其实还有一个思路就是用registerActivityLifecycleCallbacks这个方法,但是因为application只能设置一个监听,如果开发者在自己的应用中也用了这个回调,我这里就监听不到了。其次就是hook,但这里可能要引入一个框架,故没尝试。因此,还是采用比较搓的手动在生命周期中调用相应方法的办法。
使用情形
1. 简单划分UI逻辑,降低Activity复杂度
我们之前用fragment来拆分UI的逻辑的办法来提升程序可读性,降低activity的复杂度。但因此带来的是使用fragment出现的各种奇葩问题和fragment的复杂度。因此,我利用UIBlock实现了类似的功能,但复杂度远远降低。
比如我这里只想把顶部的这个linearLayout的逻辑独立出来,但不想要独立写一个xml布局文件。要完成这个功能,我只需要建立一个UIBlock:
public class DemoTopUIBlock extends UIBlock{ @Override public int getRootViewId() { return R.id.top_ub; } TextView mTopTv; @Override protected void bindViews() { mTopTv = getView(R.id.top_tv); } @Override protected void setViews() { String content = mTopTv.getText().toString(); mTopTv.setText(content + " :)"); } }
接着,在activity中getUIBlockManager().add(new DemoTopUIBlock()),这样就使得这个linearLayout的逻辑转交给了UIBlock。
2. 复用有相似界面和相似逻辑的UI
复用UI是很常见的需求,但这里我的意见是:多复用UI组件,而不是复用activity。因为如果activity被多次复用,可能会因为后面设计师的界面分化,造成维护的难度。
题外话说完了,来看看如何利用UIBlock做这样的复用吧。这样的复用很简单,直接用现成的<include/>标签即可,毫无技术性。
来看看被include的布局长啥样(这里用到了tools:showIn这个小技巧):
然后建立相应的UIBlock:
public class DemoBottomUIBlock extends UIBlock{ @Override public int getRootViewId() { return R.id.bottom_ub; } private EditText mBottomEt; private Button mBottomBtn; @Override protected void bindViews() { mBottomEt = getView(R.id.bottom_et); mBottomBtn = getView(R.id.bottom_btn); } @Override protected void setViews() { mBottomBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { getActivity(DemoActivity.class).changeText(); } }); } public void onTextChangeCompleted(@NonNull String text) { mBottomEt.setText(text); } }
最后,在activity中引入这部分逻辑:getUIBlockManager().add(new DemoBottomUIBlock())
3. 嵌套使用UIBlock
之前豪哥(大神)提出过这样的需求,activity中套fragment,这个fragment中又套了一个fragment,这种嵌套的问题在fragment的世界中真是令人头疼。现在我们看看如何用UIBlock来简单解决这个问题。
上面的代码中,LinearLayout中嵌套了一个LinearLayout,我希望外面的LinearLayout被一个UIBlock控制,内部的LinearLayout被另一个UIBlock控制,形成嵌套。废话不说,上外层的代码:
public class DemoMiddleUIBlock extends UIBlock{ @Override public int getRootViewId() { return R.id.middle_ub; } @Override protected void bindViews() { getActivity(BaseActivity.class).getUIBlockManager().add(new DemoInnerUIBlock()); } @Override protected void setViews() { getRootView().setBackgroundColor(0xff65a8b7); } }
这里重要的一个方法是:getActivity(),可以通过这个方法得到activity的对象,然后直接调用activity的getUIBlockManager()来引入内层嵌套的UIBlock就行了。至于DemoInnerUIBlock的代码就不说了,和之前的类似。最后,不要忘记了在activity把这个UIBLock的代码引入进来getUIBlockManager().add(new DemoMiddleUIBlock());。