7.5.4 交互界面的适配

从Android 3.0版本开始,Android对平板设备的支持更为良好。其中,引入动作栏和界面片段就是为了能够更方便地为平板设备和手机定制更符合其交互方式的界面。

在Android 4.0版本中,所有的系统应用都采用了该方式来定制页面,使得在任何移动设备上都可以使用这些系统应用,获得最好的体验。以Android原生的联系人应用为例,如图7-21,联系人在普通手机上呈现出单栏的界面样式;而在大屏幕的平板设备上,则会出现双栏的交互界面,充分利用屏幕尺寸来提供更多的联系人信息。

7.5.4 交互界面的适配 - 图1

图 7-21 不同尺寸设备上联系人应用呈现不同的模式

实现这样的交互界面,首要的一点是使用界面片段重新定义界面结构,将不同功能的交互界面拆分到独立的界面片段中。在联系人应用中,联系人列表、收藏的联系人列表、联系人分组的列表都单独定义了界面片段,联系人详情、联系人分组详情也被分到了各自的界面片段中。联系人界面组件会根据不同的屏幕尺寸,选择不同的界面片段组装在一起构成整个交互界面。

联系人界面组件默认的样式非常简单,仅包含一些容器控件:


<?xml version="1.0"encoding="utf-8"?>

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:id="@+id/list_container"

android:layout_width="match_parent"

android:layout_height="match_parent">

<!—界面的主要容器控件,使用4.0才支持的ViewPager,该控件可以按照一定特效切换界面片段—>

<android.support.v4.view.ViewPager

android:id="@+id/tab_pager"

android:layout_height="match_parent"

android:layout_width="match_parent"

/>

<!—界面为空时需要显示的内容—>

<FrameLayout android:id="@+id/contacts_unavailable_view"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:visibility="gone">

<FrameLayout

android:id="@+id/contacts_unavailable_container"

android:layout_height="match_parent"

android:layout_width="match_parent"/>

</FrameLayout>

</FrameLayout>


在运行时,相关的界面片段会以动态拼接的方式添加进去,以单栏形态呈现,适配普通的手机设备。此外,联系人应用为大屏幕平板设备重新定义了界面样式,它采用静态拼接的模式,用界面片段定义了双栏结构的交互界面[1]


<?xml version="1.0"encoding="utf-8"?>

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"

android:layout_height="match_parent">

<!—水平排列的控件,构成了双栏的样式—>

<LinearLayout android:id="@+id/main_view"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="horizontal">

<!—左侧的各个列表控件—>

<LinearLayout android:id="@+id/browse_view"

android:layout_width="0dip"

android:layout_height="match_parent"

android:layout_weight="1"

android:orientation="vertical">

<!—全部联系人列表的界面片段—>

<fragment android:id="@+id/all_fragment"

class="com.android.contacts.list.DefaultContactBrowseListFragment"

android:layout_height="0dip"

android:layout_width="match_parent"

android:layout_weight="1"/>

<!—其他更多列表界面片段—>

</LinearLayout>

<!—右侧的各个详情界面片段,用自定义的动画容器控件—>

<view android:id="@+id/details_view"

class="com.android.contacts.widget.TransitionAnimationView"

android:layout_width="0dip"

android:layout_height="match_parent"

android:layout_weight="1"

…>

<!—联系人分组详情的界面片段—>

<fragment android:id="@+id/group_detail_fragment"

class="com.android.contacts.group.GroupDetailFragment"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:visibility="gone"/>

<!—更多联系人详情的界面片段—>

</view>

</LinearLayout>

</FrameLayout>


有了基础的界面样式,还需要通过代码来动态地处理界面的构造和切换,最终实现适配不同尺寸屏幕的界面:


//先设置界面样式

setContentView(R.layout.people_activity);

//判断是否需要双栏显示,这也是通过资源适配来实现的,第8章将详细介绍

boolean isUsingTwoPanes=IsUsingTwoPanes(this);

//根据不同的界面样式来构造交互界面

FragmentManager fragmentManager=getFragmentManager();

FragmentTransaction transaction=

fragmentManager.beginTransaction();

if(isUsingTwoPanes){

//如果是双栏,那么所有的界面片段都是预先定义好的

mAllFragment=getFragment(R.id.all_fragment);

mGroupsFragment=getFragment(R.id.groups_fragment);

}else{

//如果是单栏,那么所有的界面片段都需要动态地进行构造

mAllFragment=(DefaultContactBrowseListFragment)

fragmentManager.findFragmentByTag(ALL_TAG);

mGroupsFragment=(GroupBrowseListFragment)

fragmentManager.findFragmentByTag(GROUPS_TAG);

if(mAllFragment==null){

mAllFragment=new DefaultContactBrowseListFragment();

mGroupsFragment=new GroupBrowseListFragment();

transaction.add(R.id.tab_pager, mAllFragment, ALL_TAG);

transaction.add(R.id.tab_pager, mGroupsFragment, GROUPS_TAG);

}

}

//构造完成后,需要控制各个界面片段的显隐性,保证界面处于正确状态

//在初始时,隐藏掉所有界面组件,直到相关事件触发后再刷新

transaction.hide(mAllFragment);

transaction.hide(mGroupsFragment);

if(isUsingTwoPanes){

//双栏模式下,右侧的详情界面片段也是静态定义的,也需要先行隐藏

mGroupDetailFragment=

getFragment(R.id.group_detail_fragment);

if(mContactDetailFragment!=null){

transaction.hide(mContactDetailFragment);

}

transaction.hide(mGroupDetailFragment);

}

//提交界面片段的切换

transaction.commitAllowingStateLoss();

fragmentManager.executePendingTransactions();


[1]如何适配不同的屏幕尺寸,定义对应的界面样式资源,可以参见第8章的相关内容。