zoukankan      html  css  js  c++  java
  • TabTopLayout【自定义顶部选项卡区域(固定宽度且居中)】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处!

    前言

    自定义顶部选项卡并居中显示。结合显示/隐藏view的方式实现切换功能(正常情况下可能是切换fragment)。

    效果图

    代码分析

    TabTopLayout:顶部选项卡布局类——自定义的LinearLayout子类;实现了各个选项卡的布局、状态切换、点击事件的回调。

    使用步骤

    一、项目组织结构图

    注意事项:

    1、  导入类文件后需要change包名以及重新import R文件路径

    2、  Values目录下的文件(strings.xml、dimens.xml、colors.xml等),如果项目中存在,则复制里面的内容,不要整个覆盖

    二、导入步骤

    将TabTopLayout.java文件复制到项目中

    package com.why.project.tabtoplayoutdemo.views.tab;
    
    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.Gravity;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.widget.CheckedTextView;
    import android.widget.LinearLayout;
    
    import com.why.project.tabtoplayoutdemo.R;
    
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.List;
    
    /**
     * Created by HaiyuKing
     * Used 顶部选项卡布局类(注意:这个是tab_top_item的父布局)
     */
    
    public class TabTopLayout extends LinearLayout {
    
        private Context mContext;
    
        //选项卡对应的文字
        //CharSequence与String都能用于定义字符串,但CharSequence的值是可读可写序列,而String的值是只读序列。
        private CharSequence[] toptab_Titles = {"已发布","未发布"};
    
        //选项卡的各个选项的view的集合:用于更改背景颜色
        private List<View> toptab_Items = new ArrayList<View>();
        //选项卡的各个选项的CheckedTextView的集合:用于切换时改变图标和文字颜色
        private List<CheckedTextView> topTab_checkeds = new ArrayList<CheckedTextView>();
    
    
        public TabTopLayout(Context context, AttributeSet attrs) {
            super(context, attrs);
    
            mContext = context;
    
            List<CharSequence> tab_titleList = new ArrayList<CharSequence>();
            tab_titleList = Arrays.asList(toptab_Titles);
            //初始化view:创建多个view对象(引用tab_top_item文件),设置图片和文字,然后添加到这个自定义类的布局中
            initAddBottomTabItemView(tab_titleList);
        }
    
        //初始化控件
        private void initAddBottomTabItemView(List<CharSequence> tabTitleList){
    
            int countChild = this.getChildCount();
            if(countChild > 0){
                this.removeAllViewsInLayout();//清空控件
                //将各个选项的view添加到集合中
                toptab_Items.clear();
                //将各个选项卡的各个选项的标题添加到集合中
                topTab_checkeds.clear();
            }
    
    
            //设置要添加的子布局view的参数
            LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
            params.weight = 1;//在tab_bottom_item文件的根节点RelativeLayout中是无法添加的,而这个是必须要写上的,否则只会展现一个view
            params.gravity = Gravity.CENTER;
    
            for(int index=0;index<tabTitleList.size();index++){
    
                final int finalIndex = index;
    
                //============引用选项卡的各个选项的布局文件=================
                View toptabitemView = LayoutInflater.from(mContext).inflate(R.layout.tab_top_item, this, false);
    
                //===========设置CheckedTextView控件的图片和文字==========
                final CheckedTextView toptab_checkedTextView = (CheckedTextView) toptabitemView.findViewById(R.id.toptab_checkedTextView);
    
                //设置CheckedTextView的文字
                toptab_checkedTextView.setText(tabTitleList.get(index).toString());
    
                //===========设置CheckedTextView控件的Tag(索引)==========用于后续的切换更改图片和文字
                toptab_checkedTextView.setTag("tag"+index);
    
                //添加选项卡各个选项的触发事件监听
                toptabitemView.setOnClickListener(new OnClickListener() {
                    public void onClick(View v) {
                        //设置CheckedTextView状态为选中状态
                        //修改View的背景颜色
                        setTabsDisplay(finalIndex);
                        //添加点击事件
                        if(topTabSelectedListener != null){
                            //执行activity主类中的onTopTabSelected方法
                            topTabSelectedListener.onTopTabSelected(finalIndex);
                        }
                    }
                });
    
                //把这个view添加到自定义的MyBottomTab布局里面
                this.addView(toptabitemView,params);
    
                //将各个选项的view添加到集合中
                toptab_Items.add(toptabitemView);
                //将各个选项卡的各个选项的CheckedTextView添加到集合中
                topTab_checkeds.add(toptab_checkedTextView);
            }
        }
    
        /**
         * 设置底部导航中图片显示状态和字体颜色
         */
        public void setTabsDisplay(int checkedIndex) {
    
            int size = topTab_checkeds.size();
    
            for(int i=0;i<size;i++){
                CheckedTextView checkedTextView = topTab_checkeds.get(i);
                //设置CheckedTextView状态为选中状态
                if(checkedTextView.getTag().equals("tag"+checkedIndex)){
                    checkedTextView.setChecked(true);
                    //修改文字颜色
                    checkedTextView.setTextColor(getResources().getColor(R.color.tab_text_selected_top));
                    //修改view的背景颜色
                    if(0 == i) {
                        toptab_Items.get(i).setBackgroundResource(R.drawable.tab_top_layout_item_shape_left_selected);
                    } else if (i == size - 1){
                        toptab_Items.get(i).setBackgroundResource(R.drawable.tab_top_layout_item_shape_right_selected);
                    } else {
                        toptab_Items.get(i).setBackgroundResource(R.drawable.tab_top_layout_item_shape_mid_selected);
                    }
    
                }else{
                    checkedTextView.setChecked(false);
                    //修改文字颜色
                    checkedTextView.setTextColor(getResources().getColor(R.color.tab_text_normal_top));
                    //修改view的背景颜色
                    if(0 == i) {
                        toptab_Items.get(i).setBackgroundResource(R.drawable.tab_top_layout_item_shape_left_unselected);
                    } else if (i == size - 1){
                        toptab_Items.get(i).setBackgroundResource(R.drawable.tab_top_layout_item_shape_right_unselected);
                    } else {
                        toptab_Items.get(i).setBackgroundResource(R.drawable.tab_top_layout_item_shape_mid_unselected);
                    }
                }
            }
        }
    
        private OnTopTabSelectListener topTabSelectedListener;
    
        //自定义一个内部接口,用于监听选项卡选中的事件,用于获取选中的选项卡的下标值
        public interface OnTopTabSelectListener{
            void onTopTabSelected(int index);
        }
    
        public void setOnTopTabSelectedListener(OnTopTabSelectListener topTabSelectedListener){
            this.topTabSelectedListener = topTabSelectedListener;
        }
    }
    TabTopLayout.java

    后续可根据实际情况修改选项卡的文字内容【三、四个选项卡也是可以的】:

        //选项卡对应的文字
        //CharSequence与String都能用于定义字符串,但CharSequence的值是可读可写序列,而String的值是只读序列。
        private CharSequence[] toptab_Titles = {"已发布","未发布"};

    将tab_top_item布局文件复制到项目中

    <?xml version="1.0" encoding="utf-8"?>
    <!-- 顶部选项卡布局 -->
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/tab_bg_normal_top"
        android:gravity="center" >
    
        <!-- android:checkMark="?android:attr/listChoiceIndicatorMultiple"代表多选
             android:checkMark="?android:attr/listChoiceIndicatorSingle" 代表单选
             该属性不添加的话,不会显示方框或者圆点
           -->
    
        <!-- android:drawableTop的属性值使用drawable目录下的selector选择器 -->
        <!-- android:tag="tag1"用于checkedTextview的索引 -->
    
        <!-- 选项卡的内容(图片+文字)类似RadioButton -->
        <!--android:textAlignment="center" 文本居中-->
        <CheckedTextView
            android:id="@+id/toptab_checkedTextView"
            android:tag="tag1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:text=""
            android:textSize="@dimen/tab_larger_text_size"
            android:textColor="@color/tab_text_normal_top"
            android:paddingTop="5dp"
            android:paddingBottom="5dp"
            android:paddingLeft="20dp"
            android:paddingRight="20dp"
            android:textAlignment="center"/>
    </RelativeLayout>
    tab_top_item

    将selector文件复制到项目中【后续可根据实际情况更换

    在colors.xml文件中添加以下代码:【后续可根据实际情况更改背景颜色、文字颜色值

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <color name="colorPrimary">#3F51B5</color>
        <color name="colorPrimaryDark">#303F9F</color>
        <color name="colorAccent">#FF4081</color>
    
        <!-- *********************************顶部选项卡区域********************************* -->
        <!-- 顶部选项卡底部背景色 -->
        <color name="tab_bg_normal_top">#00ffffff</color>
        <color name="tab_bg_selected_top">#0075AA</color>
        <!-- 顶部选项卡文本颜色 -->
        <color name="tab_text_normal_top">#0075AA</color>
        <color name="tab_text_selected_top">#ffffff</color>
    
    </resources>

    在dimens.xml文件中添加以下代码:【后续可根据实际情况更改底部选项卡区域的高度值、文字大小值

    <resources>
        <!-- Default screen margins, per the Android Design guidelines. -->
        <dimen name="activity_horizontal_margin">16dp</dimen>
        <dimen name="activity_vertical_margin">16dp</dimen>
    
        <!-- *********************************顶部选项卡区域********************************* -->
        <!-- 顶部选项卡文本大小 -->
        <dimen name="tab_text_size">14sp</dimen>
        <dimen name="tab_medium_text_size">16sp</dimen>
        <dimen name="tab_larger_text_size">18sp</dimen>
        <dimen name="tab_larger_small_text_size">20sp</dimen>
    </resources>

    至此,TabTopLayout类集成到项目中了。

    三、使用方法

    在Activity布局文件中引用TabTopLayout布局类【注意:需要重新引用TabTopLayout类的完整路径

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/activity_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:paddingBottom="@dimen/activity_vertical_margin"
        android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        android:orientation="vertical"
        tools:context="com.why.project.tabtoplayoutdemo.MainActivity">
    
        <!-- 顶部选项卡 -->
        <com.why.project.tabtoplayoutdemo.views.tab.TabTopLayout
            android:id="@+id/home_toptab"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:layout_gravity="center_horizontal"
            />
    
        <!-- 已发布 -->
        <LinearLayout
            android:id="@+id/layout_do"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:gravity="center"
            android:visibility="gone">
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="已发布"/>
    
        </LinearLayout>
        <!-- 未发布 -->
        <LinearLayout
            android:id="@+id/layout_undo"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical"
            android:gravity="center"
            android:visibility="gone">
    
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="未发布"/>
    
        </LinearLayout>
    
    </LinearLayout>

    在Activity中使用如下

    package com.why.project.tabtoplayoutdemo;
    
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    import android.view.View;
    import android.widget.LinearLayout;
    
    import com.why.project.tabtoplayoutdemo.views.tab.TabTopLayout;
    
    public class MainActivity extends AppCompatActivity {
    
        private static final String TAG = "MainActivity";
    
        private TabTopLayout mTabTopLayout;
    
        private LinearLayout mDoLayout;
        private LinearLayout mUnDoLayout;
    
        /**已发布索引值--需要和TabTopLayout中的数组的下标值对应*/
        public static final int Do_Fragment_Index = 0;
        /**未发布索引值*/
        public static final int UnDo_Fragment_Index = 1;
    
        /**保存的选项卡的下标值*/
        private int savdCheckedIndex = Do_Fragment_Index;
        /**当前的选项卡的下标值*/
        private int mCurrentIndex = -1;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            //初始化控件
            initView();
            //初始化数据
            initData();
            //初始化控件的点击事件
            initEvent();
    
        }
    
        @Override
        protected void onResume() {
            // TODO Auto-generated method stub
            super.onResume();
            Log.w(TAG, "{onResume}");
            //设置保存的或者初始的选项卡标红显示
            SwitchTab(savdCheckedIndex);
    
            mCurrentIndex = -1;//解决按home键后长时间不用,再次打开显示空白的问题
            //设置保存的或者初始的选项卡展现对应的fragment
            ShowFragment(savdCheckedIndex);
        }
        /**
         * 初始化控件
         * */
        private void initView(){
            mTabTopLayout = (TabTopLayout) findViewById(R.id.home_toptab);
    
            mDoLayout = (LinearLayout) findViewById(R.id.layout_do);
            mUnDoLayout = (LinearLayout) findViewById(R.id.layout_undo);
        }
    
        /**初始化数据*/
        private void initData() {
        }
    
        /**
         * 初始化点击事件
         * */
        private void initEvent(){
            //每一个选项卡的点击事件
            mTabTopLayout.setOnTopTabSelectedListener(new TabTopLayout.OnTopTabSelectListener() {
                @Override
                public void onTopTabSelected(int index) {
                    ShowFragment(index);//独立出来,用于OnResume的时候初始化展现相应的Fragment
                }
            });
        }
        /**控制切换选项卡*/
        public void SwitchTab(int checkedIndex){
            if(mTabTopLayout != null){
                mTabTopLayout.setTabsDisplay(checkedIndex);
            }
        }
    
        /**
         * 显示选项卡对应的Fragment*/
        public void ShowFragment(int checkedIndex) {
            if (mCurrentIndex == checkedIndex) {
                return;
            }
    
            //隐藏全部碎片
            hideFragments();
            switch (checkedIndex) {
                case Do_Fragment_Index:
                    mDoLayout.setVisibility(View.VISIBLE);
                    break;
                case UnDo_Fragment_Index:
                    mUnDoLayout.setVisibility(View.VISIBLE);
                    break;
            }
            savdCheckedIndex = checkedIndex;
            mCurrentIndex = checkedIndex;
        }
    
        /**隐藏全部碎片
         * 需要注意:不要在OnResume方法中实例化碎片,因为先添加、显示,才可以隐藏。否则会出现碎片无法显示的问题*/
        private void hideFragments() {
            mDoLayout.setVisibility(View.GONE);
            mUnDoLayout.setVisibility(View.GONE);
        }
    
        /**
         * http://blog.csdn.net/caesardadi/article/details/20382815
         * */
        // 自己记录fragment的位置,防止activity被系统回收时,fragment错乱的问题【按home键返回到桌面一段时间,然后在进程里面重新打开,会发现RadioButton的图片选中状态在第二个,但是文字和背景颜色的选中状态在第一个】
        //onSaveInstanceState()只适合用于保存一些临时性的状态,而onPause()适合用于数据的持久化保存。
        protected void onSaveInstanceState(Bundle outState) {
            //http://www.cnblogs.com/chuanstone/p/4672096.html?utm_source=tuicool&utm_medium=referral
            //总是执行这句代码来调用父类去保存视图层的状态”。其实到这里大家也就明白了,就是因为这句话导致了重影的出现
            //super.onSaveInstanceState(outState);
            outState.putInt("selectedCheckedIndex", savdCheckedIndex);
            outState.putInt("mCurrentIndex", mCurrentIndex);
        }
    
        @Override
        protected void onRestoreInstanceState(Bundle savedInstanceState) {
            savdCheckedIndex = savedInstanceState.getInt("selectedCheckedIndex");
            mCurrentIndex = savedInstanceState.getInt("mCurrentIndex");
            super.onRestoreInstanceState(savedInstanceState);
        }
    
    }

    混淆配置

    参考资料

    暂时空缺

    项目demo下载地址

    https://github.com/haiyuKing/TabTopLayoutDemo

  • 相关阅读:
    Largest Rectangle in Histogram
    Valid Sudoku
    Set Matrix Zeroes
    Unique Paths
    Binary Tree Level Order Traversal II
    Binary Tree Level Order Traversal
    Path Sum II
    Path Sum
    Validate Binary Search Tree
    新手程序员 e
  • 原文地址:https://www.cnblogs.com/whycxb/p/7683143.html
Copyright © 2011-2022 走看看