Android最佳实践之UI

Posted gouphigh2

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android最佳实践之UI相关的知识,希望对你有一定的参考价值。

为多屏设计(一) - 支持多个屏幕尺寸

参考地址:http://developer.android.com/training/multiscreen/index.html
android UI设计提供了一个灵活的框架,允许应用程序为不同设备显示不同的布局,创建自定义UI部件,在App外部控制系统的Window。
Android的设备尺寸参差不齐,从几寸的小手机到几十寸的TV设备,我们需要学会为这么多的设备做出适配让尽可能多的人有更好的体验。支持多个屏幕尺寸有以下几种方式:
- 确保你的布局可以充分调整大小以适应屏幕
- 根据屏幕配置提供适当的UI布局
- 确保正确的布局应用到正确的屏幕
- 提供可缩放的Bitmap

使用”wrap_content” 和”match_parent”

一句话:少用固定的dp来设置宽高,不利于屏幕适配。

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout android:layout_width="match_parent" 
                  android:id="@+id/linearLayout1"  
                  android:gravity="center"
                  android:layout_height="50dp">
        <ImageView android:id="@+id/imageView1" 
                   android:layout_height="wrap_content"
                   android:layout_width="wrap_content"
                   android:src="@drawable/logo"
                   android:paddingRight="30dp"
                   android:layout_gravity="left"
                   android:layout_weight="0" />
        <View android:layout_height="wrap_content" 
              android:id="@+id/view1"
              android:layout_width="wrap_content"
              android:layout_weight="1" />
        <Button android:id="@+id/categorybutton"
                android:background="@drawable/button_bg"
                android:layout_height="match_parent"
                android:layout_weight="0"
                android:layout_width="120dp"
                style="@style/CategoryButtonStyle"/>
    </LinearLayout>

    <fragment android:id="@+id/headlines" 
              android:layout_height="fill_parent"
              android:name="com.example.android.newsreader.HeadlinesFragment"
              android:layout_width="match_parent" />
</LinearLayout>

layout-hvga

使用相对布局(RelativeLayout)

虽然你可以使用LinearLayout和”wrap_content” 、”match_parent”来创建一个相当复杂的布局,但不能精确地控制子View之间以及子View和父View之间的关系。比如屏幕方向变化时,为保证子View能随着变化而保持对父View的相对位置不变,这时,就必须使用RelativeLayout了。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:id="@+id/label"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Type here:"/>
    <EditText
        android:id="@+id/entry"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/label"/>
    <Button
        android:id="@+id/ok"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/entry"
        android:layout_alignParentRight="true"
        android:layout_marginLeft="10dp"
        android:text="OK" />
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toLeftOf="@id/ok"
        android:layout_alignTop="@id/ok"
        android:text="Cancel" />
</RelativeLayout>

relativelayout1
relativelayout2
以上两张图显示,横竖屏切换时,Cancel和OK按钮的相对位置以及相对屏幕的位置都没变。

使用Size限定符

上面两种布局虽然可以适配一定的屏幕,但无法适配一些特定的屏幕尺寸。
比如,对于“列表”和“详细”,一些屏幕实现“两屏”的模式,特别是在平板和TV上,但在手机上,必须将两屏分开在两个界面显示。

  • res/layout/main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment android:id="@+id/headlines"
              android:layout_height="fill_parent"
              android:name="com.example.android.newsreader.HeadlinesFragment"
              android:layout_width="match_parent" />
</LinearLayout>
  • res/layout-large/main.xml
<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>

注意:large限定符,它修饰的布局,在大屏幕上显示(如在7寸及以上尺寸的平板上),而没有任何限定符的,则在一些较小的设备上显示。

使用最小宽度限定符( Smallest-width Qualifier)

很多App希望不同的大屏上显示不同的布局(比如在5寸和7寸的大屏上),这就是为什么在Android 3.2上出现最小宽度限定符的原因。
Smallest-width限定符允许你使用一个确定的最小的dp单位的宽度应用到目标设备上。如果你想在大屏上使用左右窗格显示,可以像上面那种模式一样,写多个相同的布局,这次不用large限定符了,用sw600dp,表示在宽度600dp及以上的设备上将使用我们定义的布局:

  • res/layout/main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment android:id="@+id/headlines"
              android:layout_height="fill_parent"
              android:name="com.example.android.newsreader.HeadlinesFragment"
              android:layout_width="match_parent" />
</LinearLayout>
  • res/layout-sw600dp/main.xml
<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>

这意味着宽度大于等于600dp的设备将使用layout-sw600dp/main.xml(双窗格模式)的布局,小于这个宽度的设备使用layout/main.xml(单窗格模式)。
然而,在Android3.2以前的设备,是不能识别sw600dp这种限定符的,所以为了兼容你必须使用large限定符。再增加res/layout-large/main.xml,让里面的内容和res/layout-sw600dp/main.xml一模一样。在下一部分,你将看到一种技术,它允许你避免重复定义这样的布局文件。

使用布局别名(Layout Alias)

在使用smallest-width限定符时,由于它是3.2才有的,所以在兼容以前老版本时,需要再重复定义large限定符的布局文件,这样会对以后的开发维护带来麻烦。为了避免这种情况,我们使用布局别名,比如:

  • res/layout/main.xml, 单窗格
  • res/layout/main_twopanes.xml,多窗格
    然后加下面两个文件:

  • res/values-large/layout.xml:

<resources>
    <item name="main" type="layout">@layout/main_twopanes</item>
</resources>
  • res/values-sw600dp/layout.xml:
<resources>
    <item name="main" type="layout">@layout/main_twopanes</item>
</resources>

这样解决了维护多个相同布局文件的麻烦。

使用方向限定符

一些布局可以在横屏和竖屏自动调整的很好,但大部分还是需要手工调整的。比如在NewsReader例子中,不同的屏幕尺寸不同的方向,显示的Bar是不一样的:

  • small screen, portrait: single pane, with logo
  • small screen, landscape: single pane, with logo
  • 7” tablet, portrait: single pane, with action bar
  • 7” tablet, landscape: dual pane, wide, with action bar
  • 10” tablet, portrait: dual pane, narrow, with action bar
  • 10” tablet, landscape: dual pane, wide, with action bar
  • TV, landscape: dual pane, wide, with action bar
    所以每一个布局都定义在res/layout/目录下,每一个布局都对应一个屏幕配置(大小和方向)。app使用布局别名来匹配它们到各自对应的设备:
    res/layout/onepane.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment android:id="@+id/headlines"
              android:layout_height="fill_parent"
              android:name="com.example.android.newsreader.HeadlinesFragment"
              android:layout_width="match_parent" />
</LinearLayout>

res/layout/onepane_with_bar.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout android:layout_width="match_parent" 
                  android:id="@+id/linearLayout1"  
                  android:gravity="center"
                  android:layout_height="50dp">
        <ImageView android:id="@+id/imageView1" 
                   android:layout_height="wrap_content"
                   android:layout_width="wrap_content"
                   android:src="@drawable/logo"
                   android:paddingRight="30dp"
                   android:layout_gravity="left"
                   android:layout_weight="0" />
        <View android:layout_height="wrap_content" 
              android:id="@+id/view1"
              android:layout_width="wrap_content"
              android:layout_weight="1" />
        <Button android:id="@+id/categorybutton"
                android:background="@drawable/button_bg"
                android:layout_height="match_parent"
                android:layout_weight="0"
                android:layout_width="120dp"
                style="@style/CategoryButtonStyle"/>
    </LinearLayout>

    <fragment android:id="@+id/headlines" 
              android:layout_height="fill_parent"
              android:name="com.example.android.newsreader.HeadlinesFragment"
              android:layout_width="match_parent" />
</LinearLayout>

res/layout/twopanes.xml:

<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>

res/layout/twopanes_narrow.xml:

<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="200dp"
              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>

既然所有的布局都定义好了,现在就只需要将正确的布局对应到每个配置的文件中。如下使用布局别名技术:
res/values/layouts.xml:

<resources>
    <item name="main_layout" type="layout">@layout/onepane_with_bar</item>
    <bool name="has_two_panes">false</bool>
</resources>

res/values-sw600dp-land/layouts.xml:

<resources>
    <item name="main_layout" type="layout">@layout/twopanes</item>
    <bool name="has_two_panes">true</bool>
</resources>

res/values-sw600dp-port/layouts.xml:

<resources>
    <item name="main_layout" type="layout">@layout/onepane</item>
    <bool name="has_two_panes">false</bool>
</resources>

res/values-large-land/layouts.xml:

<resources>
    <item name="main_layout" type="layout">@layout/twopanes</item>
    <bool name="has_two_panes">true</bool>
</resources>

res/values-large-port/layouts.xml:

<resources>
    <item name="main_layout" type="layout">@layout/twopanes_narrow</item>
    <bool name="has_two_panes">true</bool>
</resources>

使用Nine-patch图片

要支持不同的屏幕分辨率,那么图片也需要做成多个尺寸的,这样势必增加美工的工作量。如果应用图片较多,那么可想而知这时一件多么可怕的事情。这时,9-patch图片可以很好的解决这个问题,它可以随着屏幕的变化而伸展而不变形。
9-patch图片是.9.png为后缀的图片,它使用SDK目录下tools文件夹下的draw9patch.bat的工具来制作。

样例代码:NewsReader

为多屏设计(二) - 支持不同的屏幕密度

参考地址:http://developer.android.com/training/multiscreen/screendensities.html
本文向你展示如何通过提供不同的资源和使用分辨率无关的测量单位支持不同的屏幕密度。

使用像素密度

一句话,使用dp(尺寸、距离等)、sp(文本)单位,尽量不用px单位。
例如:

<Button android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/clickme"
    android:layout_marginTop="20dp" />

指定文本大小,使用sp:

<TextView android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textSize="20sp" />

提供可选择的Bitmap

因为Android运行在各个屏幕密度不同的设备中,所以你需要为不同的密度设备提供不同的图片资源 low, medium, high and xhigh 等等。

  • xhdpi: 2.0
  • hdpi: 1.5
  • mdpi: 1.0 (baseline)
  • ldpi: 0.75
    意思是说,如果你为一个密度是2 的设备准备了200x200的图片,那么同时需要为密度为1.5的设备准备150x150的图片,为密度为1的设备准备100x100的图片,为密度为0.75的设备准备75x75的图片。
    然后在res目录下生成多个drawable文件夹:
MyProject/
  res/
    drawable-xhdpi/
        awesomeimage.png
    drawable-hdpi/
        awesomeimage.png
    drawable-mdpi/
        awesomeimage.png
    drawable-ldpi/
        awesomeimage.png

你通过引用@drawable/awesomeimage,系统将通过屏幕的dpi找到合适的图片。

将app启动logo放在mipmap/文件夹下:

res/...
    mipmap-ldpi/...
        finished_launcher_asset.png
    mipmap-mdpi/...
        finished_launcher_asset.png
    mipmap-hdpi/...
        finished_launcher_asset.png
    mipmap-xhdpi/...
        finished_launcher_asset.png
    mipmap-xxhdpi/...
        finished_launcher_asset.png
    mipmap-xxxhdpi/...
        finished_launcher_asset.png

你应该将app启动图片放在res/mipmap-[density]/文件夹,而不是drawable/下面,以确保使用最佳的分辨率

为多屏设计(三) - 实现适配的UI流

参考地址:http://developer.android.com/training/multiscreen/adaptui.html
根据应用程序目前显示的布局,界面流可能会有所不同。例如,如果你的App是双窗格模式,点击左侧窗格上的一个item,将在右边的面板中显示对应的内容;如果是在单窗格模式下,显示的内容应该在一个新的Activity里。

确定当前的布局

判断当前布局是单窗格模式还是多窗格模式(如在NewsReader App中):

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;
    }
}

在使用一个组件之前需要检测是否为null。比如,在NewsReader的例子App中,有一个按钮只在Android 3.0 一下的版本下运行时才出现,3.0以上的版本显示Actionbar(API11+),所以在操作这个按钮时,应该这样做:

Button catButton = (Button) findViewById(R.id.categorybutton);
OnClickListener listener = /* create your listener here */;
if (catButton != null) {
    catButton.setOnClickListener(listener);
}

根据当前的布局React

当前布局不同,那么点击同样的item,会产生不同的效果。比如,在NewsReader中,单窗格模式,点击item,会进入一个新的Activity,双窗格模式下,点击item(左侧),右侧则显示相应的内容:

@Override
public void 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 = new Intent(this, ArticleActivity.class);
        intent.putExtra("catIndex", mCatIndex);
        intent.putExtra("artIndex", index);
        startActivity(intent);
    }
}

同样,在双窗格模式下,你应该在ActionBar上创建Tabs导航,反而言之,如果app是单窗格模式,你应该使用Spinner组件进行导航。所以代码如下:

final String CATEGORIES[] = { "Top Stories", "Politics", "Economy", "Technology" };

public void 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 = new ArrayAdapter(this, 
                R.layout.headline_item, CATEGORIES);
        actionBar.setListNavigationCallbacks(adap, handler);
    }
}

在其他Activities重用Fragments

复用模式在多屏状态下比较常用。比如在NewsReader App中,News详情采用一个Fragment,那么它既可以用在双窗格模式的右边,又可以用在单窗格模式下的详情Activity中。
ArticleFragment在双窗格模式下:

<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>

在单窗格模式下,不需要为ArticleActivity创建布局,直接使用ArticleFragment:

ArticleFragment frag = new ArticleFragment();
getSupportFragmentManager().beginTransaction().add(android.R.id.content, frag).commit();

要深深记住的一点是,不要让Fragment和你的Activity有强的耦合性。你可以在Fragment中定义接口,由Activity来实现。比如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;
    }
}

当用户选择了一个标题,fragment就会通知绑定到指定Activity的监听器:

public class HeadlinesFragment extends ListFragment {
    ...
    @Override
    public void onItemClick(AdapterView<?> parent, 
                            View view, int position, long id) {
        if (null != mHeadlineSelectedListener) {
            mHeadlineSelectedListener.onHeadlineSelected(position);
        }
    }
    ...
}

处理屏幕配置更改(Configuration Changes)

如果你使用单独的Activity实现界面的一些部分,那么就应该记住当屏幕变化时(比如旋转屏幕)需要重构界面。
比如,在7寸运行Android3.0及以上版本的平板上,NewsReader App在竖屏时新闻详情界面在单独的一个Activity中,但是在横屏时,它使用双窗格模式,左右各一个Fragment。
这意味着,当用户竖屏切换到横屏来看一个新闻详情,你需要监测到屏幕的变化,来进行适当的重构:结束当前的Activity,显示左右两个窗格。

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;
        }
        ...
}

示例代码:NewsReader

AppBar(ActionBar->ToolBar)

参考地址:http://developer.android.com/training/appbar/index.html

创建应用程序栏(AppBar)

在大多数的App中都会有标题栏这个组件,这个组件能让App有统一的风格,它一般由标题和溢出菜单(overflow menu)组成。
appbar_basic
从Android3.0开始,使用默认主题的Activity都有一个ActionBar作为标题栏。然而,随着版本的不断升级,不断有新的特性加到ActionBar中,导致不同的版本ActionBar的行为不太一样。相比之下,支持库(support library)中的ToolBar不断集成了最新的特性,而且可以无差异的运行到任意的设备上。
基于此,我们使用支持库中的Toolbar作为AppBar,他提供各种设备一致的行为。

在Activity中添加Toolbar

  1. 添加v7 appcompat support library到工程中
  2. 确保Activity继承AppCompatActivity
  3. 在manifest文件的 元素中使用 NoActionBar主题
<application
    android:theme="@style/Theme.AppCompat.Light.NoActionBar"
    />

4.在Activity的布局中添加Toolbar

<android.support.v7.widget.Toolbar
   android:id="@+id/my_toolbar"
   android:layout_width="match_parent"
   android:layout_height="?attr/actionBarSize"
   android:background="?attr/colorPrimary"
   android:elevation="4dp"
   android:theme="@style/ThemeOverlay.AppCompat.ActionBar"
   app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>

Material Design specification推荐App Bar有一个4dp的elevation。

5.在Activity的onCreate()方法中,调用Activity的setSupportActionBar(),使ToolBar作为Activity的App bar。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_my);
    Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
    setSupportActionBar(myToolbar);
    }

这样你就创建了一个基本的actionbar,上面默认是app的名称和一个溢出菜单。菜单中只有Settings选项。

使用 App Bar的实用方法

在Activity的标题栏创建了toolbar 之后,你可以使用v7 appcompat support library提供的ActionBar类的很多实用方法,比如显示和隐藏App bar。
通过getSupportActionBar()得到兼容的ActionBar,如果要隐藏它,可以调用ActionBar.hide()。

添加和处理Actions

Appbar是有限的,所以在它上面添加action,就会溢出(overflow),可以选择将其放到menu中。
appbar_with_button
图:添加了一个按钮的AppBar

添加Action 按钮

在menu资源中添加item来添加菜单选项:

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

    <!-- "Mark Favorite", should appear as action button if possible -->
    <item
        android:id="@+id/action_favorite"
        android:icon="@drawable/ic_favorite_black_48dp"
        android:title="@string/action_favorite"
        app:showAsAction="ifRoom"/>

    <!-- Settings, should always be in the overflow -->
    <item android:id="@+id/action_settings"
          android:title="@string/action_settings"
          app:showAsAction="never"/>

</menu>

app:showAsAction属性表示哪个action可以显示到appbar上。如果设置为app:showAsAction=”ifRoom”,则appbar上有空间显示在appbar上,没有空间就藏在菜单中;如果设置app:showAsAction=”never”,则这个action永远都在菜单中,不会显示在appbar上。

响应Actions

在Activity中的onOptionsItemSelected()中处理菜单的点击事件:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.action_settings:
            // User chose the "Settings" item, show the app settings UI...
            return true;

        case R.id.action_favorite:
            // User chose the "Favorite" action, mark the current item
            // as a favorite...
            return true;

        default:
            // If we got here, the user's action was not recognized.
            // Invoke the superclass to handle it.
            return super.onOptionsItemSelected(item);

    }
}

添加一个Up Action

为了用户方便的返回主界面,我们需要在Appbar上提供一个Up 按钮。当用户点击Up按钮,app则返回到父Activity。

声明父Activity

例如:

<application ... >
    ...

    <!-- The main/home activity (it has no parent activity) -->

    <activity
        android:name="com.example.myfirstapp.MainActivity" ...>
        ...
    </activity>

    <!-- A child of the main activity -->
    <activity
        android:name="com.example.myfirstapp.MyChildActivity"
        android:label="@string/title_activity_child"
        android:parentActivityName="com.example.myfirstapp.MainActivity" >

        <!-- Parent activity meta-data to support 4.0 and lower -->
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.example.myfirstapp.MainActivity" />
    </activity>
</application>

让Up按钮可用(Enable)

要让Up按钮可用,需要在onCreate()方法中调用appbar的setDisplayHomeAsUpEnabled()方法。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_my_child);

    // my_child_toolbar is defined in the layout file
    Toolbar myChildToolbar =
        (Toolbar) findViewById(R.id.my_child_toolbar);
    setSupportActionBar(myChildToolbar);

    // Get a support ActionBar

以上是关于Android最佳实践之UI的主要内容,如果未能解决你的问题,请参考以下文章

android片段-数据传递-最佳实践[重复]

在android中使用底部导航的最佳实践:活动与片段

不使用支持库的 Android 4.0、4.1 (<4.2) 中嵌套片段的最佳实践

Android开发:Translucent System Bar 的最佳实践

Android最佳实践之高效的应用导航

FlutterComponent最佳实践之TabbarIndicator