1.CollapsingToolBarLayout
它是一个作用于ToolBar基础之上的布局,可以让ToolBar更丰富,不仅仅是展示一个标题栏,而是能够实现非常华丽的效果。但是CollapsingToolBarLayout不能单独存在,它必须作为AppBarLayout的直接子布局来使用,而AppBarLayout又是CoordinatorLayout的子布局。
1.1首先新建一个布局activity_fruit.xml,它有两部分,一个是水果标题栏,一个是水果内容部分,首先实现标题栏部分,这里用CoordinatorLayout作为最外层布局:
<?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:fitsSystemWindows="true"> <android.support.design.widget.AppBarLayout android:id="@+id/appBar" android:layout_width="match_parent" android:layout_height="250dp" android:fitsSystemWindows="true"> <android.support.design.widget.CollapsingToolbarLayout<!--在里面主要是定义标题栏的具体内容,下面定义了一个ImageView和ToolBae,
表示高级标题栏的内容--> android:id="@+id/collapsing_toolbar" android:layout_width="match_parent" android:layout_height="match_parent" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:fitsSystemWindows="true" app:contentScrim="?attr/colorPrimary"<!--指定CollapsingToolbarLayout趋于折叠状态以及折叠之后的背景色,其实它折叠之后就是一个
普通的ToolBae,背景色即为colorPrimary--> app:layout_scrollFlags="scroll|exitUntilCollapsed"><!--指定随变化的效果,scroll表示CollapsingToolbarLayout随着水果内容
详情的滚动一起滚动,exitUntilCollapsed表示CollapsingToolbarLayout随着滚动完成折叠之后就保留在界面上,不再移出屏幕。--> <ImageView android:id="@+id/fruit_image_view" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:fitsSystemWindows="true" app:layout_collapseMode="parallax" /><!--指定当前控件在CoolapsingToolBarLayout折叠过程中的折叠模式,其中ToolBar指定成
pin表示在折叠过程中位置始终保持不变;指定成为parallax表示会在折叠过程中产生一定的错位偏移,这种模式的视觉效果会非常好--> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin" /> </android.support.design.widget.CollapsingToolbarLayout> </android.support.design.widget.AppBarLayout> <android.support.v4.widget.NestedScrollView<!--在这里面编写的是水果内容详情部分,指定为NestedScrollView,注意它是和AppBarLayout平级
的,NestedScrollView和ScrollView类似,允许使用滚动的方式查看屏幕以外的内容,但它还增加了嵌套响应滚动事件的功能。由于CoordinatorLayout本身可以
响应滚动事件,因此我们需要在它的内部使用NestedScrollView和RecyclerView这样的能响应的布局,所以用能响应的NestedScrollView而不是ScrollView。 android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"><!--声明布局的行为移到内部的NestedScrollView中。--> <LinearLayout<!--不管是NestedScrollView还是ScrollView,它的直接子布局只可以有一个,所以先嵌套一个LinearLayout再放入具体内容--> android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="15dp" android:layout_marginLeft="15dp" android:layout_marginRight="15dp" android:layout_marginTop="35dp" app:cardCornerRadius="4dp"> <TextView android:id="@+id/fruit_content_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="10dp" /> </android.support.v7.widget.CardView> </LinearLayout> </android.support.v4.widget.NestedScrollView> <android.support.design.widget.FloatingActionButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="16dp" android:src="@drawable/ic_comment" app:layout_anchor="@id/appBar"<!--指定了一个锚点,这样它的它的位置会相对于指定的id为appBar中--> app:layout_anchorGravity="bottom|end" /><!--表示其位置在id为appBar的右下方--> </android.support.design.widget.CoordinatorLayout>2.编写一个活动FruitActivity.java,用于展示在MainActivity.java中点击了具体的水果之后转到的内容详情:
package com.example.wanglunhui.materialdesigntest; import android.content.Intent; import android.graphics.Color; import android.support.design.widget.CollapsingToolbarLayout; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.Toolbar; import android.view.MenuItem; import android.widget.ImageView; import android.widget.TextView; import com.bumptech.glide.Glide; public class FruitActivity extends AppCompatActivity { public static final String FRUIT_NAME = "fruit_name"; public static final String FRUIT_IMAGE_ID = "fruit_image_id"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_fruit); Intent intent = getIntent(); String fruitName = intent.getStringExtra(FRUIT_NAME);//水果名 int fruitImageId = intent.getIntExtra(FRUIT_IMAGE_ID, 0);//水果id Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); CollapsingToolbarLayout collapsingToolbar = (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar); ImageView fruitImageView = (ImageView) findViewById(R.id.fruit_image_view); TextView fruitContentText = (TextView) findViewById(R.id.fruit_content_text); setSupportActionBar(toolbar);//将ToolBar最为ActionBar使用,所以下面的ActionBar即为ToolBar ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setDisplayHomeAsUpEnabled(true);//启用HomeUpAs按钮,即显示返回上一个活动的左箭头按钮,点击时相当于Finish()操作返回
上一个活动 } collapsingToolbar.setTitle(fruitName);//将水果内容设置为CollapsingToolbarLayout标题 Glide.with(this).load(fruitImageId).into(fruitImageView);//显示图片 String fruitContent = generateFruitContent(fruitName); fruitContentText.setText(fruitContent);//设置水果内容详情 } private String generateFruitContent(String fruitName) { StringBuilder fruitContent = new StringBuilder(); for (int i = 0; i < 500; i++) { fruitContent.append(fruitName); } return fruitContent.toString(); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: finish(); return true; } return super.onOptionsItemSelected(item); } }3.最后还要修改Adapter的点击Holder的点击事件才能进入FruitActivity中:
package com.example.wanglunhui.materialdesigntest; import android.content.Context; import android.content.Intent; import android.support.v7.widget.CardView; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import com.bumptech.glide.Glide; import java.util.List; public class FruitAdapter extends RecyclerView.Adapter<FruitAdapter.ViewHolder>{ private Context mContext; private List<Fruit> mFruitList; static class ViewHolder extends RecyclerView.ViewHolder { CardView cardView; ImageView fruitImage; TextView fruitName; public ViewHolder(View view) { super(view); cardView = (CardView) view; fruitImage = (ImageView) view.findViewById(R.id.fruit_image); fruitName = (TextView) view.findViewById(R.id.fruit_name); } } public FruitAdapter(List<Fruit> fruitList) { mFruitList = fruitList; } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (mContext == null) { mContext = parent.getContext(); } View view = LayoutInflater.from(mContext).inflate(R.layout.fruit_item, parent, false); final ViewHolder holder= new ViewHolder(view); holder.cardView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int position=holder.getAdapterPosition(); Fruit fruit=mFruitList.get(position); Intent intent=new Intent(mContext,FruitActivity.class); intent.putExtra(FruitActivity.FRUIT_NAME,fruit.getName()); intent.putExtra(FruitActivity.FRUIT_IMAGE_ID,fruit.getImageId()); mContext.startActivity(intent); } }); return holder; } @Override public void onBindViewHolder(ViewHolder holder, int position) { Fruit fruit = mFruitList.get(position); holder.fruitName.setText(fruit.getName()); Glide.with(mContext).load(fruit.getImageId()).into(holder.fruitImage); } @Override public int getItemCount() { return mFruitList.size(); } }
2.充分利用系统状态栏空间:
上面的运行的时候你会发现水果的背景图片会和系统状态栏不搭配,如果我呢吧能将背景图和状态栏融合在一起就更好了。要想将二者融合,需要用到android:
fitsSystemWindows这个属性来实现,在CoordinatorLayout、AppBarLayout和CollapsingToolbarLayout中将其ndroid:fitsSystemWindows设置为true。
对应于我们的程序就是ImageView设置该属性,不过单独给它设置这个属性没用,还必须设置它的所有父布局的这个属性才行,修改activity_main.xml:
<?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:fitsSystemWindows="true"> <android.support.design.widget.AppBarLayout android:id="@+id/appBar" android:layout_width="match_parent" android:layout_height="250dp" android:fitsSystemWindows="true"> <android.support.design.widget.CollapsingToolbarLayout android:id="@+id/collapsing_toolbar" android:layout_width="match_parent" android:layout_height="match_parent" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:fitsSystemWindows="true" app:contentScrim="?attr/colorPrimary" app:layout_scrollFlags="scroll|exitUntilCollapsed"> <ImageView android:id="@+id/fruit_image_view" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" android:fitsSystemWindows="true" app:layout_collapseMode="parallax" /> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_collapseMode="pin" /> </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"> <LinearLayout android:orientation="vertical" android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.v7.widget.CardView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="15dp" android:layout_marginLeft="15dp" android:layout_marginRight="15dp" android:layout_marginTop="35dp" app:cardCornerRadius="4dp"> <TextView android:id="@+id/fruit_content_text" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="10dp" /> </android.support.v7.widget.CardView> </LinearLayout> </android.support.v4.widget.NestedScrollView> <android.support.design.widget.FloatingActionButton android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="16dp" android:src="@drawable/ic_comment" app:layout_anchor="@id/appBar" app:layout_anchorGravity="bottom|end" /> </android.support.design.widget.CoordinatorLayout>但是设置好了这个属性后还是没用,我们还需将程序中状态栏的颜色指定成透明色才行。很简单,只需将android:statusBarColor设置成@android:color/
transparent即可,但是android:statusBarColor在API21才有,所以在res下新建一个values-v21目录,在里面新建一个styles.xml文件:
<?xml version="1.0" encoding="utf-8"?> <resources> <style name="FruitActivityTheme" parent="AppTheme"> <item name="android:statusBarColor">@android:color/transparent</item><!--将其状态栏的颜色指定为透明色--> </style> </resources>这里我们定义了一个主题,它专门给FruitActivity使用的,继承了AppTheme主题的内容。
但是Android 5.0之前的系统无法识别FruitActivityTheme这个主题,所以还需对values/styles.xml进行修改(注意不是对values-v21下面的修改):
<resources> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style> <style name="FruitActivityTheme" parent="AppTheme"> </style> </resources>这里也定义了一个FruitActivityTheme主题,而且也继承自AppTheme,但是里面没有为状态栏指定颜色,因为这是对于Andorid 5.0之前的系统,所以此处
什么都不用做。
最后我们让FruitActivity使用这个主题:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.wanglunhui.materialdesigntest"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity" android:label="修改后的名字"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".FruitActivity" android:theme="@style/FruitActivityTheme"/> </application> </manifest>