1. 程式人生 > >android新特性:使用CollapsingToolbarLayout實現摺疊效果及問題解決

android新特性:使用CollapsingToolbarLayout實現摺疊效果及問題解決

CollapsingToolbarLayout作用是提供了一個可以摺疊的Toolbar,它繼承至FrameLayout,給它設定layout_scrollFlags就可以實現摺疊效果!

  • 效果展示:

這裡寫圖片描述

  • 引入相對使用的庫

    compile 'com.android.support:appcompat-v7:23.3.0'
    compile 'com.android.support:design:23.3.0'
    compile 'com.android.support:support-v4:23.3.0'

    compile 'com.jakewharton:butterknife:7.0.1'
//沉浸狀態列 compile 'com.jaeger.statusbaruitl:library:1.1.1' //glide圖片載入 compile 'jp.wasabeef:glide-transformations:2.0.1'
  • 首先檢視佈局:
<?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:id="@+id/coordinator_Layout" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="cn.hnshangyu.coordinatorlayout.MainActivity">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar_layout" 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="300dp" app:collapsedTitleTextAppearance="@style/ToolBarTitleText" app:contentScrim="#46a8ba" app:expandedTitleMarginEnd="48dp" app:expandedTitleMarginStart="48dp" app:expandedTitleTextAppearance="@style/transparentText" app:layout_scrollFlags="scroll|exitUntilCollapsed"> <!--設定layout_scrollFlags保證CollapsingToolbarLayout能滾動--> <!--app:layout_scrollFlags="scroll|exitUntilCollapsed"--> <LinearLayout android:id="@+id/head_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" app:layout_collapseMode="pin" app:layout_collapseParallaxMultiplier="0.7"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="50dp" android:padding="20dp"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentLeft="true" android:layout_centerVertical="true" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="黃曉果" android:textColor="#ffffff" android:textSize="16sp" android:textStyle="bold" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:lineSpacingMultiplier="1.3" android:text="我很喜歡你,像你媽打你,沒有道理;\n像放出的屁,身不由己。" android:textColor="#ffffff" android:textSize="13sp" android:textStyle="bold" /> </LinearLayout> <ImageView android:id="@+id/head_iv" android:layout_width="50dp" android:layout_height="50dp" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:scaleType="centerCrop" /> </RelativeLayout> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:layout_marginRight="40dp" android:ellipsize="end" android:lineSpacingMultiplier="1.3" android:maxLines="2" android:text="萌逼的臉是來親的,帥逼的臉是用來看的,逗逼的臉是用來笑的,傻逼的臉是用來哭的,偏偏就你的臉是用來踢的。" android:textColor="#ffffff" android:textSize="12sp" /> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:padding="20dp"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:layout_marginRight="40dp" android:ellipsize="end" android:lineSpacingMultiplier="1.3" android:maxLines="2" android:text="今天的你對我愛搭不理,\n明天的我還來找你。" android:textColor="#ffffff" android:textSize="12sp" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:background="@drawable/setting_bg" android:paddingBottom="3dp" android:paddingLeft="6dp" android:paddingRight="6dp" android:paddingTop="3dp" android:text="設定" android:textColor="#ffffff" android:textSize="12sp" /> </RelativeLayout> </LinearLayout> <!--Toolbar放在下面不然會被擋住--> <android.support.v7.widget.Toolbar android:id="@+id/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.TabLayout android:id="@+id/toolbar_tab" android:layout_width="match_parent" android:layout_height="48dp" android:layout_gravity="bottom" android:background="#ffffff" android:fillViewport="false" app:layout_scrollFlags="scroll" app:tabIndicatorColor="#0835f8" app:tabIndicatorHeight="2.0dp" app:tabSelectedTextColor="#0835f8" app:tabTextColor="#151515"> <!--指示器顏色--> <!-- app:tabIndicatorColor="#0835f8"--> <!--tab條目中字型顏色--> <!--app:tabSelectedTextColor="#0835f8"--> <android.support.design.widget.TabItem android:layout_width="match_parent" android:layout_height="match_parent" android:icon="@drawable/tab_selector" /> <!--佈局選擇器--> <!--android:icon="@drawable/tab_selector"--> <android.support.design.widget.TabItem android:layout_width="match_parent" android:layout_height="match_parent" android:text="頭條" /> <android.support.design.widget.TabItem android:layout_width="match_parent" android:layout_height="match_parent" android:text="社交" /> <android.support.design.widget.TabItem android:layout_width="match_parent" android:layout_height="match_parent" android:text="直播" /> <android.support.design.widget.TabItem android:layout_width="match_parent" android:layout_height="match_parent" android:text="約嗎" /> </android.support.design.widget.TabLayout> </android.support.design.widget.AppBarLayout> <android.support.v4.widget.NestedScrollView android:id="@+id/nsv" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true" android:scrollbars="none" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <android.support.v4.view.ViewPager android:id="@+id/main_vp_container" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> </android.support.v4.widget.NestedScrollView> <!--在CoordinatorLayout中只要是能滑動控制元件的都需要設定layout_behavior--> <!--app:layout_behavior="@string/appbar_scrolling_view_behavior"--> </android.support.design.widget.CoordinatorLayout>
內部特殊的屬性都有相對註釋:




    我們在CollapsingToolbarLayout中設定了一個LinearLayout和一個Toolbar。
    並把這個CollapsingToolbarLayout放到AppBarLayout中作為一個整體。

1、在CollapsingToolbarLayout中:

我們設定了layout_scrollFlags:關於它的值我這裡再說一下:
scroll - 想滾動就必須設定這個。

enterAlways - 實現quick return效果, 當向下移動時,立即顯示View(比如Toolbar)。

exitUntilCollapsed - 向上滾動時收縮View,但可以固定Toolbar一直在上面。

enterAlwaysCollapsed - 當你的View已經設定minHeight屬性又使用此標誌時,
你的View只能以最小高度進入,只有當滾動檢視到達頂部時才擴大到完整高度。

其中還設定了一些屬性,簡要說明一下:

contentScrim - 設定當完全CollapsingToolbarLayout摺疊(收縮)後的背景顏色。

expandedTitleMarginStart - 設定擴張時候(還沒有收縮時)title向左填充的距離。

layout_collapseMode (摺疊模式) - 有兩個值:

pin -  設定為這個模式時,當CollapsingToolbarLayout完全收縮後,Toolbar還可以保留在螢幕上。

parallax - 設定為這個模式時,在內容滾動時,CollapsingToolbarLayout中的View(比如ImageView)也可以同時滾動,
實現視差滾動效果,通常和layout_collapseParallaxMultiplier(設定視差因子)搭配使用。

layout_collapseParallaxMultiplier(視差因子) - 設定視差滾動因子,值為:0~1。 
  • 這裡使用到了部分樣式:
 <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>

    <style name="transparentText" parent="TextAppearance.AppCompat.Small">
        <item name="android:textColor">#00000000</item>
    </style>

    <style name="ToolBarTitleText" parent="TextAppearance.AppCompat.Medium">
        <item name="android:textColor">#ffffffff</item>
        <item name="android:textSize">16sp</item>
        <item name="android:textStyle">bold</item>

    </style>
  • 然後就是MainActivity中的程式碼設定了:
package cn.hnshangyu.coordinatorlayout;

import android.annotation.TargetApi;
import android.os.Build;
import android.os.Bundle;
import android.support.design.widget.AppBarLayout;
import android.support.design.widget.CollapsingToolbarLayout;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.support.v4.widget.NestedScrollView;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.request.animation.GlideAnimation;
import com.bumptech.glide.request.target.SimpleTarget;
import com.jaeger.library.StatusBarUtil;

import butterknife.Bind;
import butterknife.ButterKnife;
import cn.hnshangyu.coordinatorlayout.adapter.ViewPagerAdapter;
import jp.wasabeef.glide.transformations.BlurTransformation;
import jp.wasabeef.glide.transformations.RoundedCornersTransformation;

public class MainActivity extends AppCompatActivity {

    /**
     * ScrollView上半部分
     */
    @Bind(R.id.toolbar)
    Toolbar toolbar;
    /**
     * 頭像
     */
    @Bind(R.id.head_iv)
    ImageView headIv;
    /**
     * CollapsingToolbarLayout內部顯示內容部分
     */
    @Bind(R.id.head_layout)
    LinearLayout headLayout;
    /**
     * tab分類條目
     */
    @Bind(R.id.toolbar_tab)
    TabLayout toolbarTab;

    @Bind(R.id.app_bar_layout)
    AppBarLayout appBarLayout;
    /**
     * 摺疊部分
     */
    @Bind(R.id.collapsingToolbarLayout)
    CollapsingToolbarLayout collapsingToolbarLayout;
    /**
     * ViewPager
     */
    @Bind(R.id.main_vp_container)
    ViewPager mViewPager;
    /**
     * ScrollView
     */
    @Bind(R.id.nsv)
    NestedScrollView nsv;
    /**
     * 整個佈局
     */
    @Bind(R.id.coordinator_Layout)
    CoordinatorLayout coordinatorLayout;

    private ViewPagerAdapter myPagerAdapter;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        //用toolBar替換ActionBar
        setToolBarReplaceActionBar();

        //把title設定到CollapsingToolbarLayout上
        setTitleToCollapsingToolbarLayout();

        // 給viewpager設定介面卡
        setViewPagerAdapter();

        //tablayout和viewpager建立聯絡
        setTabBindViewPager();

        //設定毛玻璃效果和沉浸狀態列
        loadBlurAndSetStatusBar();

        //設定頭像
        Glide.with(this).load(R.mipmap.bg).bitmapTransform(new RoundedCornersTransformation(this,
                90, 0)).into(headIv);
    }


    /**
     * 用toolBar替換ActionBar
     */
    private void setToolBarReplaceActionBar() {
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        toolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, "返回", Toast.LENGTH_LONG).show();
                // onBackPressed();//結束程式
            }
        });
    }

    /**
     * 使用CollapsingToolbarLayout必須把title設定到CollapsingToolbarLayout上,
     * 設定到Toolbar上則不會顯示
     */
    private void setTitleToCollapsingToolbarLayout() {
        appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
            @Override
            public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
                if (verticalOffset <= -headLayout.getHeight() / 2) {
                    collapsingToolbarLayout.setTitle("黃曉果");
                    //使用下面兩個CollapsingToolbarLayout的方法設定展開透明->摺疊時你想要的顏色
                    collapsingToolbarLayout.setExpandedTitleColor(getResources().getColor(android.R.color.transparent));
                    collapsingToolbarLayout.setCollapsedTitleTextColor(getResources().getColor(R.color.colorAccent));
                } else {
                    collapsingToolbarLayout.setTitle("");
                }
            }
        });
    }

    /**
     * 給viewpager設定介面卡
     */
    private void setViewPagerAdapter() {
        myPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager(), this);
        mViewPager.setAdapter(myPagerAdapter);
    }

    /**
     * tablayout和viewpager建立聯絡
     */
    private void setTabBindViewPager() {
        //tablayout和viewpager建立聯絡方式一:tab與viewpager之間的相互繫結
        mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener
                (toolbarTab));
        toolbarTab.setOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener
                (mViewPager));

        //tablayout和viewpager建立聯絡方式二: 使用此方法Tablayout中的TabItem設定icon無效
        // (android:icon="@drawable/tab_selector" )只能使用 android:text="分享"
        //  toolbarTab.setupWithViewPager(mViewPager);
    }


    /**
     * 設定毛玻璃效果和沉浸狀態列
     */
    private void loadBlurAndSetStatusBar() {
        //目的是讓狀態列半透明
//         StatusBarUtil.setTranslucent(MainActivity.this, StatusBarUtil.DEFAULT_STATUS_BAR_ALPHA);
        //目的是讓狀態列全透明
        StatusBarUtil.setTransparent(MainActivity.this);

        Glide.with(this).load(R.mipmap.bg).bitmapTransform(new BlurTransformation(this, 100))
                .into(new SimpleTarget<GlideDrawable>() {
                    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
                    @Override
                    public void onResourceReady(GlideDrawable resource, GlideAnimation<? super
                            GlideDrawable> glideAnimation) {
                        headLayout.setBackground(resource);
                        coordinatorLayout.setBackground(resource);
                    }
                });

        Glide.with(this).load(R.mipmap.bg).bitmapTransform(new BlurTransformation(this, 100))
                .into(new SimpleTarget<GlideDrawable>() {
                    @Override
                    public void onResourceReady(GlideDrawable resource, GlideAnimation<? super
                            GlideDrawable> glideAnimation) {
                        collapsingToolbarLayout.setContentScrim(resource);
                    }
                });
    }

    //在ActionBar設定條目
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        String msg = "";
        switch (item.getItemId()) {
            case R.id.webview:
                msg += "部落格跳轉";
                break;
            case R.id.weibo:
                msg += "微博跳轉";
                break;
            case R.id.action_settings:
                msg += "設定";
                break;
        }
        if (!msg.equals("")) {
            Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
        }
        return super.onOptionsItemSelected(item);
    }

}
程式碼內部有詳細註釋



【注】:使用CollapsingToolbarLayout時必須把title設定到CollapsingToolbarLayout上,設定到Toolbar上不會顯示。
即:
mCollapsingToolbarLayout.setTitle(" ");

該變title的字型顏色:

擴張時候的title顏色:mCollapsingToolbarLayout.setExpandedTitleColor();

收縮後在Toolbar上顯示時的title的顏色:mCollapsingToolbarLayout.setCollapsedTitleTextColor();

這個顏色的過度變化其實CollapsingToolbarLayout已經幫我們做好,它會自動的過度
  • ViewPagerAdapter:
package cn.hnshangyu.coordinatorlayout.adapter;

import android.content.Context;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

import cn.hnshangyu.coordinatorlayout.fragment.PageFragment;

public class ViewPagerAdapter extends FragmentPagerAdapter {

    final int PAGE_COUNT = 5;
    private String tabTitles[] = new String[]{"", "頭條", "社交", "直播", "約嗎"};
    private Context context;

    public ViewPagerAdapter(FragmentManager fm, Context context) {
        super(fm);
        this.context = context;
    }

    @Override
    public Fragment getItem(int position) {
        return PageFragment.newInstance(position + 1);
    }

    @Override
    public int getCount() {
        return PAGE_COUNT;
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return tabTitles[position];
    }
}
  • PageFragment:
package cn.hnshangyu.coordinatorlayout.fragment;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.List;

import butterknife.Bind;
import butterknife.ButterKnife;
import cn.hnshangyu.coordinatorlayout.R;
import cn.hnshangyu.coordinatorlayout.adapter.MyAdapter;


public class PageFragment extends Fragment {
    public static final String ARG_PAGE = "PAGE_NUM";
    @Bind(R.id.recyclerView)
    RecyclerView recyclerView;
    private int mPage;

    public static PageFragment newInstance(int page) {
        Bundle args = new Bundle();
        args.putInt(ARG_PAGE, page);
        PageFragment pageFragment = new PageFragment();
        pageFragment.setArguments(args);
        return pageFragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mPage = getArguments().getInt(ARG_PAGE);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
            savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_page, null);
        ButterKnife.bind(this, view);
        // 建立一個線性佈局管理器

        LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());

        // 設定佈局管理器

        recyclerView.setLayoutManager(layoutManager);

        List<String> list = new ArrayList<String>();
        for (int i = 0; i < 100; i++) {
            list.add("黃曉果" + i);
        }
        recyclerView.setAdapter(new MyAdapter(list));

        return view;
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        ButterKnife.unbind(this);
    }
}
  • MyAdapter:
package cn.hnshangyu.coordinatorlayout.adapter;

import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import java.util.List;


public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    // 資料集
    private List<String> mDataset;

    public MyAdapter(List<String> dataset) {
        super();
        mDataset = dataset;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {

        // 建立一個View,簡單起見直接使用系統提供的佈局,就是一個TextView

        View view = View.inflate(viewGroup.getContext(), android.R.layout.simple_list_item_1, null);

        return new ViewHolder(view);

    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int i) {

        // 繫結資料到ViewHolder上

        holder.mTextView.setText(mDataset.get(i));

    }

    @Override
    public int getItemCount() {

        return mDataset.size();

    }

    class ViewHolder extends RecyclerView.ViewHolder {

        public TextView mTextView;

        public ViewHolder(View itemView) {

            super(itemView);

            mTextView = (TextView) itemView;

        }

    }

}

  • menu_main:
<?xml version="1.0" encoding="utf-8"?>
<menu 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"
    tools:context=".MainActivity">

    <item
        android:id="@+id/webview"
        android:icon="@mipmap/icon_blog"
        android:orderInCategory="80"
        android:title="web"
        app:showAsAction="ifRoom" />

    <item
        android:id="@+id/weibo"
        android:icon="@mipmap/icon_weibo"
        android:orderInCategory="90"
        android:title="weibo"
        app:showAsAction="ifRoom" />

    <item
        android:id="@+id/action_settings"
        android:orderInCategory="100"
        android:title="設定"
        app:showAsAction="never" />
</menu>
  • 問題一:

    異常資訊:

Caused by: java.lang.IllegalStateException: This Activity already has an action bar supplied by the window decor. Do not request Window.FEATURE_SUPPORT_ACTION_BAR and set windowActionBar to false in your theme to use a Toolbar instead.

問題原因:

當在activity中呼叫了setSupportActionBar(toolbar); 

這裡寫圖片描述

同時,AndroidManifest.xml 對應的Activity標籤的android:theme為:

android:theme="@style/AppTheme" >

這裡寫圖片描述

且,style資原始檔中的parent為

parent="Theme.AppCompat.Light.DarkActionBar

這裡寫圖片描述

就會報這個異常。

問題分析:

Using Theme.AppCompat.Light tells Android that you want the framework to provide an ActionBar for you. However, you are creating your own ActionBar (a Toolbar), so you are giving the framework mixed signals as to where you want the ActionBar to come from.

解決方法:

1、在style配置檔案中加上

<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>

或者,將parent改為

parent="Theme.AppCompat.Light.NoActionBar"

2、在AndroidManifest.xml 對應的Activity標籤的android:theme引用該style中的修改的主題

  • 問題二:

問題:

    當成功執行程式後如果在6.0及以上的機子上執行會出現頂部狀態列顯示系統顏色,這裡是   coordinatorLayout.setBackground(resource);這行程式碼無效的情況

解決方式:

將編譯版本,修改到23且 compile 'com.jaeger.statusbaruitl:library:1.1.1'版本為1.1.1,如果設定為現在最高版本1.3.5會出現,編譯不通過!

 compileSdkVersion 23
buildToolsVersion "23.0.3"
defaultConfig {
    applicationId "cn.hnshangyu.coordinatorlayout"
    minSdkVersion 15
    targetSdkVersion 23
    versionCode 1
    versionName "1.0"
    renderscriptTargetApi 19
    renderscriptSupportModeEnabled true
}

好了,到這裡就結束了,歡迎各位指教…….