要实现可折叠式的标题栏可以借助CollapsingToolbarLayout来实现。CollapsingToolbarLayout是不能单独存在的,只能作为AppBarLayout的直接子布局来使用,而AppBarLayout又必须是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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="website.dengta.drawerlayout.FruitActivity">
<android.support.design.widget.AppBarLayout
android:id="@+id/appBar"
android:layout_width="match_parent"
android:layout_height="250dp">
<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"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed"
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/fruit_image_view"
android:scaleType="centerCrop"
app:layout_collapseMode="parallax"
/>
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin">
</android.support.v7.widget.Toolbar>
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
</android.support.design.widget.CoordinatorLayout>
app:contentScrim 属性用于指定CollapsingToolbarLayout 在趋于折叠状态以及折叠之后的背泉色,其实CollapsingToolbarLayout在折叠之后就是一个普通的Toolbar, 那么背景色肯定应该是colorPrimary 了,具体的效果我们待会儿就能看到。app:layout— scrol lFlags 属性我们也是见过的,只不过之前是给Toolbar 指定的,现在也移到外面来了。其中, scroll 表示CollapsingToolbarLayout 会随着水果内容详情的滚动一起滚动, exitUntilCol lapsed 表示当CollapsingToolbarLayout 随着滚动完成折叠之后就保留在界面上,不再移出屏幕。
效果如图所示
这里定义的大多数属性我们都是见过的,就不再解释了,只有一个app:layout_collapseMode 比较陌生。它用于指定当前控件在CollapsingToolbarLayout 折叠过程中的折叠模式,其中Toolbar 指定成pin, 表示在折叠的过程中位置始终保持不变, ImageView 指定成parallax, 表示会在折叠的过程中产生一定的错位偏移,这种模式的视觉效果会非常好。
内容部分操作如下
继续操作上面的xml布局文件
<!--正文内容部分-->
<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_marginBottom="15dp"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:layout_marginTop="35dp"
app:cardCornerRadius="4dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/fruit_content_text"
android:layout_margin="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</android.support.v7.widget.CardView>
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
NestedScrollView 在此基础之上还增加了嵌套响应滚动事件的功能。由于CoordinatorLayout 本身已经可以响应滚动事件了,因此我们在它的内部就需要使用NestedScrollView 或RecyclerView这样的布局。另外,这里还通过app:layout—behavior 属性指定了一个布局行为,这和之前在Recycler View 中的用法是一模一样的。
在文章正文中加入一个悬浮的评论按钮
<!--悬浮的评论按钮-->
<android.support.design.widget.FloatingActionButton
android:layout_margin="16dp"
android:src="@drawable/comments"
app:layout_anchor="@id/appBar"
app:layout_anchorGravity="bottom|end"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
FloatingActionButton 中使用app:layout_anchor 属性指定了一个描点,我们将描点
设置为AppBarLayout, 这样悬浮按钮就会出现在水果标题栏的区域内,接着又使用app:layout_anchorGravity 属性将悬浮按钮定位在标题栏区域的右下角。
效果如图所示
代码如下
FruitActivity.java
package website.dengta.drawerlayout;
import android.content.Intent;
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);
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);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
collapsingToolbar.setTitle(fruitName);
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);
}
}
通过Intent 获取到传入的水果名和水果图片的资源id, 然后通过findViewByid() 方法拿到刚才在布局文件中定义的各个控件的实例。接着就是使用了Toolbar 的标准用法,将它作为ActionBar 显示,并启用HomeAsUp 按钮。由于HomeAsUp 按钮的默认图标就是一个返回箭头,这正是我们所期望的,因此就不用再额外设置别的图标了。
调用CollapsingToolbarLayout 的setTitle() 方法将水果名设置成当前界面的标题,然后使用Glide 加载传入的水果图片,并设置到标题栏的ImageView 上面。接着需要填充水果的内容详情,由于这只是一个示例程序,并不需要什么真实的数据,所以我使用了一个enerateFruitContent ()方法将水果名循环拼接500 次,从而生成了一个比较长的字符串,将它设置到了TextView 上面。
在onOptionsitemSelected() 方法中处理了HomeAsUp 按钮的点击事件,当点击了这个按钮时,就调用finish ()方法关闭当前的活动,从而返回上一个活动。
处理Recycler View的点击事件,让其可以进入到FruitActivity的布局中
@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 new ViewHolder(view);
}
充分利用系统状态栏空间
想要让背景图能够和系统状态栏融合,需要借助android:fitsSystemWindows 这个属性来实现。在CoordinatorLayout 、AppBarLayout 、CollapsingToolbarLayout 这种嵌套结构的布局中,将控件的android:fitsSystemWindows 属性指定成true, 就表示该控件会出现在系统状态栏里。对应到我们的程序,那就是水果标题栏中的ImageView 应该设置这个属性了。不过只给Image View 设置这个属性是没有用的,我们必须将ImageView 布局结构中的所有父布局都设置上这个属性才可以。
将android:fitsSystemWindows 属性都设置好了还是没有用的,因为还必须在程序的主题中将状态栏颜色指定成透明色才行。指定成透明色的方法很简单,在主题中将
android:statusBarColor 属性的值指定成@android:color/transparent 就可以了。