实现自适应的UI界面
2015-08-29 15:59
447 查看
根据 app 当前的所显示的 layout,UI 界面往往会有差异。如在 dual-pane 模式下,点击左侧的 item,会直接在右侧显示相应的内容;但是如果是在 single-pane 模式下,那么内容将会被显示到另外的界面上(通常会显示在另外的 activity 上)。
一、那么如果决定当前要采用怎样的 layout 呢?
也许你需要的所有 layout 之间都是有差异的,但是不管你要实现哪种 layout,你首先要考虑的是用户当前支持哪种形式的 layout。如你必须知道用户是支持的是 single-pane 还是 dual-pane 模式,这你可以通过检测特定 view 的可见性来做到:
上面的这段代码通过检测 "article" pane 的可见性来判断用户是否支持 dual-pane。
此外,在你要对某种组件执行相关操作的时候,你还需要判断它是否存在。如在 News Reader app 中,如果系统版本是 Android 3.0 以下的版本,那么它将通过一个按钮来打开下拉菜单,而在 Android 3.0 以后,打开下拉菜单的功能可由 ActionBar 来实现。所以在给 button 添加 listener 的时候,你可以这样做:
二、根据当前的 Layout 处理用户操作
根据 layout 的不同,对于同一事件的响应方式可能是不同的。如大 News Reader app 中,点击左侧的 headline 列表时,如果当前设备支持 dual mode,那么相应 item 的内容将会被显示在右侧。而如果是 single mode,那么其内容将会在新的 activity 中显示。
类似的,如果设备支持 dual-pane,那么 action bar 就可以用 tabs 来实现 navigation,否则 action bar 就应该通过 spinner widget 来实现 navigation。所以你要检测当前设备适合采用哪种方式:
三、在其它 activity 中重用 Fragments
在不同 configurations 的屏幕中,界面的可重用性是非常重要的。在 News Reader app 中,如果设备的是大屏幕的,那么它就可以直接在右侧显示 item 的内容,否则它就会通过启动另外的 activity 来显示。像这种情况,你可以通过在 activity 中重用 Fragment 来避免写重复的代码。下面这段代码是用于在大屏幕设备上布局的
而如果换到小屏幕设备,你就可以在新的 activity(ArticleActivity) 中重用已经写好的 Fragment
显然,这和直接在 xml 中声明 fragment 的效果是一样的,但是这样写你就不需要在 xml 中声明了,因为这个 fragment 就是该 activity 的所需要的所有内容了。
在设计 fragment 的时候,一个非常重要的原则是:不要让任何 fragment 和 activity 有大多的耦合。如果 activity 需要和 fragment 交互,那么你可以在 fragment 中声明接口,就像在 News Reader app 中的实现一样:首先在 HeadlinesFragment 中声明接口
这样当用户点击 headline 的时候,fragment 就可以通知通过 host activity 传递给它的 listener 回调相应的响应方法
四、处理 Screen Configuration Changes 事件
如果你在用不同的 activity 来实现不同的界面,那么你就得处理好 configuration changes 事件,以保持界面的一致性。如在系统版本大于等 Android 3.0 的 tablet 上,在竖屏的时候, article 会在新的 activity 中显示,而切换到横屏之后,左侧就显示文章列表,而右侧显示文章内容。所以你要检测当前设备屏幕是处于 portrait
还是 landscape 模式,然后做相应处理。如用户从 portrait 切换到 landscape,那么就应该把 content activity finish 掉,然后回到 main activity(因为此时 main activity 已经可以显示 content 了)
下载 News Reader 源码
一、那么如果决定当前要采用怎样的 layout 呢?
也许你需要的所有 layout 之间都是有差异的,但是不管你要实现哪种 layout,你首先要考虑的是用户当前支持哪种形式的 layout。如你必须知道用户是支持的是 single-pane 还是 dual-pane 模式,这你可以通过检测特定 view 的可见性来做到:
public class NewsReaderActivity extends FragmentActivity{ boolean mIsDualPane; @Override publicvoid onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main_layout); View articleView = findViewById(R.id.article); mIsDualPane = articleView !=null&& articleView.getVisibility()==View.VISIBLE; } }
上面的这段代码通过检测 "article" pane 的可见性来判断用户是否支持 dual-pane。
此外,在你要对某种组件执行相关操作的时候,你还需要判断它是否存在。如在 News Reader app 中,如果系统版本是 Android 3.0 以下的版本,那么它将通过一个按钮来打开下拉菜单,而在 Android 3.0 以后,打开下拉菜单的功能可由 ActionBar 来实现。所以在给 button 添加 listener 的时候,你可以这样做:
Button catButton =(Button) findViewById(R.id.categorybutton); OnClickListener listener =/* create your listener here */; if(catButton !=null){ catButton.setOnClickListener(listener); }
二、根据当前的 Layout 处理用户操作
根据 layout 的不同,对于同一事件的响应方式可能是不同的。如大 News Reader app 中,点击左侧的 headline 列表时,如果当前设备支持 dual mode,那么相应 item 的内容将会被显示在右侧。而如果是 single mode,那么其内容将会在新的 activity 中显示。
@Override publicvoid onHeadlineSelected(int index){ mArtIndex = index; if(mIsDualPane){ /* display article on the right pane */ mArticleFragment.displayArticle(mCurrentCat.getArticle(index)); }else{ /* start a separate activity */ Intent intent =newIntent(this,ArticleActivity.class); intent.putExtra("catIndex", mCatIndex); intent.putExtra("artIndex", index); startActivity(intent); } }
类似的,如果设备支持 dual-pane,那么 action bar 就可以用 tabs 来实现 navigation,否则 action bar 就应该通过 spinner widget 来实现 navigation。所以你要检测当前设备适合采用哪种方式:
finalString CATEGORIES[]={"Top Stories","Politics","Economy","Technology"}; publicvoid onCreate(Bundle savedInstanceState){ .... if(mIsDualPane){ /* use tabs for navigation */ actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_TABS); int i; for(i =0; i < CATEGORIES.length; i++){ actionBar.addTab(actionBar.newTab().setText( CATEGORIES[i]).setTabListener(handler)); } actionBar.setSelectedNavigationItem(selTab); } else{ /* use list navigation (spinner) */ actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_LIST); SpinnerAdapter adap =newArrayAdapter(this, R.layout.headline_item, CATEGORIES); actionBar.setListNavigationCallbacks(adap, handler); } }
三、在其它 activity 中重用 Fragments
在不同 configurations 的屏幕中,界面的可重用性是非常重要的。在 News Reader app 中,如果设备的是大屏幕的,那么它就可以直接在右侧显示 item 的内容,否则它就会通过启动另外的 activity 来显示。像这种情况,你可以通过在 activity 中重用 Fragment 来避免写重复的代码。下面这段代码是用于在大屏幕设备上布局的
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal"> <fragment android:id="@+id/headlines" android:layout_height="fill_parent" android:name="com.example.android.newsreader.HeadlinesFragment" android:layout_width="400dp" android:layout_marginRight="10dp"/> <fragment android:id="@+id/article" android:layout_height="fill_parent" android:name="com.example.android.newsreader.ArticleFragment" android:layout_width="fill_parent"/> </LinearLayout>
而如果换到小屏幕设备,你就可以在新的 activity(ArticleActivity) 中重用已经写好的 Fragment
ArticleFragment frag =new ArticleFragment(); getSupportFragmentManager().beginTransaction().add(android.R.id.content, frag).commit();
显然,这和直接在 xml 中声明 fragment 的效果是一样的,但是这样写你就不需要在 xml 中声明了,因为这个 fragment 就是该 activity 的所需要的所有内容了。
在设计 fragment 的时候,一个非常重要的原则是:不要让任何 fragment 和 activity 有大多的耦合。如果 activity 需要和 fragment 交互,那么你可以在 fragment 中声明接口,就像在 News Reader app 中的实现一样:首先在 HeadlinesFragment 中声明接口
public class HeadlinesFragment extends ListFragment{ ... OnHeadlineSelectedListener mHeadlineSelectedListener = null; /* Must be implemented by host activity */ public interface OnHeadlineSelectedListener{ public void onHeadlineSelected(int index); } ... public void setOnHeadlineSelectedListener(OnHeadlineSelectedListener listener){ mHeadlineSelectedListener = listener; } }
这样当用户点击 headline 的时候,fragment 就可以通知通过 host activity 传递给它的 listener 回调相应的响应方法
public class HeadlinesFragment extends ListFragment{ ... @Override publicvoid onItemClick(AdapterView<?> parent, View view,int position,long id){ if(null!= mHeadlineSelectedListener){ mHeadlineSelectedListener.onHeadlineSelected(position); } } ... }
四、处理 Screen Configuration Changes 事件
如果你在用不同的 activity 来实现不同的界面,那么你就得处理好 configuration changes 事件,以保持界面的一致性。如在系统版本大于等 Android 3.0 的 tablet 上,在竖屏的时候, article 会在新的 activity 中显示,而切换到横屏之后,左侧就显示文章列表,而右侧显示文章内容。所以你要检测当前设备屏幕是处于 portrait
还是 landscape 模式,然后做相应处理。如用户从 portrait 切换到 landscape,那么就应该把 content activity finish 掉,然后回到 main activity(因为此时 main activity 已经可以显示 content 了)
public class ArticleActivity extends FragmentActivity{ int mCatIndex, mArtIndex; @Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); mCatIndex = getIntent().getExtras().getInt("catIndex",0); mArtIndex = getIntent().getExtras().getInt("artIndex",0); // If should be in two-pane mode, finish to return to main activity if(getResources().getBoolean(R.bool.has_two_panes)){ finish(); return; } ... }
下载 News Reader 源码
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories