TabLayout和TabLayout.Tab
使用場景
在ViewPager的上方哗讥,通常我們都會放一個標(biāo)簽指示器與ViewPager進行聯(lián)動; 以前通常使用開源的框架,或者自定義view;現(xiàn)在google提供的解決辦法-
使用方法
通常我們調(diào)用
TabLayout.setupWithViewPager
和ViewPager進行關(guān)聯(lián), 每個Tab的內(nèi)容從PagerAdapter.getPageTitle
方法獲取;也可以自己設(shè)置每個Tab的內(nèi)容, 代碼如下
TabLayout tabLayout = ...; TabLayout.Tab tab = tabLayout.newTab(); // 創(chuàng)建tab tab.setText("Tab 1"); // 設(shè)置每個tab的屬性 tabLayout.addTab(tab);
顯示的模式有2種, 一種固定寬度
TabLayout.MODE_FIXED
, 一種可以滾動TabLayout.MODE_SCROLLABLE
; 默認(rèn)是MODE_FIXED
, 可以通過代碼,也可以通過xml屬性設(shè)置常見屬性
<item name="tabMaxWidth">@dimen/tab_max_width</item> <item name="tabIndicatorColor">?attr/colorAccent</item> <item name="tabIndicatorHeight">2dp</item> <item name="tabPaddingStart">12dp</item> <item name="tabPaddingEnd">12dp</item> <item name="tabBackground">?attr/selectableItemBackground</item> <item name="tabTextAppearance">@style/TextAppearance.Design.Tab</item> <item name="tabSelectedTextColor">?android:textColorPrimary</item>
https://guides.codepath.com/android/google-play-style-tabs-using-tablayout#design-support-library
可以參考的鏈接
CoordinatorLayout AppbarLayout CollapsingToolbarLayout
CoordinatorLayout作用
CoordinatorLayout作用可以從名稱看出,作為一個協(xié)調(diào)者; 主要用來協(xié)調(diào)調(diào)度子View; 分兩個方面來協(xié)調(diào), 協(xié)調(diào)子View的布局 和協(xié)調(diào)子View的事件分發(fā)-
解決的問題
-
子View事件分發(fā)的困境;
在原先View的事件分發(fā)設(shè)計模型中, 事件由 dispatchTouchEvent分發(fā), 然后由 onIntercepteTouchEvent負責(zé)攔截, 最后在onTouchEvent中處理, ActionDown事件一旦被接收, 后續(xù)事件將默認(rèn)給此view處理, 其他view無法接收事件, 當(dāng)有多個view需要同時處理一個滑動事件時, 原先的事件分發(fā)無法解決; 原先一旦遇到這種情況,只有自己去自定義view, 重寫事件分發(fā)過程, 現(xiàn)在通過CoordinatorLayout可以優(yōu)雅的解決這個問題;NestedScroll: 解決父子view的同時處理同一事件的流程
CoordinatorLayout: 解決并列的兄弟View處理同一事件的流程 子View布局的困境
和子view的事件分發(fā)一樣, 原先每個子View布局位置, 是在父ViewGroup的layout方法中確定; 而當(dāng)需要子view的布局位置, 跟隨另一個子view變化時,絕大部分情況, 需要自定義view; 而現(xiàn)在CoordinatorLayout也可以優(yōu)雅的解決這個問題
-
-
使用
使用很簡單, 使用CoordinatorLayout作為父ViewGroup, 子view在xml中指定app:behavior
; 指定的behavior都是繼承于CoordinatorLayout.Behavior
, Behavior類提供的接口中, 可以定義該子View需要和另外哪些子view關(guān)聯(lián), 關(guān)聯(lián)的子view發(fā)生變化時, 自身怎么處理; 當(dāng)父CoordinatorLayout接收到滑動事件時, 該子view怎么處理;Behavior需要自己去自定義, 不過系統(tǒng)默認(rèn)提供幾種常用的behavior; 具體介紹, 下面再說
-
原理
-
子view接收處理的事件如何交給父CoordinatorLayout去分發(fā)
上面說過,父子view協(xié)同處理滑動事件, google官方很早給出了NestedScroll; 同時也在v4包中提供了NestedScrillingChild
,NestedScrollingChildHelper
,NestedScrollingParent
和NestedScrollingParentHelper
, 幫助我們解決嵌套的滾動問題;CoordinatorLayout
實現(xiàn)的NestedScrollingParent
接口, 因此當(dāng)子view實現(xiàn)了NestedScrillingChild
接口時,可以收到子view的滑動事件; 同時,原先系統(tǒng)的ScrollView, ListView都未實現(xiàn)NestedScrillingChild
, 所以放在CoordinatorLayout
中用于滾動的view一般是RecyclerView
,NestedScrollView
子view接收兄弟view的滑動事件并消耗掉
上面說到子view把滑動事件交給CoordinatorLayout去處理, 子View接收消耗兄弟view的的事件,就是CoordinatorLayout接收到事件后, 調(diào)用兄弟view的behavior的方法, 由我們自定義behavior去處理子view跟隨兄弟view變化而變化
和上面一樣, 布局原先是有l(wèi)ayout方法決定, 而在CoordinatorLayout
中, 在layout的過程中, 會調(diào)用behavior中的方法,以方便自己調(diào)整布局
從RecyclerView開始, View設(shè)計思想有所轉(zhuǎn)變; 組合優(yōu)于繼承, 約定優(yōu)于配置,體現(xiàn)的很明顯
多組合而少繼承; 推薦擴展指定的組件實現(xiàn)功能, 而不是通過自定義view去實現(xiàn)功能; eg: 使用behavior去控制CoordinatorLayout的事件分發(fā);使用LayoutMananger去控制recyclerview的布局 -
和AppbarLayout, CollapsingToolbarLayout 結(jié)合使用
-
作用
AppbarLayout一般放在CoordinatorLayout中使用, 可以使不具有處理滾動事件的view, 產(chǎn)生滾動效果; AppBarLayout會默認(rèn)和AppBarLayout.Behavior關(guān)聯(lián), 而該behavior中會幫我們處理滾動事件CollapsingToolbarLayout提供視差滾動, 和調(diào)整滾動時 狀態(tài)欄和toolbar顏色配置的功能
-
AppbarLayout的使用
AppBarLayout繼承與LinearLayout, 可以為每個子view設(shè)置app:layout_scrollFlags
屬性, 用于去控制子view的滾動
滾動屬性有如下幾種- scroll 該子view可以滾動
- enterAlways 當(dāng)有向下滾動事件時,改view就馬上顯示
- scrollUntilCollpse 向上滾動搜索直至最小高度, 需要和minHeight一起用
- snap 滾動只能在開始位置或者結(jié)束位置停下
<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.v4.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<!-- Your scrolling content -->
</android.support.v4.widget.NestedScrollView>
<android.support.design.widget.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent">
<android.support.v7.widget.Toolbar
...
app:layout_scrollFlags="scroll|enterAlways"/>
<android.support.design.widget.TabLayout
...
app:layout_scrollFlags="scroll|enterAlways"/>
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
一般在布局中, 遇到三段式布局, 并且布局布局要求滾動, 就可以考慮使用了
SnakeBar FloatActionButton
SnakeBar和Toast類似, 僅用于提示信息, 代碼寫法也和toast相似
Snackbar.make(mCoordinatorLayout, "顯示snackBar", Snackbar.LENGTH_SHORT).show();
BottomSheetBehavior BottomSheetDialog
使View從底部彈出, 分兩段顯示的一個Coordinator.Behavior, 必須使用在CoordinatorLayout
中;
對需要使用的的View,在布局中添加上app:layout_behavior="@string/bottom_sheet_behavior"
屬性即可
常用的有3中模式狀態(tài), 展開STATE_EXPANDED
, 收縮STATE_COLLAPSED
, 隱藏STATE_HIDDEN
, 隱藏后,一般需要通過代碼使其展開
在代碼中使用
View view = ....;
final BottomSheetBehavior behavior = BottomSheetBehavior.from(view);
behavior.setState(BottomSheetBehavior.STATE_COLLAPSED) // 設(shè)置狀態(tài)
常用屬性
app:behavior_hideable="true" // 是否可以隱藏
app:behavior_peekHeight="100dp" // 坍塌時的高度
BottomSheetDialog是BottomSheet的dialog實現(xiàn)形式; 實現(xiàn)比較巧妙, BottomSheetDialog繼承于Dialog,在構(gòu)造時,會創(chuàng)建CoordinatorLayout, 然后拿到dialog對應(yīng)的window的decorView, 將其添加到CoordinatorLayout中, 從而實現(xiàn)BottomSheetBehavior
Ripple animattion
水波紋動畫目前僅支持api>21的版本
屬于view的背景效果,放在drawable文件下, 由于只支持21之上,一般需要針對不同的版本提供2套背景, drawable-v21目錄使用水波紋悲劇, drawable目錄使用普通背景
創(chuàng)建內(nèi)容很簡單
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:colorControlHighlight">
<item android:drawable="@drawable/button_normal" />
</ripple>
有無界unbounded
和有邊境之分, 如果ripple中間沒有item, 就為unbounded的, 水波紋可以擴散到其他view的背景中去
Reveal animator
揭露動畫, 目前也僅支持api>21
通過ViewAnimationUtils.createCircularReveal
創(chuàng)建, 返回的是一個Animator
對象;
// 創(chuàng)建揭露動畫,
Animator revealAnimator = ViewAnimationUtils.createCircularReveal( animatorView, x, y, 0, animatorView.getWidth() );
stateListAnimator
View的狀態(tài)動畫, 和view的狀態(tài)背景相似
動畫文件放在animator目錄下,
參考鏈接
Transtions 轉(zhuǎn)場動畫
新的過渡動畫,仍然只兼容api>21的版本
示例demo可以參考 https://github.com/lgvalle/Material-Animations
過渡動畫
原先的過渡動畫Activity.overridePendingTransition
,只有進入,退出兩種, 現(xiàn)在有了4種;
分別為以下4種;
EnterTransition <--> ReturnTransition
ExitTransition <--> ReenterTransition
假設(shè)Activity A 啟動Activity B;
A退出時,觸發(fā)ExitTransition; 跳轉(zhuǎn)到B, 進入到B時, 觸發(fā)EnterTransition;
從B點擊返回鍵,退回到A時
B觸發(fā)ReturnTransition, 返回到A時, 觸發(fā)A的ReenterTransition
目前支持的動畫, 有Explode, Fade, Slide幾種, 動畫支持在主題中配置,和使用代碼設(shè)置, 和原先的過渡動畫相似
-
在主題中配置動畫示例
- 創(chuàng)建動畫文件
<?xml version="1.0" encoding="utf-8"?>
<slide xmlns:android="http://schemas.android.com/apk/res/"
android:duration="1000"/> - 在主題中使用屬性引用動畫文件
<item name="android:windowEnterTransition"></item>
<item name="android:windowExitTransition"></item>
<item name="android:windowReenterTransition"></item>
<item name="android:windowReturnTransition"></item>
- 創(chuàng)建動畫文件
-
手動配置示例
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_transition);
setupWindowAnimations();
}private void setupWindowAnimations() { Slide slide = TransitionInflater.from(this).inflateTransition(R.transition.activity_slide); getWindow().setExitTransition(slide); }
如果只配置EnterTransition,沒有配置ReturnTransition, 在返回時, 將會把EnterTransition反過來運行一遍
退出時需要運行ReturnTransition和ReenterTransition試, 不能直接調(diào)用
Activity.finish
方法, 要改為調(diào)用Activity.finishAfterTransition
, 如果各版本要保持相同的代碼, 可以調(diào)用ActivityCompact
的ActivityCompat
方法
共享元素的過渡動畫
在主題中打開該功能, 如果使用的material design主題, 會默認(rèn)打開
<style name="MaterialAnimations" parent="@style/Theme.AppCompat.Light.NoActionBar">
...
<item name="android:windowContentTransitions">true</item
...
</style>設(shè)置共享view的transition name; 2個共享view的android:transitionName屬性必須一樣
<ImageView
android:id="@+id/small_blue_icon"
style="@style/MaterialAnimations.Icon.Small"
android:src="@drawable/circle"
android:transitionName="@string/blue_name" />-
使用新的api構(gòu)建動畫并啟動actiivity
blueIconImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(MainActivity.this, SharedElementActivity.class);View sharedView = blueIconImageView; String transitionName = getString(R.string.blue_name); ActivityOptions transitionActivityOptions = ActivityOptions.makeSceneTransitionAnimation(MainActivity.this, sharedView, transitionName); startActivity(i, transitionActivityOptions.toBundle()); } });
如果想要保持不同版本的代碼一致, 可以使用v4包中的
ActivityCompat.startActivity
方法去啟動activity
參考
https://developer.android.google.cn/training/material/index.html
http://wiki.jikexueyuan.com/project/material-design/whatis-material-design/environment.html
https://developer.android.google.cn/training/material/index.html