天天看點

Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫

參考: 吳小龍:Android Design Support Library使用

參考:徐宜生:Android Design Support Library使用詳解

最近看到一個介紹的也挺好的Meterial Design開發者文檔

1 CoordinatorLayout #

Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫

效果圖:

Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫

布局圖:

可以實作滑到頂部固定的效果
Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫

需要滿足的條件

  1. A必須設定:app:layout_scrollFlags=”scroll|enterAlways”,B不設定。
  2. C必須設定:app:layout_behavior=”@string/appbar_scrolling_view_behavior”
  3. AB必須在AppBarLayout中
  4. ABC必須在CoodinatorLayout中
  5. C不能是ListView,一般是RecyclerView,或者ViewPager,ScrollView

含義:

現在,當使用者滾動RecyclerView,AppBarLayout可以這樣響應滾動事件:根據子view的滾動标志(scroll flag)來控制它們如何進入(滾入螢幕)與退出(滾出螢幕)。

Flag包括:

scroll: 所有想滾動出螢幕的view都需要設定這個flag- 沒有設定這個flag的view将被固定在螢幕頂部。


enterAlways: 這個flag讓任意向下的滾動都會導緻該view變為可見,啟用快速“傳回模式”。


enterAlwaysCollapsed: 顧名思義,這個flag定義的是何時進入(已經消失之後何時再次顯示)。
假設你定義了一個最小高度(minHeight)同時enterAlways也定義了,那麼view将在到達這個最小高度的時候開始顯示,并且從這個時候開始慢慢展開,當滾動到頂部的時候展開完。              


exitUntilCollapsed: 同樣顧名思義,這個flag時定義何時退出,當你定義了一個minHeight,這個view将在滾動到達這個最小高度的時候消失。
           

布局:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    tools:context="com.cqc.coordinatorlayoutdemo.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolBar"
            android:layout_width="match_parent"
            android:layout_height="30dp"
            app:layout_scrollFlags="scroll|enterAlways"
            app:navigationIcon="@mipmap/ic_launcher"
            app:subtitle="标題"/>

        <android.support.design.widget.TabLayout
            android:id="@+id/tabLayout"
            android:layout_width="match_parent"

            android:layout_height="wrap_content"/>

    </android.support.design.widget.AppBarLayout>


    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:dividerHeight="2dp"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

    </android.support.v7.widget.RecyclerView>


</android.support.design.widget.CoordinatorLayout>
           

代碼:

package com.cqc.coordinatorlayoutdemo;

import android.support.design.widget.TabLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

/**
 * 主要是實作頂部固定的效果,其他的都沒做處理
 * 效果:螢幕從上到下是:A-->B-->C,
 *      手指往上滑動控件C,會導緻控件A移除螢幕,控件B頂部固定;
 *      手指往下滑動控件C,控件A再次出現
 * 要求:
 *  1 劃出螢幕的控件必須設定app:layout_scrollFlags="scroll|enterAlways"
 *  2 頂部固定的控件不用設定app:layout_scrollFlags="scroll|enterAlways"
 *  3 上述的2個控件必須在AppBarLayout中
 *  4 滑動控件 必須設定app:layout_behavior="@string/appbar_scrolling_view_behavior"
 *  5 滑動的那個控件不能是listView
 *  6 A B C 3個控件必須在CoodinatorLayout中
 *
 *
 * */
public class MainActivity extends AppCompatActivity {

    private List<String> list = new ArrayList<>();
    private Toolbar toolBar;
    private TabLayout tabLayout;
    private RecyclerView recyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main);

        findViews();
        initViews();
    }

    private void initViews() {
        initToolbar();
        initTabLayout();
        initRecyclerView();
    }

    private void initToolbar() {

    }

    private void initTabLayout() {
        //設定mode
        tabLayout.setTabMode(TabLayout.MODE_FIXED);
        //添加每個tab的文字
        tabLayout.addTab(tabLayout.newTab().setText("tab1"), );
        tabLayout.addTab(tabLayout.newTab().setText("tab2"), );
        tabLayout.addTab(tabLayout.newTab().setText("tab3"), );
    }

    private void initRecyclerView() {
        initData();

        recyclerView.setItemAnimator(new DefaultItemAnimator());//item動畫有預設的
        recyclerView.setLayoutManager(new LinearLayoutManager(MainActivity.this,LinearLayoutManager.VERTICAL,false));
        MyAdapter adapter = new MyAdapter();
        recyclerView.setAdapter(adapter);
    }

    private void findViews() {
        toolBar = (Toolbar) findViewById(R.id.toolBar);
        tabLayout = (TabLayout) findViewById(R.id.tabLayout);
        recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
    }

    private void initData() {
        list.clear();
        for (int i = ; i < ; i++) {
            list.add("text" + i);
        }
    }


    public class MyAdapter extends RecyclerView.Adapter<MyHolder> {

        @Override
        public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            TextView tv = new TextView(MainActivity.this);
            MyHolder holder = new MyHolder(tv);
            return holder;
        }

        @Override
        public void onBindViewHolder(MyHolder holder, int position) {
            holder.tv.setText(list.get(position));
            holder.tv.setTextSize();
        }

        @Override
        public int getItemCount() {
            return list.size();
        }
    }

    public class MyHolder extends RecyclerView.ViewHolder {

        public TextView tv;

        public MyHolder(View itemView) {
            super(itemView);
            tv = (TextView) itemView;
        }
    }
}
           

位于CoordinatorLayout的底部

子View位于CoordinatorLayout的底部,應該用屬性

layout_gravity

layout_alignParentBottom

無效

源碼:CoordinatorLayout

2 NavigationView

DrawerLayout的側欄欄布局控件,xml中有2個重要的屬性

headerLayout + menu

,分别是側拉欄的頭像布局和主布局。

當然可以使用java填充布局:

nagivationView.inflateHeaderView(R.layout.layout_main_nav);
View headerView = mNavView.getHeaderView();//可能有多個header
           

效果圖

Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫

xml中的使用

<!--有滾動效果scrollbar-->
<android.support.design.widget.NavigationView
    android:id="@+id/navigationView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="left"
    android:fitsSystemWindows="true"
    app:headerLayout="@layout/header_layout_navigation_view"
    app:menu="@menu/menu_naviagtion_view_main"/>
           

headerLayout:header_layout_navigation_view.xml比較簡單,隻是放置了1個imageView+2個TextView.

menu:menu_naviagtion_view_main.xml

menu節點包含group+item,group包含item。
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group android:checkableBehavior="single">
        <item
            android:id="@+id/camera"
            android:icon="@android:drawable/ic_menu_camera"
            android:title="camera"/>
        <item
            android:id="@+id/gallery"
            android:icon="@android:drawable/ic_menu_gallery"
            android:title="gallery"/>
        <item
            android:id="@+id/slideshow"
            android:icon="@android:drawable/ic_menu_slideshow"
            android:title="slideshow"/>
        <item
            android:id="@+id/manage"
            android:icon="@android:drawable/ic_menu_manage"
            android:title="manage"/>
    </group>

    <item android:title="其他">
        <menu>
            <item
                android:id="@+id/share"
                android:checkable="true"
                android:icon="@android:drawable/ic_menu_share"
                android:title="share"/>
            <item
                android:id="@+id/send"
                android:checkable="true"
                android:icon="@android:drawable/ic_menu_send"
                android:title="send"/>
        </menu>
    </item>
</menu>
           

代碼

navigationView.setNavigationItemSelectedListener(this);

public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener
           

2種方式填充HeadView和Menu

第一種:上面說的xml填充

第二種:代碼填充

mNavigationView.inflateMenu(R.menu.nav_menu);
        mNavigationView.inflateHeaderView(R.layout.nav_header_main);
           

怎麼讓預設選中第一個MenuItem

Menu menu = mNavigationView.getMenu();
menu.getItem().setChecked(true);
           

3 FloatingActionButton

懸浮控件,可以設定擺放的位置。

當然懸浮控件還可以通過

relativeLayout(根布局) = layout +button;

來實作

效果圖

Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫

xml

<!--紅色是前景色,所有android:background="@android:drawable/ic_dialog_email"無效,不顯示-->
<android.support.design.widget.FloatingActionButton
    android:id="@+id/fab"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="bottom|end"
    android:layout_margin="20dp"
    android:src="@android:drawable/ic_dialog_email"
    />
           

代碼

點選FloatingActionButton,彈出Toast
fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
            Toast.makeText(getApplicationContext(), "action", Toast.LENGTH_SHORT).show();
    }
});
           

上滑隐藏FAB,下滑顯示TAB

Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫

通過自定義behavior來實作:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2016/0407/4126.html,并在xml中定義beh。

下面2種方法,測試上滑FAB會消失,但是下滑FAB沒有出現,網絡的解決方法如下,但是測試無效。http://stackoverflow.com/questions/31381474/menu-and-autohide-floatingactionbutton-of-android-design-support-library

<android.support.design.widget.FloatingActionButton
    ...
    android:src="@android:drawable/sym_action_chat"
    app:layout_behavior="com.paireach.bw.view.ScrollAwareFABBehavior"/>
           

第一種:ScrollAwareFABBehaviorDefault

public class ScrollAwareFABBehaviorDefault extends FloatingActionButton.Behavior {

    public ScrollAwareFABBehaviorDefault(Context context, AttributeSet attrs) {
        super();
    }

    @Override
    public boolean onStartNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child,
                                       final View directTargetChild, final View target, final int nestedScrollAxes) {
        // Ensure we react to vertical scrolling
        return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL
                || super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
    }

    @Override
    public void onNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child,
                               final View target, final int dxConsumed, final int dyConsumed,
                               final int dxUnconsumed, final int dyUnconsumed) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
        if (dyConsumed >  && child.getVisibility() == View.VISIBLE) {
            // User scrolled down and the FAB is currently visible -> hide the FAB
            child.hide();
        } else if (dyConsumed <  && child.getVisibility() != View.VISIBLE) {
            // User scrolled up and the FAB is currently not visible -> show the FAB
            child.show();
        }
    }
}
           

第二種:ScrollAwareFABBehavior

public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior {

    private static final Interpolator INTERPOLATOR = new FastOutSlowInInterpolator();
    private boolean mIsAnimatingOut = false;

    public ScrollAwareFABBehavior(Context context, AttributeSet attrs) {
        super();
    }

    @Override
    public boolean onStartNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child,
                                       final View directTargetChild, final View target, final int nestedScrollAxes) {
        // Ensure we react to vertical scrolling
        return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL
                || super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
    }

    @Override
    public void onNestedScroll(final CoordinatorLayout coordinatorLayout, final FloatingActionButton child,
                               final View target, final int dxConsumed, final int dyConsumed,
                               final int dxUnconsumed, final int dyUnconsumed) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);
        if (dyConsumed >  && !this.mIsAnimatingOut && child.getVisibility() == View.VISIBLE) {
            // User scrolled down and the FAB is currently visible -> hide the FAB
            animateOut(child);
        } else if (dyConsumed <  && child.getVisibility() != View.VISIBLE) {
            // User scrolled up and the FAB is currently not visible -> show the FAB
            animateIn(child);
        }
    }

    // Same animation that FloatingActionButton.Behavior uses to hide the FAB when the AppBarLayout exits
    private void animateOut(final FloatingActionButton button) {
        if (Build.VERSION.SDK_INT >= ) {
            ViewCompat.animate(button).translationY(button.getHeight() + getMarginBottom(button)).setInterpolator(INTERPOLATOR).withLayer()
                    .setListener(new ViewPropertyAnimatorListener() {
                        public void onAnimationStart(View view) {
                            ScrollAwareFABBehavior.this.mIsAnimatingOut = true;
                        }

                        public void onAnimationCancel(View view) {
                            ScrollAwareFABBehavior.this.mIsAnimatingOut = false;
                        }

                        public void onAnimationEnd(View view) {
                            ScrollAwareFABBehavior.this.mIsAnimatingOut = false;
                            view.setVisibility(View.GONE);
                        }
                    }).start();
        } else {

        }
    }

    // Same animation that FloatingActionButton.Behavior uses to show the FAB when the AppBarLayout enters
    private void animateIn(FloatingActionButton button) {
        button.setVisibility(View.VISIBLE);
        if (Build.VERSION.SDK_INT >= ) {
            ViewCompat.animate(button).translationY()
                    .setInterpolator(INTERPOLATOR).withLayer().setListener(null)
                    .start();
        } else {

        }
    }

    private int getMarginBottom(View v) {
        int marginBottom = ;
        final ViewGroup.LayoutParams layoutParams = v.getLayoutParams();
        if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
            marginBottom = ((ViewGroup.MarginLayoutParams) layoutParams).bottomMargin;
        }
        return marginBottom;
    }
}
           

4 Snackbar

類似Toast,隻不過Snackbar實在螢幕頂部彈出,而且可以設定點選事件。同Toast一樣,不需要再xml中胚子。

效果圖

Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫

代碼

點選Snackbar,彈出Toast
fab.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        //Snacker和Toast差不多,隻是Snacker底部的彈出。setAction(...)可以給Snacker設定點選事件
        Snackbar.make(view, "fab", Snackbar.LENGTH_SHORT).setAction("action", new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(getApplicationContext(), "action", Toast.LENGTH_SHORT).show();
            }
        }).show();
    }
});
           
//無點選事件
Snackbar.make(view, "fab", Snackbar.LENGTH_SHORT).setAction("action", null).show();

//有點選事件
Snackbar.make(view, "fab", Snackbar.LENGTH_SHORT).setAction("action", new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Toast.makeText(getApplicationContext(), "action", Toast.LENGTH_SHORT).show();
    }
}).show();
           

源碼:https://git.oschina.net/MaterialDisign/NavigationViewDemo02

Metarial Design:主要示範 NavigationView + Snackbar + FloagtingActionButton 效果,還有CoordinatorLayout + AppbarLayout + Toolbar。

5 TabLayout

詳看:Android Design:原生TabLayout+viewpaper+fragment實作滑動效果

TabLayout一般配合ViewPager使用。設定title要在viewpager的adapter調用

getPageTitle(int position)

方法

xml

<android.support.design.widget.TabLayout
    android:id="@+id/tablayout"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:background="#03A9F4"
    app:tabGravity="fill"
    app:tabIndicatorColor="@color/colorPrimary"
    app:tabMode="fixed"
    app:tabIndicatorHeight="2dp"
    app:tabSelectedTextColor="@color/colorAccent"
    app:tabTextAppearance="@style/TabLayoutTextStyle"
    app:tabTextColor="@android:color/black">
</android.support.design.widget.TabLayout>
           

代碼:

//注意這行代碼的順序:viewpaper要先設定adapter,才可以讓 tablayout綁定,否則報錯:viewpager沒有setAdapter()
viewPager.setAdapter(adapter);
tabLayout.setupWithViewPager(viewPager);
viewPager.setCurrentItem();
           

TabLayoutDemo

下面介紹的内容是:TextInputLayout + BottomNavigationView + SearchView + 白天夜間模式切換

源碼:https://git.oschina.net/MaterialDisign/DesignDemo02

效果圖:

Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫

6 TextInputLayout

其它:android TextInputLayout元件的使用

注意:

design:25.0.0

有顯示密碼這個小眼睛

Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫

design:25.0.1

就沒有這個小眼睛。

顯示小眼睛需滿足2個條件:

android:inputType="textPassword"
app:passwordToggleEnabled="true"
           

裡面隻可以包含一個EditView,常用的2個 方法是

setErrorEnabled(boolean)

(不可以提示錯誤資訊) 和

setError(CharSequence)

(提示錯誤資訊)

app:counterEnabled=”true”//設定是否可以開啟計數器,預設是false

app:counterOverflowTextAppearance=”“ 電腦越位後的文字顔色和大小

app:counterMaxLength=”“電腦的最大字數限制

app:errorEnabled=”true” 是否允許錯誤提示

app:errorTextAppearance=”“ 錯誤提示的文字大小和顔色

app:passwordToggleEnabled=”true”顯示小眼睛

app:passwordToggleTint=”@color/colorAccent” 給小眼睛上色

app:passwordToggleTintMode=”multiply”小眼睛的顯示方式

app:passwordToggleDrawable=”@mipmap/ic_launcher”用另一張圖檔代替小眼睛

需要注意的是:如果想要顯示小眼睛,就需要在

TextInputEditText

或者 EditText 中設定 為密碼格式。比如:

android:inputType="textPassword"

如果在xml中給

TextInputLayout

設定

app:errorEnabled="true"

,那麼會擴大它的高,顯得不美觀,是以在xml中不配置此屬性。

效果圖

Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫

xml

<android.support.design.widget.TextInputLayout
    android:id="@+id/textInputLayout2"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_below="@id/textInputLayout1"
    android:layout_marginTop="10dp">

    <EditText
        android:id="@+id/et_pwd"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="密碼"
        android:imeActionId="@+id/login"
        android:imeActionLabel="登入"
        android:imeOptions="actionDone"
        android:inputType="textPassword"/>
</android.support.design.widget.TextInputLayout>
           
ime是軟鍵盤(輸入法)的意思,

android:imeActionId=

是軟鍵盤右下角按鈕的id,

android:imeOptions="actionDone"

是動作意圖,

android:imeActionLabel=

是顯示的文字(以

imeOptions

為主)。詳情android EditText inputType 及 android:imeOptions=”actionDone”

代碼

//剛開始不顯示錯誤資訊,隻有判斷之後才會提示錯誤資訊
textInputLayout1.setErrorEnabled(false);
textInputLayout2.setErrorEnabled(false);

String phone = et_phone.getText().toString().trim();
String pwd = et_pwd.getText().toString().trim();
if (TextUtils.isEmpty(phone)) {
    textInputLayout1.setError("手機号不可為空");
} else if (phone.length() != ) {
    textInputLayout1.setError("請輸入正确的手機号");
} else if (TextUtils.isEmpty(pwd)) {
    textInputLayout2.setError("密碼不可為空");
} else if (pwd.length() < ) {
    textInputLayout2.setError("密碼不少于6位");
} else {
    toast.setText("登入成功");
    toast.show();
}
           

可以給軟鍵盤的enter見設定點選事件,調用EditText的setOnEditorActionListener(…)方法

//設定軟鍵盤的點選事件
et_pwd.setOnEditorActionListener(new TextView.OnEditorActionListener() {
    @Override
    public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
        if (id == R.id.login || id == EditorInfo.IME_ACTION_DONE) {
            loginApp();//執行登入操作
            return true;//事件被消耗
        }
        return false;
    }
});
           

7 TextInputLayout

它的

etName.setError("賬号不可為空!");

效果圖是這樣的

Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫

如果

TextInputEditText

的父布局是

TextInputLayout

,這會導緻一個問題,就是當沒有輸入任何内容+調用方法

TextInputEditText.setError("")

時,圖檔小眼睛和錯誤提示框(圓)重疊在一起。他們都在

TextInputEditText

控件的最右邊。是以一般隻使用

TextInputLayout.setError("密碼不少于6位")

<android.support.design.widget.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <android.support.design.widget.TextInputEditText
        android:id="@+id/et_pwd"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:hint="@string/login_input_pwd"
        android:inputType="textPassword"/>
</android.support.design.widget.TextInputLayout>
           
Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫

8 BottomNavigationView

可以作為底部導航欄,自帶 動畫效果,當隻有3個tab時,顯示頂部文字;檔有4-5個tab時,隻顯示目前tab的文字。

效果圖:

Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫
Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫
Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫

xml

最重要的屬性是

app:menu=

<android.support.design.widget.BottomNavigationView
    android:id="@+id/bottomNavigationView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:background="#039BE5"
    app:menu="@menu/bottom_navigation_view"
    />
           

res/menu/bottom_navigation_view.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/tab1"
        android:icon="@android:drawable/ic_menu_add"
        android:title="tab1"/>
    <item
        android:id="@+id/tab2"
        android:icon="@android:drawable/ic_menu_search"
        android:title="tab2"/>
    <item
        android:id="@+id/tab3"
        android:icon="@android:drawable/ic_menu_share"
        android:title="tab3"/>
    <item
        android:id="@+id/tab4"
        android:icon="@android:drawable/ic_menu_camera"
        android:title="tab4"/>
    <item
        android:id="@+id/tab5"
        android:icon="@android:drawable/ic_menu_week"
        android:title="tab5"/>
</menu>
           

代碼

bottonNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                switch (item.getItemId()) {
                    case R.id.tab1:
                        toast.setText("tab1");
                        toast.show();
                        break;
                    case R.id.tab2:
                        toast.setText("tab2");
                        toast.show();
                        break;
                    ...
                }
                return true;
            }
        });
           

注意:

onNavigationItemSelected(...)

必須傳回

return true

,否則沒有動畫效果。

BottomNavigationView

繼承自

FrameLayou

,是以可以節點下添加其它控件。下圖添加了分割線。

Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫
<android.support.design.widget.BottomNavigationView
        android:id="@+id/bottom_navigation_view"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:layout_alignParentBottom="true"
        android:backgroundTint="@color/colorAccent"
        android:backgroundTintMode="src_atop"
        app:itemTextColor="#000000"
        app:menu="@menu/bottom_main_menu">

        <View
            android:layout_width="match_parent"
            android:layout_height="2dp"
            android:background="#00ff00"/>
    </android.support.design.widget.BottomNavigationView>
           

BottomNavigationView 怎麼預設選中第一個item?

系統預設選中第一個,但是系統選中第一個不執行

onNavigationItemSelected(MenuItem)

。方法未找到相關方法,用下面的代替

HomeFrag homeFrag = new HomeFrag();
getSupportFragmentManager().beginTransaction().add(R.id.frameLayout_main, homeFrag, "HomeFrag").commit();
           

今天看部落格的時候發現一個方法

當時該方法必須在

bottomView.setOnNavigationItemSelectedListener(...)

之後,否則無效。

下面的方法是無效的:

MenuItem tab1 = bottomView.getMenu().getItem();
tab1.setChecked(true);
或 都是無效的。
NavigationMenuItemView tab1 = (NavigationMenuItemView) bottomView.findViewById(R.id.tab1);
tab1.performClick();
           

怎麼解決BottomNavigationView +ViewPager結合使用導緻的bug?

bug描述:當viewpager滑動時,底部的menu被選中後無法恢複正常狀态。

bug圖:

Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫
Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫

方法:

第一步:ViewPager的監聽中加入下面代碼:

@Override
public void onPageSelected(int position) {
    if (menuItem != null) {
        menuItem.setChecked(false);
    } else {
        bottomNavigationView.getMenu().getItem().setChecked(false);
    }
    menuItem = bottomNavigationView.getMenu().getItem(position);
    menuItem.setChecked(true);
}
           

此時的效果圖:

Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫

第二步:BottomNavigationViewHelper.disableShiftMode(bottomNavigationView);

BottomNavigationViewHelper是自定義的類
// 利用反射,改變 item 中 mShiftingMode 的值
public class BottomNavigationViewHelper {

    public static void disableShiftMode(BottomNavigationView navigationView) {

        BottomNavigationMenuView menuView = (BottomNavigationMenuView) navigationView.getChildAt();
        try {
            Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode");
            shiftingMode.setAccessible(true);
            shiftingMode.setBoolean(menuView, false);
            shiftingMode.setAccessible(false);

            for (int i = ; i < menuView.getChildCount(); i++) {
                BottomNavigationItemView itemView = (BottomNavigationItemView) menuView.getChildAt(i);
                itemView.setShiftingMode(false);
                itemView.setChecked(itemView.getItemData().isChecked());
            }

        } catch (Exception e) {//NoSuchFieldException | IllegalAccessException e
            e.printStackTrace();
        }
    }
}
           

解決後的效果圖:

Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫

相關的庫:

NavBar

AHBottomNavigation

BottomNavigationBar

BottomNavigationViewEx

BottomBar

BottomNavigation

9 CollapsingToolbarLayout

Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫
包裹Toolbar + 其他控件,其他控件作為背景,這裡已ImageView為例
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    android:id="@+id/coordinatorLayout"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.design.widget.CollapsingToolbarLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <ImageView
                android:id="@+id/iv_activity_new"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:src="@mipmap/show_img2"/>

            <!--layout_height=wrap_content 不顯示title,也就沒有了title字型變小的動畫效果-->
            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                app:layout_collapseMode="pin"
                app:title="Toolbar"/>
        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>


    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="@string/show_text"/>
    </android.support.v4.widget.NestedScrollView>
</android.support.design.widget.CoordinatorLayout>
           

CollapsingToolbarLayout

中的child view 都可以使用屬性

app:layout_collapseMode=""

。有3種值: pin+parallax+none.“pin”:固定模式,在折疊的時候最後固定在頂端,保留左邊的三條橫線,顯示的部分是該view的bottom部分;“parallax”:視差模式,在折疊的時候會有個視差折疊的效果,顯示的是該View中間部分。

Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫
toolbar = (Toolbar) findViewById(R.id.toolbar);
 drawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
 toggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar,, );
 toggle.syncState();
 drawerLayout.addDrawerListener(toggle);
           

demo: https://git.oschina.net/MaterialDisign/DrawerLayoutCollpsingToolbarLayout.git

下面的效果

Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫
Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫

demo: https://git.oschina.net/MaterialDisign/DrawerLayoutCollpsingToolbarLayout2

要實作這個效果要注意:

1.

TabLayout

往上滑動的時候,他的top就是toolBar高度的大約1/2處(開發者模式–>顯示布局邊界,滑動的時候看一看到,大約是1/2處),是以要想完美顯示,注意調整ToolBar的height.

2. 給

TabLayout

設定

android:layout_gravity="bottom"

,否則預設是top

3. title文字要想顯示完美,注意調整參數

android:gravity="top"app:titleMarginTop="10dp"

4.

collapsingToolBarLayout.setTitleEnabled(false);

CollapsingToolbarLayout collapsingToolBarLayout = (CollapsingToolbarLayout) findViewById(R.id.collapsingToolBarLayout);
collapsingToolBarLayout.setTitleEnabled(false);
           
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsingToolBarLayout"
            android:layout_width="match_parent"
            android:layout_height="250dp"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:scaleType="centerCrop"
                android:src="@mipmap/show_img2"
                app:layout_collapseMode="parallax"/>

            <android.support.v7.widget.Toolbar
                android:id="@+id/toolbar"
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:gravity="top"
                app:titleMarginTop="10dp"
                app:layout_collapseMode="pin"
                app:navigationIcon="@mipmap/ic_nav_back_nor"
                app:title="Title"/>


            <android.support.design.widget.TabLayout
                android:id="@+id/tabLayout"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:layout_gravity="bottom"/>
        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>


    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior"/>


</android.support.design.widget.CoordinatorLayout>
           

下面介紹些其他的内容,不屬于Material Design,包含SearchView + 夜間模式 + 過度動畫

1 SearchView

Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫
<android.support.v7.widget.SearchView
    android:id="@+id/searchView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_below="@id/btn_login"
    android:layout_margin="10dp"
    android:background="@color/colorPrimary"
    app:queryHint="搜尋中..."
    />
           
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
    //點選軟鍵盤輸入法中的搜尋按鈕調用這個方法
    @Override
    public boolean onQueryTextSubmit(String query) {
        toast.setText(query);
        toast.show();
        return true;
    }

    //newText:搜尋框内的整體值
    @Override
    public boolean onQueryTextChange(String newText) {
        toast.setText(newText);
        toast.show();
        return true;
    }
});
           

2 白天模式 + 夜間模式

Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫

用到的類:AppCompatDelegate 方法setDefaultNightMode(int mode) + recreate();

需要建立res/values-night/style.xml,主題繼承自

Theme.AppCompat.DayNight

style.xml

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.DayNight.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        ...
    </style>

</resources>
           

代碼;

btn_day.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
        recreate();
    }
});
btn_night.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
        recreate();
    }
});
           

3 過度動畫

Design: Android Design Support Library(一)1 CoordinatorLayout #2 NavigationView3 FloatingActionButton4 Snackbar5 TabLayout6 TextInputLayout7 TextInputLayout8 BottomNavigationView9 CollapsingToolbarLayout1 SearchView 2 白天模式 + 夜間模式3 過度動畫
用到的類:ActivityOptionCompat + ViewCompat,用到的的方法

makeSceneTransitionAnimation(...), ViewCompat.setTransitionName(iv, "transition");

在MAinActivity中給ImageView設定點選事件,并設定過度動畫,在新打開的NewActivity中設定控件

iv.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        //ActivityOptionsCompat必須放在點選事件中
        ActivityOptionsCompat optionsCompat = ActivityOptionsCompat.makeSceneTransitionAnimation(MainActivity.this, iv, "transition");
        startActivity(new Intent(MainActivity.this, NewActivity.class), optionsCompat.toBundle());
    }
});      
           

繼續閱讀