天天看点

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

继续阅读