代码改变世界

OmniCommonUI框架

2015-04-05 18:00  飞沙0913  阅读(986)  评论(4编辑  收藏  举报

OmniCommonUI框架

 

OmniCommonUI框架在不修改原有布局文件的基础上去加载显示我们的公共UI,只需要一个属性的添加即可。很好的解决了开发过程中再次返工修改布局文件去添加公共UI的问题。公共UI即:loading加载页,无数据页,无网络页等。

在日常开发中,我们的XML布局文件除了展示视觉稿中的组件外,还需要添加,如Loading布局文件、无数据时的展示、无网络时的展示等等。这些都是我们在正常开发完成后,二次返工时做的。

这块工作一是没有技术的难度,二是非常繁琐,每个业务在开发完成后必须得二次返工。所以每个团队对于这些公共UI的加载都有自己的机制以使这块的工作在最大程度上减少。

通过分析调查,目前对于公共UI的显示处理分为以下几种情况:

1,在需要展示公共UI的组件外层嵌套一层FramLayout,然后这这个FrameLayout中再通include引用公共UI,如下图: 

我们正常的业务开发,只需要中间“正文内容”一个布局,最终却成了上述所出现的情况,必须是大多数布局文件中都得copy这么一大段。

2,自定义布局,通过自定义一个布局,在自定义的布局中自动加载各种公共UI,如下图: 

这种做法就比第一种做法好了很多,在布局外面只是多加了一层布局,改动看起来也不是很大。这也是目前使用的相对较多的一种做法。

3,一样是自定义布局。和上面不同的是,将所有有可能用到的布局都继承且重写相关方法,这些自定义的布局带有原布局的所有功能,并且附带有对公共UI的加载功能,如下图: 

  

在需要用到LinearLayout时,那就换用成自定义的CustomLinearLayout,那么相对布局,帧布局,ScrollView,ListView等等,所有的系统ViewGroup都得继承扩展一下,那开发起来就很苦逼了,因为每次都得复制这么长的包名与类名,自定义的组件在xml中使用时代码提示是不支持的。

 

大体就这三种情况,这些从某种意义上确实或多或少解轻了一些繁琐的事情 。它们都是一种可借鉴的封装思想,很难产品化的让其它团队去使用。那有没有产品化的解决方案呢?产品化的的解决方案就是无侵入、兼容、可插拔。一句话甚至一个属性就搞定,下面是我的研究结果。

大家看看我的解决方案: 

上面的布局是系统原生的组件,需要在这一块展示公共UI,现在只需要在该布局中添加几个额外的属性即可。

omni:omni_nonet="no_net"表示无网络时在这里显示no_net.xml布局;

omni:omni_nodata=“com.example.reshello.fragment.NodataFragment”表示无数据时在这里显示NodataFragment这个fragment;

在不改变原有布局的情况下,很轻松的添加对公共UI显示的支持。这些就是我们OmniCommonUI框架做的事情,在项目中只需引入一个几十K的JAR包即可实现上述功能。

在某些公共UI中有事件需要处理,因此这里也支持Fragment。如无数据时页面中的重试按钮的点击事件。 

下面是使用时的代码:

xml:

 1 <LinearLayout 
 2     xmlns:android="http://schemas.android.com/apk/res/android"
 3     xmlns:tools="http://schemas.android.com/tools"
 4     xmlns:omni="http://com.example.reshello/android"
 5     tools:ignore="all"
 6     android:layout_width="match_parent"
 7     android:layout_height="match_parent"
 8     android:orientation="vertical" >
 9     <LinearLayout android:layout_width="match_parent"
10         android:layout_height="80dp"
11         android:background="#ff0000">
12         <Button android:id="@+id/nodata_layout"
13             android:layout_width="wrap_content"
14             android:layout_height="match_parent"
15             android:padding="15dp"
16             android:text="显示无数据"/>
17         <Button android:id="@+id/nonet_layout"
18             android:layout_width="wrap_content"
19             android:layout_height="match_parent"
20             android:padding="15dp"
21             android:text="显示无网络"/>
22     </LinearLayout>
23     <LinearLayout android:layout_width="match_parent"
24         android:layout_height="match_parent"
25         android:layout_weight="1"
26         omni:omni_loading="loading"
27         omni:omni_nodata="com.example.reshello.fragment.NodataFragment"
28         omni:omni_nonet="no_net"
29         android:background="#990099"
30         android:id="@+id/layout_center"
31         android:layout_margin="20dp">
32         <TextView android:layout_width="match_parent"
33             android:layout_height="wrap_content"
34             android:text="【这里是正文内容】【这里是正文内容】【这里是正文内容】【这里是正文内容】【这里是正文内容】【这里是正文内容】【这里是正文内容】"/>
35     </LinearLayout>
36     <LinearLayout android:layout_width="match_parent"
37         android:layout_height="80dp"
38         android:background="#ff0000"
39         android:orientation="horizontal">
40         <Button android:id="@+id/loading_layout"
41             android:layout_width="wrap_content"
42             android:layout_height="match_parent"
43             android:padding="15dp"
44             android:text="显示Loading"/>
45         <Button android:id="@+id/stop_layout"
46             android:layout_width="wrap_content"
47             android:layout_height="match_parent"
48             android:padding="15dp"
49             android:text="关闭公共窗口"/>
50     </LinearLayout>
51 </LinearLayout>

 

JAVA代码:

 1 public class MainActivity extends FragmentActivity implements OnClickListener{
 2  
 3     private Button loading_layout;
 4     private Button stop_layout;
 5     private Button nodata_layout;
 6     private Button nonet_layout;
 7     private CommonUIService mCommonUIService;
 8     private LinearLayout layout_center;
 9     
10     @Override 
11     protected void onCreate(Bundle savedInstanceState) {
12         super.onCreate(savedInstanceState);
13 
14         mCommonUIService = OmniCommon.getInstance().getCommonUIService(this);
15         mCommonUIService.setContentView(R.layout.activity_main);
16         
17         layout_center = (LinearLayout) findViewById(R.id.layout_center);
18 
19         loading_layout = (Button) findViewById(R.id.loading_layout);
20         nodata_layout = (Button) findViewById(R.id.nodata_layout);
21         nonet_layout = (Button) findViewById(R.id.nonet_layout);
22         stop_layout = (Button) findViewById(R.id.stop_layout);
23         
24         loading_layout.setOnClickListener(this);
25         nodata_layout.setOnClickListener(this);
26         nonet_layout.setOnClickListener(this);
27         stop_layout.setOnClickListener(this);
28     }
29     @Override
30     public void onClick(View v) {
31         switch (v.getId()) {
32         case R.id.loading_layout://加载loading
33             mCommonUIService.show(R.id.layout_center, "omni_loading");
34             break;
35         case R.id.nodata_layout://加载无数据页面
36             mCommonUIService.show(R.id.layout_center, "omni_nodata");
37             break;
38         case R.id.nonet_layout://加载无网络页面
39             mCommonUIService.show(R.id.layout_center, "omni_nonet");
40             break;
41         case R.id.stop_layout:
42             mCommonUIService.dismiss(R.id.layout_center);
43             break;
44         }
45     }
46     
47     public void tryAgain(View v){
48         Toast.makeText(this, "正在重新加载 ,请稍候", 1000).show();;
49     }
50 }

 

OmniCommonUI框架使用说明如下:

一、Activity的onCreate初始化:

private CommonUIService mCommonUIService;

onCreate方法中添加:

mCommonUIService = OmniCommon.getInstance().getCommonUIService(this);

mCommonUIService.setContentView(R.layout.activity_main);

这两句取代:setContentView(R.layout.activity_main);

二、在XML中:

在需要用到公共UI(loading/无数据/无网络等)的xml的最外层布局添加:

xmlns:tools="http://schemas.android.com/tools"

xmlns:omni="http://com.example.reshello/android"

tools:ignore=“all"

其中xmlns:omni的全名空间为”http://包名/android”,包名为Manifest中注册的package。

三、在需要显示公共UI的组件上添加属性:

omni:omni_nodata="com.example.reshello.fragment.NodataFragment"

omni:omni_nonet=“no_net”

上面两句话表示在无数据时,页面这块加载NodataFragment,没有网络时,加载显示no_net.xml这个布局文件。

其中omni_nodata与omni_nonet这两个标签可以随便定义。只是必须以omni_开头即可。

四、在Activity中调用时:

1,显示某个属性对应的xml或者是fragment时:

mCommonUIService.show(R.id.layout_center“omni_nodata”);

调用上面这句,表示在R.id.layout_center这个组件上显示omni_nodata标签所对应的Fragment(第三步中定义好的fragment),这里的omni_nodata只需保证与第三步中定义的标签一致,但必须以omi_开头

2,隐藏某个view上面所有的公共UI时调用:

mCommonUIService.dismiss(R.id.layout_center);

表示隐藏R.id.layout_center上面所有的公共UI。

五、Fragment中事件的支持,Activity或者及父类必须继承FragmentActvity

如在无数据页面上有一个“重试”按钮,点击该按钮时需要调用Activity中的tryAgain()方法进行网络数据的重新加载。

1,在Fragment中添加:

click事件的支持:

@InjectRuntime(id=R.id.try_again, click="tryAgain")

private Button try_again;

try_again是重试按钮,在该定义上添加@InjectRuntime标签,第一个参数为按钮在xml中的id,第二个参数为Activity中的方法。

该标签首先会自动注入try_again,以后无需再findViewById.其次在点击该按钮时会自动调用Activity中的tryAgain方法(前提是Activity中得有该方法)。public void tryAgain(View v);//参数v为try_again的句柄

touch事件的支持:

@InjectRuntime(id=R.id.try_again, touch="touchAgain")

private Button try_again;

和click事件一样。touchAgain为Activity中的方法,方法格式为:

public void touchAgain(View v, MotionEvent event);

 

Demo下载