Android响应式界面开发要点
现在很多项目需要到达同一个Apk既可以在Phone上跑也尅在tablet上跑,即界面要适应不同尺寸和类型的需要而自动调整。这个即为响应式设计。在web开发商响应式设计已经是个常谈的内容了,而对于android开发,也有很多相关的资料,比如使用fragment。这里将一些要点总结下。
1. 使用relativelayout和wrap_content、match_parent标记
2. 建立多Layout文件
API > 3.2可以将小屏幕文件放到res/layout/main.xml,大屏幕文件放到res/layout-sw600dp/main.xlm
API<3.2同时提供对老版本的支持,将大屏幕布局文件放到res/layout-large/main.xml
或者用资源别名:
这样子可以直接用:
setContentView(R.layout.main)
参考:http://wen66.iteye.com/blog/1161375
3. 提供多套图片资源文件
4. 提供多套启动图标放置到mipmap文件夹(而不是drawable文件夹),以免在高分辨率的屏幕上出现launcher图表模糊的情况
5. 宿主activity在setcontentview后通过查询某个view(多pane中必须出现的view)是否存在而判定当前是多pane还是单pane状态:
public class NewsReaderActivity extends FragmentActivity { boolean mIsDualPane; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main_layout); View articleView = findViewById(R.id.article); mIsDualPane = articleView != null && articleView.getVisibility() == View.VISIBLE; } }
获得这个mIsDualPane变量的值后即可以在运行时决定是刷新second pane(多pane中原本需要在单pane中另起activity展示的那个fragment)还是起新的activity:
6. 操作内容的代码尽量放到fragment中,和activity解耦合,同时可以提供fragment的重用性:
比如,两个fragment单独写成类, 在多pane中,可以布局成:
单pane中可以将当前的fragment的替换:
7. 使用EventBus
通常多pane的设计中,比如Fragment A是个Headline,Fragement B是detail,那么B通常需要实现A的点击事件的接口,这样子的话,两个fragment就高耦合了,而且需要在Fragment A中编写一个interface,如果Fragment很多,情景更复杂些,就乱了。
这里可以使用EventBus这个框架,一个典型的发布者-订阅者模式。具体可以参考:
https://github.com/greenrobot/EventBus
使用方法大致如下:
a. 首先定义自己的Event,这里其实是随便写个类,例子中Headline需传一个点击时候的listview的position给Detail fragment,所以可以写个包装int类型的messageevent:
public class MessageEvent { public int positioin; public MessageEvent(int positioin) { this.positioin = positioin; } }
b. 在订阅者(即Detail fragment或者说fragment B)中,onstart和onstop要注册/解注册:
@Override public void onStart() { super.onStart();; EventBus.getDefault().register(this); } @Override public void onStart() { super.onStart(); setNewsCategory(0); EventBus.getDefault().register(this); }
c. 在订阅者(即Detail fragment或者说fragment B)中,写一个名字叫onEvent的函数,带回来的参数是MessageEvent类型,这个函数即被调用的方法,等待Headline传过来包装了position数据的MessageEvent对象
public void onEvent(MessageEvent event){ int index = event.positioin; // do something using index }
d. 在发布者(即Headline Fragment或者说Fragment A)中,在合适的地方执行post,这里即在listview被点击的回调中发送post:
@Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { EventBus.getDefault().post(new MessageEvent(position)); }
大功告成,这里可以发现两个fragment没有写任何的interface也没implements任何的接口,也不用实例化一个listenser并且setonlistener。
这里的原理大致是,EventBus在某个组件中注册的时候回记录下这个组件里面的onEvent函数,一个应用中可能有多个onEvent函数等待被调用,这里即通过onEvent函数的参数类型和个数来区别。
关于EventBus更多使用方法可以参考
https://github.com/greenrobot/EventBus/blob/master/HOWTO.md