CoordinatorLayout嵌套AppBarLayout的使用

1,288 阅读4分钟

这是我参与11月更文挑战的第19天,活动详情查看:2021最后一次更文挑战

实现的效果图:

coordinator

要实现这种联动的效果图,就需要使用CoordinatorLayout,这是一个专门为联动而生的控件。在这种效果图中,我们先来学习下TabLayout的使用。

一、TabLayout的基本使用

### 1. TabLayout的声明。
public class TabLayout extends HorizontalScrollView

可以看到是继承HorizontalScrollView而开发的一个控件。它就是用来实现我们的顶部Tab页。

2. 常用属性。

  • app:tabIndicatorColor:Tab页指示器的颜色
  • app:tabSelectedTextColor:Tab页选中时的颜色
  • app:tabTextColor:Tab页上文本的颜色
  • app:tabMode:Tab页的展示形式,有两种形式:MODE_FIXED、MODE_SCROLLABLE。Fixed是填充模式,也就是默认模式,表示TabLayout不可滚动,其宽度有一个最大值,所有的Tab则会挤在这个宽度中。MODE_SCROLLABLE是可以滚动的,不会拥挤的排在一起。

3. 基本使用:

TabLayout的使用,需要添加Tab页进行。这里的Tab类是TabLayout的一个静态内部类,并且其构造方法是包内可访问的,也就是说你无法在外部构造其实例,只能通过TabLayout的newTab方法。

4. 简单使用:

	tabLayout = (TabLayout) findViewById(R.id.tabs);

    TabLayout.Tab tabFirst = tabLayout.newTab();
    tabFirst.setText("TabFirst");
    tabLayout.addTab(tabFirst);

    TabLayout.Tab tabSecond = tabLayout.newTab();
    tabSecond.setText("tabSecond");
    tabLayout.addTab(tabSecond);

    TabLayout.Tab tabThird = tabLayout.newTab();
    tabThird.setText("tabThird");
    tabLayout.addTab(tabThird);

效果图: mobile_tablayout_normal

virtur_easy_test

一个是在我手机真机上的效果,一个是在模拟器上的效果,同样版本的api17,不知道为什么效果差别如此之大。

#####5、TabLayout结合ViewPager的使用 如果能将TabLayout与ViewPager绑定那效果美的让人难以想象,在也不用那么复杂处理Indicator了。TabLayout中已经给我们提供setupWithViewPager方法让我们来绑定了。

(1)、先来看布局文件:

	<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" android:fitsSystemWindows="true"
	    tools:context=".MainActivity">
	
	    <android.support.design.widget.AppBarLayout
	        android:layout_height="wrap_content"
	        android:layout_width="match_parent"
	        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
	
	        <android.support.v7.widget.Toolbar
	            android:id="@+id/toolbar"
	            android:layout_width="match_parent"
	            android:layout_height="?attr/actionBarSize"
	            android:background="?attr/colorPrimary"
	            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
	            app:layout_scrollFlags="scroll|enterAlways"/>
	        <android.support.design.widget.TabLayout
	            android:id="@+id/tabs"
	            android:layout_width="match_parent"
	            android:layout_height="wrap_content"
	            app:tabIndicatorColor="#FF0000"
	            app:tabSelectedTextColor="#00FF00"
	            app:tabTextColor="#FFFFFF"
	            app:tabMode="fixed"/>
	    </android.support.design.widget.AppBarLayout>
	
	    <android.support.v4.view.ViewPager
	        android:id="@+id/viewPager"
	        android:layout_height="match_parent"
	        android:layout_width="match_parent"
	        app:layout_behavior="@string/appbar_scrolling_view_behavior"
	        />
	
	    <android.support.design.widget.FloatingActionButton android:id="@+id/fab"
	        android:layout_width="wrap_content" android:layout_height="wrap_content"
	        android:layout_gravity="bottom|end" android:layout_margin="@dimen/fab_margin"
	        android:src="@android:drawable/ic_dialog_email"
	        app:borderWidth="0dp"/>
	
	</android.support.design.widget.CoordinatorLayout>

(2)、在MainActivity中进行处理。

	public class MainActivity extends AppCompatActivity {
	    private ViewPager viewPager;
	    private TabLayout tabLayout;
	    @Override
	    protected void onCreate(Bundle savedInstanceState) {
	        super.onCreate(savedInstanceState);
	        setContentView(R.layout.activity_main);
	        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
	        setSupportActionBar(toolbar);
	        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
	        fab.setOnClickListener(new View.OnClickListener() {
	            @Override
	            public void onClick(View view) {
	                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
	                        .setAction("Action", null).show();
	            }
	        });
	
	        viewPager = (ViewPager) findViewById(R.id.viewPager);
	        viewPager.setAdapter(new PagerAdapter() {
	
	            @Override
	            public int getCount() {
	                return 3;
	            }
	
	            @Override
	            public boolean isViewFromObject(View view, Object object) {
	                return view == object;
	            }
	
	            @Override
	            public Object instantiateItem(ViewGroup container, int position) {
	                container.addView(new ListViewLayout(getApplication()), position);
	                return container.getChildAt(position);
	            }
	
	            @Override
	            public void destroyItem(ViewGroup container, int position, Object object) {
	                container.removeViewAt(position);
	            }
	        });
	        initTabLayout();
	    }
	
	    private void initTabLayout(){
	        tabLayout = (TabLayout) findViewById(R.id.tabs);
	
	        TabLayout.Tab tabFirst = tabLayout.newTab();
	        tabFirst.setText("TabFirst");
	        tabLayout.addTab(tabFirst);
	
	        TabLayout.Tab tabSecond = tabLayout.newTab();
	        tabSecond.setText("tabSecond");
	        tabLayout.addTab(tabSecond);
	
	        TabLayout.Tab tabThird = tabLayout.newTab();
	        tabThird.setText("tabThird");
	        tabLayout.addTab(tabThird);
	        tabLayout.setupWithViewPager(viewPager);
	    }
	
	    @Override
	    public boolean onCreateOptionsMenu(Menu menu) {
	        getMenuInflater().inflate(R.menu.menu_main, menu);
	        return true;
	    }
	
	    @Override
	    public boolean onOptionsItemSelected(MenuItem item) {
	        int id = item.getItemId();
	        if (id == R.id.action_settings) {
	            return true;
	        }
	        return super.onOptionsItemSelected(item);
	    }
	}

在上例中我们使用了一个还有ListView的视图View来填充ViewPager。 看下效果图。 viewpager

我们确实实现了效果,但是却没有了Tab页的标题。这是为什么呢?我们需要看下setupWithViewPager(ViewPager viewPager)的源码。

	 public void setupWithViewPager(ViewPager viewPager) {
        PagerAdapter adapter = viewPager.getAdapter();
        if(adapter == null) {
            throw new IllegalArgumentException("ViewPager does not have a PagerAdapter set");
        } else {
            this.setTabsFromPagerAdapter(adapter);
            viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(this));
            this.setOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(viewPager));
        }
    }

在该方法中首先判断viewPager的adapter是否为null,如果为null抛出异常。所以我们在使用这个方法前,应该给viewpager设置好adapter才行。接着我们看this.setTabsFromPagerAdapter(adapter)这个方法。

	public void setTabsFromPagerAdapter(PagerAdapter adapter) {
        this.removeAllTabs();
        int i = 0;
        for(int count = adapter.getCount(); i < count; ++i) {
            this.addTab(this.newTab().setText(adapter.getPageTitle(i)));
        }
    }

在这个方法中,使用removeAllTabs()方法删除所有的Tab页,然后遍历adapter进行生成tab页,这里调用adapter的getPageTitle方法设置tab页的名称。所以我们的adapter需要重写getPageTitle方法。

由于我们没有重写该方法,所以导致title无法显示,同样,我们也不需要手动添加tab页,只需要在getPageTitle方法中进行判断即可。

修改后的:

	@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });

        viewPager = (ViewPager) findViewById(R.id.viewPager);
        viewPager.setAdapter(new PagerAdapter() {

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

            @Override
            public boolean isViewFromObject(View view, Object object) {
                return view == object;
            }

            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                container.addView(new ListViewLayout(getApplication()), position);
                return container.getChildAt(position);
            }

            @Override
            public void destroyItem(ViewGroup container, int position, Object object) {
                container.removeViewAt(position);
            }

            @Override
            public CharSequence getPageTitle(int position) {
                if (position % 3 == 0) {
                    return "新闻世界";
                } else if (position % 3 == 1) {
                    return "IT新闻";
                } else {
                    return "Mr_dsw博客";
                }
            }
        });
        tabLayout = (TabLayout) findViewById(R.id.tabs);
        tabLayout.setupWithViewPager(viewPager);
    }

效果图就是这样子。 this

二、CoordinatorLayout的基本使用

仔细的同学,可以看到我们设置了以下属性:

(1)、app:layout_scrollFlags:它有四个值,分别是:

  • scroll: 所有想滚动出屏幕的view都需要设置这个flag, 没有设置这个flag的view将被固定在屏幕顶部。例如,TabLayout 没有设置这个值,将会停留在屏幕顶部。
  • enterAlways: 设置这个flag时,向下的滚动都会导致该view变为可见,启用快速“返回模式”。
  • enterAlwaysCollapsed: 当你的视图已经设置minHeight属性又使用此标志时,你的视图只能已最小高度进入,只有当滚动视图到达顶部时才扩大到完整高度。
  • exitUntilCollapsed: 滚动退出屏幕,最后折叠在顶端。

(2)、app:layout_behavior:为了ToolBar可以滚动,CoordinatorLayout里面,放一个带有可滚动的View.CoordinatorLayout包含的子视图中带有滚动属性的View需要设置app:layout_behavior属性。

但是我们设置了该属性但是依旧无法实现需要的伸缩,后来无果,我将ListView改为RecyclerView,竟然可以滚动了,这点我也不晓得怎么个情况。

看下RecycerView的布局:

	<?xml version="1.0" encoding="utf-8"?>
	<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	    android:orientation="vertical" android:layout_width="match_parent"
	    android:layout_height="match_parent">
	    <android.support.v7.widget.RecyclerView
	        android:id="@+id/recycler_view"
	        android:layout_width="match_parent"
	        android:layout_height="match_parent"
	        android:scrollbars="vertical"
	        />
	</LinearLayout>

我们自定义一个View。

	/**
	 * Created by dsw on 2015/11/8.
	 */
	public class RecyclerViewLayout extends LinearLayout {
	    public RecyclerViewLayout(Context context, AttributeSet attrs) {
	        super(context, attrs);
	        initView(context);
	    }
	
	    public RecyclerViewLayout(Context context) {
	        super(context);
	        initView(context);
	    }
	
	    private void initView(Context context){
	        View view = LayoutInflater.from(context).inflate(R.layout.recycler_view,this);
	        RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
	        recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
	        recyclerView.setAdapter(new MyAdapter(context));
	    }
	
	    class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewHolder>{
	        String[] data = new String[]{"A","B","C","D","E",
	                "F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","Z","Y","Z"};
	        Context context;
	        public MyAdapter(Context context){
	            this.context = context;
	        }
	        @Override
	        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
	            TextView textView = new TextView(context);
	            textView.setTextColor(Color.parseColor("#000000"));
	            textView.setTextSize(17*getResources().getDisplayMetrics().scaledDensity);
	            textView.setPadding(20,20,20,20);
	            return new MyViewHolder(textView);
	        }
	
	        @Override
	        public void onBindViewHolder(MyViewHolder holder, int position) {
	            holder.tv_textView.setText(data[position]);
	        }
	
	        @Override
	        public int getItemCount() {
	            return data.length;
	        }
	
	        public class MyViewHolder extends RecyclerView.ViewHolder{
	            public TextView tv_textView;
	            public MyViewHolder(View itemView) {
	                super(itemView);
	                tv_textView = (TextView) itemView;
	            }
	        }
	    }
	}

我们只需要在PagerAdapter中修改。

	 @Override
    public Object instantiateItem(ViewGroup container, int position) {
        container.addView(new RecyclerViewLayout(getApplication()), position);
        return container.getChildAt(position);
    }

这样就可以了。效果图:

result

在来看看模拟器中的怪模样吧! neusx