多屏幕设计——实现适应性的UI布局 .

来源:互联网 发布:寂静岭pt 知乎 编辑:程序博客网 时间:2024/05/20 21:18

根据您的应用程序目前呈现的布局,用户界面​​布局可能会有所不同。如果您的应用程序是在双窗格模式,单击在左窗格中的项目将只显示在右侧窗格中的内容;如果它是在单窗格模式,内容上应该显示自己的布局中(在不同的activity)。

确定当前布局

由于实现每个布局将有一点不同,需要做的第一件事情就是确定什么样的用户目前观看布局。可能想知道用户是在“单一窗口”模式或“双窗格”模式。通过查询一个给定的视图存在并可见来判断:

[html] view plaincopyprint?
  1. public class NewsReaderActivity extends FragmentActivity {  
  2.     boolean mIsDualPane;  
  3.   
  4.     @Override  
  5.     public void onCreate(Bundle savedInstanceState) {  
  6.         super.onCreate(savedInstanceState);  
  7.         setContentView(R.layout.main_layout);  
  8.   
  9.         View articleView = findViewById(R.id.article);  
  10.         mIsDualPane = articleView != null &&   
  11.                         articleView.getVisibility() == View.VISIBLE;  
  12.     }  
  13. }  

注意,此代码查询“article”窗格中是否可用或不可,这比为一个特定的布局查询的硬编码更为灵活。

如何适应不同存在的组件的另一个例子是,在组件执行操作之前检查它是否可用。例如,在News Reader示例应用程序,有一个打开菜单的按钮,但该按钮只存在Android 3.0以上的版本上运行时(因为它的功能是 ActionBar API级别11提供) 。因此,要为这个按钮添加事件监听器,你可以做:

[html] view plaincopyprint?
  1. Button catButton = (Button) findViewById(R.id.categorybutton);  
  2. OnClickListener listener = /* create your listener here */;  
  3. if (catButton != null) {  
  4.     catButton.setOnClickListener(listener);  
  5. }  

根据当前布局做出应对

有些行为可能有不同的结果,这取决于当前的布局。例如,在News Reader例子,点击标题列表中的标题可以打开的相应文章,如果UI在双窗格模式,则文章是显示在右边的窗格;如果UI是单窗格模式,文章则会显示在开启的另一个activity:

[html] view plaincopyprint?
  1. @Override  
  2. public void onHeadlineSelected(int index) {  
  3.     mArtIndex = index;  
  4.     if (mIsDualPane) {  
  5.         /* display article on the right pane */  
  6.         mArticleFragment.displayArticle(mCurrentCat.getArticle(index));  
  7.     } else {  
  8.         /* start a separate activity */  
  9.         Intent intent = new Intent(this, ArticleActivity.class);  
  10.         intent.putExtra("catIndex", mCatIndex);  
  11.         intent.putExtra("artIndex", index);  
  12.         startActivity(intent);  
  13.     }  
  14. }  
同样,如果应用是双窗口模式,它将会用Action bar 作为导航,而如果它是单窗口模式,则会用Spinner组件作为导航。因此,代码应该做适当的检查:

[html] view plaincopyprint?
  1. final String CATEGORIES[] = { "Top Stories", "Politics", "Economy", "Technology" };  
  2.   
  3. public void onCreate(Bundle savedInstanceState) {  
  4.     ....  
  5.     if (mIsDualPane) {  
  6.         /* use tabs for navigation */  
  7.         actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_TABS);  
  8.         int i;  
  9.         for (i = 0; i < CATEGORIES.length; i++) {  
  10.             actionBar.addTab(actionBar.newTab().setText(  
  11.                 CATEGORIES[i]).setTabListener(handler));  
  12.         }  
  13.         actionBar.setSelectedNavigationItem(selTab);  
  14.     }  
  15.     else {  
  16.         /* use list navigation (spinner) */  
  17.         actionBar.setNavigationMode(android.app.ActionBar.NAVIGATION_MODE_LIST);  
  18.         SpinnerAdapter adap = new ArrayAdapter(this,   
  19.                 R.layout.headline_item, CATEGORIES);  
  20.         actionBar.setListNavigationCallbacks(adap, handler);  
  21.     }  
  22. }  

在别的Activity中重用Fragment

在多个屏幕设计中一个经常性的模式是接口部分,实现接口作为屏幕配置上一个窗格和其他配置上一个单独的Activity。例如,在News Reader例子,新闻文章文字是在大屏幕的右侧窗格中,但在较小的屏幕上是一个单独的activity。

在这种情况下,你通常能避免几个activity重复使用相同的代码通过复用片段的子类。例如,ArticleFragment 被用在双窗格布局中

[html] view plaincopyprint?
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     android:layout_width="fill_parent"  
  3.     android:layout_height="fill_parent"  
  4.     android:orientation="horizontal">  
  5.     <fragment android:id="@+id/headlines"  
  6.               android:layout_height="fill_parent"  
  7.               android:name="com.example.android.newsreader.HeadlinesFragment"  
  8.               android:layout_width="400dp"  
  9.               android:layout_marginRight="10dp"/>  
  10.     <fragment android:id="@+id/article"  
  11.               android:layout_height="fill_parent"  
  12.               android:name="com.example.android.newsreader.ArticleFragment"  
  13.               android:layout_width="fill_parent" />  
  14. </LinearLayout>  
并且ArticleFragment 也可以被重用在小屏幕的activity的布局中ArticleActivity,这个activity没有布局文件

[html] view plaincopyprint?
  1. ArticleFragment frag = new ArticleFragment();  
  2. getSupportFragmentManager().beginTransaction().add(android.R.id.content, frag).commit();  

 当然,这个和在xml布局文件中描述fragment的效果是一样的。在这个实例中xml布局文件不是必须的,因为文章fragment是ArticleActivity唯一的组件。

设计Fragment时,要牢记的一个很重要的一点是不要创建一个强耦合到一个特定的activity。通常可以定义一个接口,接口抽象出所有需要与它的宿主activity交互的方法,然后由宿主activity实现该接口:

例如,News Reader应用程序的HeadlinesFragment正是:

[html] view plaincopyprint?
  1. public class HeadlinesFragment extends ListFragment {  
  2.     ...  
  3.     OnHeadlineSelectedListener mHeadlineSelectedListener = null;  
  4.   
  5.     /* Must be implemented by host activity */  
  6.     public interface OnHeadlineSelectedListener {  
  7.         public void onHeadlineSelected(int index);  
  8.     }  
  9.     ...  
  10.   
  11.     public void setOnHeadlineSelectedListener(OnHeadlineSelectedListener listener) {  
  12.         mHeadlineSelectedListener = listener;  
  13.     }  
  14. }  

当用户选中标题时,fragment通知宿主activity指定的监听器(不是硬编码特定的通知):

[html] view plaincopyprint?
  1. public class HeadlinesFragment extends ListFragment {  
  2.     ...  
  3.     @Override  
  4.     public void onItemClick(AdapterView<?> parent,   
  5.                             View view, int position, long id) {  
  6.         if (null != mHeadlineSelectedListener) {  
  7.             mHeadlineSelectedListener.onHeadlineSelected(position);  
  8.         }  
  9.     }  
  10.     ...  
  11. }  
这项技术在开发指导中Supporting Tablets and Handsets.文章有进一步的讨论。

处理屏幕配置更改

如果使用特定的活动实现界面的特定部分,必须要记住,它可能是做些必要的改变来适应某些配置更改(如旋转变化),以保持你界面保持一致。

例如,一个典型的7“运行Android 3.0或更高的平板上,News Reader例子中使用一个单独的activity以显示新闻文章在竖屏模式下运行时,但在横向模式时使用两个窗格的布局。

这意味着,当用户在竖屏模式下,阅览文章在整个activity屏幕上。需要检测的屏幕方向改变成横屏并且适当做出反应,通过结束activity,并返回到这样的内容可以显示在两个窗格的布局:

[html] view plaincopyprint?
  1. public class ArticleActivity extends FragmentActivity {  
  2.     int mCatIndex, mArtIndex;  
  3.   
  4.     @Override  
  5.     protected void onCreate(Bundle savedInstanceState) {  
  6.         super.onCreate(savedInstanceState);  
  7.         mCatIndex = getIntent().getExtras().getInt("catIndex", 0);  
  8.         mArtIndex = getIntent().getExtras().getInt("artIndex", 0);  
  9.   
  10.         // If should be in two-pane mode, finish to return to main activity  
  11.         if (getResources().getBoolean(R.bool.has_two_panes)) {  
  12.             finish();  
  13.             return;  
  14.         }  
  15.         ...  
  16. }  



译自:http://developer.android.com/training/multiscreen/adaptui.html

原创粉丝点击