5.0之后的Android系統(tǒng),google推出了自己的移動(dòng)端設(shè)計(jì)規(guī)范怎囚,Material Design怎顾,同時(shí)sdk包中也加入了support.design包,加入了很多符合md風(fēng)格的組件怕品。這里主要講解一下CoordinatorLayout這個(gè)布局和它的使用。
什么是CoordinatorLayout
? 正如它的名字巾遭,這個(gè)布局是用來協(xié)調(diào)2個(gè)控件之間的聯(lián)動(dòng)肉康。我們使用一個(gè)圖片來說明這個(gè)布局的最終效果。

? 可以發(fā)現(xiàn)地下的視圖滑動(dòng)上去之后上面圖片所在的區(qū)域會(huì)被折疊灼舍,然后會(huì)有一個(gè)Toolbar懸停在頂部吼和。
? 下面我來實(shí)現(xiàn)以下這個(gè)效果
? 引入design包里面的組件:
compile 'com.android.support:design:25.3.1'
? 新建一個(gè)Activity和布局文件
? 布局文件如下:
<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="200dp">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsingToolbarLayout_1"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:contentScrim="@color/colorPrimary"
app:layout_scrollFlags="exitUntilCollapsed|scroll|enterAlways"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/head_img"
app:layout_collapseMode="parallax"
android:scaleType="centerCrop"
/>
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>
?
這個(gè)布局的分析如下:
最外層使用CoordinatorLayout,頂部的折疊部分使用AppBarLayout骑素,在AppBarLayout中我們加入了一個(gè)圖片和Toolbar炫乓,圖片和Toolbar需要包含在一個(gè)CollapsingToolbarLayout里面。
下方是一個(gè)用來滑動(dòng)的RecyclerView献丑。
分析一下一些默認(rèn)屬性的作用:
CollapsingToolbarLayout
app:contentScrim 折疊后Toolbar的顏色
app:layout_scrollFlags 滑動(dòng)折疊的五種效果
- scroll Child View 伴隨著滾動(dòng)事件而滾出或滾進(jìn)屏幕末捣。注意兩點(diǎn):第一點(diǎn),如果使用了其他值创橄,必定要使用這個(gè)值才能起作用箩做;第二點(diǎn):如果在這個(gè)child View前面的任何其他Child View沒有設(shè)置這個(gè)值,那么這個(gè)Child View的設(shè)置將失去作用妥畏。
- enterAlways 滾動(dòng)優(yōu)先級(jí)邦邦。比較scroll和scroll|enterAlways, 設(shè)置該屬性后安吁,向下滾動(dòng)的時(shí)候,前者優(yōu)先滾動(dòng)可滾動(dòng)的組件燃辖,后者優(yōu)先滾動(dòng)child view鬼店。
- enterAlwaysCollapsed enterAlways的附加值。這里涉及到Child View的高度和最小高度黔龟,向下滾動(dòng)時(shí)薪韩,Child View先向下滾動(dòng)最小高度值,然后Scrolling View開始滾動(dòng)捌锭,到達(dá)邊界時(shí),Child View再向下滾動(dòng)罗捎,直至顯示完全观谦。
- exitUntilCollapsed child view不完全退出屏幕,child view向上滾動(dòng)停住以后再往上滾動(dòng)滾動(dòng)組件桨菜。例如折疊后Toolbar不退出屏幕豁状,懸停在上方,然后RecyclerView的視圖向上滑動(dòng)倒得。
- snap child view要么顯示要么全部退出屏幕泻红。
child view中的
app:layout_collapseMode 折疊的模式,有三種霞掺。其中none表示沒有效果谊路。其余2個(gè)分別是
- pin 固定模式,折疊后固定在頂端菩彬。
- parallax 視差模式缠劝,在折疊的時(shí)候會(huì)有個(gè)視差折疊的效果。
####### 可滾動(dòng)的控件
app:layout_behavior 行為骗灶,指定在scroll view上面的惨恭。這里我們?cè)O(shè)置為
app:layout_behavior="@string/appbar_scrolling_view_behavior"
這個(gè)指的是AppBarLayout中的內(nèi)部類ScrollingViewBehavior,這個(gè)用來指定RecyclerView和AppBarLayout之間的聯(lián)動(dòng)耙旦。查看源碼
@Override
public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {
// We depend on any AppBarLayouts
return dependency instanceof AppBarLayout;
}
@Override
public boolean onDependentViewChanged(CoordinatorLayout parent, View child,
View dependency) {
offsetChildAsNeeded(parent, child, dependency);
return false;
}
這段代碼的含義分別是指定滑動(dòng)行為根據(jù)AppBarLayout決定脱羡。在onDependentViewChanged方法中我們指定了移動(dòng)的方式。具體代碼在這不贅述免都。
這個(gè)時(shí)候我們的基本效果就實(shí)現(xiàn)了锉罐。可見這個(gè)MD控件的強(qiáng)大琴昆。當(dāng)然它的具體實(shí)現(xiàn)也是很復(fù)雜的氓鄙。
常見問題
同時(shí)我們可以發(fā)現(xiàn)Toolbar的行為是根據(jù)CollapsingToolbarLayout來控制的。
設(shè)置Toolbar的title业舍,會(huì)發(fā)現(xiàn)效果沒有達(dá)到預(yù)期抖拦。title不會(huì)隨著滑動(dòng)縮放升酣。
那么問題來了,我們?nèi)绾卧O(shè)置Toolbar的標(biāo)題呢态罪?
Toolbar的標(biāo)題我們可以如下設(shè)置:
mCollapsingToolbarLayout.setTitle("標(biāo)題");
setSupportActionBar(mToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
現(xiàn)在問題又來了噩茄,正常我們不設(shè)置的時(shí)候,會(huì)發(fā)現(xiàn)有一個(gè)md規(guī)范控件自帶的效果复颈,標(biāo)題會(huì)在滾動(dòng)過程中上下移動(dòng)并且縮放大小的效果绩聘。有時(shí)候我們并不想把標(biāo)題顯示在下發(fā),這個(gè)時(shí)候應(yīng)該怎么辦呢耗啦?
可以在style文件中設(shè)置
<style name="collapsing_toolbar_text_size">
<item name="android:textSize">0sp</item>
</style>
在Activity中設(shè)置
mCollapsingToolbarLayout
.setExpandedTitleTextAppearance(R.style.collapsing_toolbar_text_size);
這句代碼的含義是設(shè)置滑動(dòng)后的標(biāo)題字體大小凿菩,我們?cè)O(shè)置為0sp,就不會(huì)有任何顯示了帜讲。
附上最后Activity里面的代碼衅谷,也可以參考我在github上的demo代碼
public class CoordinatorTestActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private List<String> data = new ArrayList<>();
private CollapsingToolbarLayout collapsingToolbarLayout;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_coordinator);
recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
initData();
MyAdapter adapter = new MyAdapter(this,data);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
collapsingToolbarLayout = (CollapsingToolbarLayout) findViewById(R.id.collapsingToolbarLayout_1);
collapsingToolbarLayout.setTitle("標(biāo)題");
collapsingToolbarLayout.setExpandedTitleTextAppearance(R.style.collapsing_toolbar_text_size);
}
private void initData() {
for (int i = 0;i < 20;i++) {
data.add("str"+i);
}
}
class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyHolder> {
private Context mContext;
private List<String> mData;
public MyAdapter(Context context, List<String> data) {
mContext = context;
mData = data;
}
@Override
public MyHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new MyHolder(LayoutInflater.from(mContext).inflate(android.R.layout.simple_list_item_1, parent, false));
}
@Override
public void onBindViewHolder(MyHolder holder, int position) {
String text = mData.get(position);
holder.tv.setText(text);
}
@Override
public int getItemCount() {
return mData.size();
}
class MyHolder extends RecyclerView.ViewHolder{
TextView tv;
public MyHolder(View itemView) {
super(itemView);
tv = (TextView) itemView.findViewById(android.R.id.text1);
}
}
}
}