參考: 吳小龍:Android Design Support Library使用
參考:徐宜生:Android Design Support Library使用詳解
最近看到一個介紹的也挺好的Meterial Design開發者文檔
1 CoordinatorLayout #
效果圖:
布局圖:
可以實作滑到頂部固定的效果
需要滿足的條件
- A必須設定:app:layout_scrollFlags=”scroll|enterAlways”,B不設定。
- C必須設定:app:layout_behavior=”@string/appbar_scrolling_view_behavior”
- AB必須在AppBarLayout中
- ABC必須在CoodinatorLayout中
- 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
效果圖
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;
效果圖
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
通過自定義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中胚子。
效果圖
代碼
點選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
效果圖:
6 TextInputLayout
其它:android TextInputLayout元件的使用
注意:
design:25.0.0
有顯示密碼這個小眼睛
,
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”用另一張圖檔代替小眼睛
需要注意的是:如果想要顯示小眼睛,就需要在
或者 EditText 中設定 為密碼格式。比如:
TextInputEditText
android:inputType="textPassword"
如果在xml中給
TextInputLayout
設定
app:errorEnabled="true"
,那麼會擴大它的高,顯得不美觀,是以在xml中不配置此屬性。
效果圖
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是軟鍵盤(輸入法)的意思,是軟鍵盤右下角按鈕的id,
android:imeActionId=
是動作意圖,
android:imeOptions="actionDone"
是顯示的文字(以
android:imeActionLabel=
為主)。詳情android EditText inputType 及 android:imeOptions=”actionDone”
imeOptions
代碼
//剛開始不顯示錯誤資訊,隻有判斷之後才會提示錯誤資訊
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("賬号不可為空!");
效果圖是這樣的
如果
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>
8 BottomNavigationView
可以作為底部導航欄,自帶 動畫效果,當隻有3個tab時,顯示頂部文字;檔有4-5個tab時,隻顯示目前tab的文字。
效果圖:
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
,是以可以節點下添加其它控件。下圖添加了分割線。
<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圖:
方法:
第一步: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);
}
此時的效果圖:
第二步: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();
}
}
}
解決後的效果圖:
相關的庫:
NavBar
AHBottomNavigation
BottomNavigationBar
BottomNavigationViewEx
BottomBar
BottomNavigation
9 CollapsingToolbarLayout
包裹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中間部分。
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
下面的效果
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
<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 白天模式 + 夜間模式
用到的類: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 過度動畫
用到的類: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());
}
});