继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

【Android】顶部Tab指示器(自定义LinearLayout+Viewpager)

JFSL
关注TA
已关注
手记 9
粉丝 14
获赞 93

2016-11-13 第一篇 ViewPagerIndicator

根据鸿洋的视频编写,然后自己添加了可以滑动的图形方式,直线或者三角形。还添加了可以在xml中自定义样式的功能。

最后效果演示图
图片描述

图片描述

ChangeablePagerIndicator类(顶部的指示器类)
重写父类主要的方法:
1.dispatchDraw(Canvas canvas) 绘制直线或者三角形
图片描述
2.onFinishInflate() xml文件加载完成之后调用此放过,在xml中设置item时,在此方法重新设置item的宽度
图片描述


Tab item移动的方法:
1.scroll(int position,float offset)
图片描述

代码生成Items的方法
1.setTabItems(List<String> titles)
图片描述


内部处理ViewPager的滑动
1.设置ViewPager :setViewPager(ViewPager viewPager,int currentPos)
图片描述
2.设置监听事件(这里的IndicatorListener是实现ViewPager.OnPageChangeListener接口)
图片描述


点击Item跳转ViewPager
1.setItemClickListener()
图片描述


xml中自定义的属性值
图片描述
图片描述


全部代码


指示器类代码(ChangeablePagerIndicator.java)

package jfsl.view.toptab.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.CornerPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.TextView;

import java.util.List;

import jfsl.view.toptab.R;
import jfsl.view.toptab.listener.IndicatorListener;

/**
 * 顶部Tab的导航区域
 * 固定的顶部Indicator
 *
 * @version 1.0
 * @aduthor JFSL
 * @date 2016/11/12
 * @date 2016-11-13 15:08 完成
 */

public class ChangeablePagerIndicator extends LinearLayout
{
    //默认的高亮文本颜色:白色
    public static final int COLOR_TEXT_HIGHLIGHT = Color.parseColor("#FFFFFFFF");
    //默认的正常文本颜色:灰色
    public static final int COLOR_TEXT_NORMAL = Color.parseColor("#77FFFFFF");
    //默认绘制图形的颜色:白色
    public static final int COLOR_GRAPHICS = Color.parseColor("#FFFFFFFF");
    //默认Tab的文本大小 16sp
    public static final int TAB_TEXT_SIZE = 16;
    //直线的高度 10dp
    public static final int LINE_HEIGHT = 10;
    //最小的显示Tab的数量
    public static final int DEFAULT_VISIBLE_COUNTS = 3;
    //绘制的类型:1.直线 2.三角形
    public static final int STYLE_LINE = 100;
    public static final int STYLE_TRIANGLE = 200;
    //三角形的比例
    public static final float TRIANGLE_RADIO = 1 / 6F;
    //绘制三角形的画笔
    private Paint mTrianglePaint;
    //绘制三角形的路径
    private Path mTrianglePath;
    //三角形的宽
    private int mTriangleWidth;
    //三角形的高
    private int mTriangleHeight;
    //绘制直线的画笔
    private Paint mLinePaint;
    //线的宽度
    private int mLineWidth;
    //初始位置时三角形的位置
    private int mStartX;
    //移动时三角形的位置
    private int mMoveX;
    //绘制的类型
    private int mDrawStyle = STYLE_LINE;
    //默认显示的tab item数量
    private int mDefaultVisibleCounts;
    //高亮文本的颜色
    private int mHighLightColor;
    //普通文本的颜色
    private int mNormalTextColor;
    //文本大小
    private int mTextSize;
    //线的高度(strokeWidth)
    private int mLineHeight;
    //直线或者三角形的颜色
    private int mGraphicsColor;

    public ChangeablePagerIndicator(Context context)
    {
        this(context,null);
    }

    public ChangeablePagerIndicator(Context context,AttributeSet attrs)
    {
        super(context,attrs);
        //获取自定义的值
        getCustomValue(context,attrs);
        //初始化三角形的画笔
        initTrianglePaint();
        //初始化直线的画笔
        initLinePaint();
    }

    /**
     * 加载完XML时,调用此方法
     */
    @Override
    protected void onFinishInflate()
    {
        super.onFinishInflate();

        int coutns = getChildCount();
        if(coutns == 0)
            return;

        for(int i = 0;i < coutns;i++)
        {
            View view = getChildAt(i);
            LinearLayout.LayoutParams params = (LayoutParams)view.getLayoutParams();
            params.weight = 0;
            params.width = getScreenWidth() / mDefaultVisibleCounts;

            view.setLayoutParams(params);
        }
        //设置监听
        setItemClickListener();
        //直线的宽度
        mLineWidth = getScreenWidth() / mDefaultVisibleCounts;
    }

    @Override
    protected void onSizeChanged(int width,int height,int oldWidth,int oldHeight)
    {
        super.onSizeChanged(width,height,oldWidth,oldHeight);
        //创建三角形
        createIndicatorTriangle();
    }

    @Override
    protected void dispatchDraw(Canvas canvas)
    {
        canvas.save();
        if(mDrawStyle == STYLE_LINE)
        {
            //绘制直线
            canvas.drawLine(mMoveX,getHeight(),mMoveX + mLineWidth,getHeight(),mLinePaint);
        }
        if(mDrawStyle == STYLE_TRIANGLE)
        {
            //绘制三角形
            canvas.translate(mStartX + mMoveX,getHeight());
            canvas.drawPath(mTrianglePath,mTrianglePaint);
        }
        canvas.restore();
        super.dispatchDraw(canvas);
    }

    /**
     * 获取自定义的值
     *
     * @param attrs
     */
    private void getCustomValue(Context context,AttributeSet attrs)
    {
        TypedArray attributes = context.obtainStyledAttributes(attrs,R.styleable.ChangeablePagerIndicator);
        //获取默认显示的可见Tab的数量
        mDefaultVisibleCounts = attributes.
                getInt(R.styleable.ChangeablePagerIndicator_default_display_counts,DEFAULT_VISIBLE_COUNTS);
        mDefaultVisibleCounts = Math.max(DEFAULT_VISIBLE_COUNTS,mDefaultVisibleCounts);
        //高亮文本的颜色
        mHighLightColor = attributes.getColor(R.styleable.ChangeablePagerIndicator_high_light_color,COLOR_TEXT_HIGHLIGHT);
        //普通文本的颜色
        mNormalTextColor = attributes.getColor(R.styleable.ChangeablePagerIndicator_normal_text_color,COLOR_TEXT_NORMAL);
        //文本大小
        mTextSize = attributes.getInt(R.styleable.ChangeablePagerIndicator_text_size,TAB_TEXT_SIZE);
        //线的高度(strokeWidth)
        mLineHeight = attributes.getInt(R.styleable.ChangeablePagerIndicator_graphics_height,LINE_HEIGHT);
        //直线或者三角形的颜色
        mGraphicsColor = attributes.getColor(R.styleable.ChangeablePagerIndicator_graphics_color,COLOR_GRAPHICS);
        //绘制的类型
        boolean drawStyle = attributes.getBoolean(R.styleable.ChangeablePagerIndicator_is_draw_line,true);
        mDrawStyle = drawStyle ? STYLE_LINE : STYLE_TRIANGLE;
        //直线的宽度
        mLineWidth = getScreenWidth() / mDefaultVisibleCounts;

        attributes.recycle();
    }

    /**
     * 初始化三角形的画笔
     */
    private void initTrianglePaint()
    {
        mTrianglePaint = new Paint();
        mTrianglePaint.setAntiAlias(true);
        //三角形的画笔颜色
        mTrianglePaint.setColor(mGraphicsColor);
        mTrianglePaint.setStyle(Paint.Style.FILL);
        //绘制角时的弧度
        mTrianglePaint.setPathEffect(new CornerPathEffect(2));
    }

    /**
     * 初始化直线的画笔
     */
    private void initLinePaint()
    {
        mLinePaint = new Paint(mTrianglePaint);
        mLinePaint.setStrokeWidth(mLineHeight);
    }

    /**
     * 创建指示器的三角形
     */
    private void createIndicatorTriangle()
    {
        int tabWidth = getScreenWidth() / mDefaultVisibleCounts;
        //三角形的宽度
        mTriangleWidth = (int)(tabWidth * TRIANGLE_RADIO);
        //初始位置时三角形的位置
        mStartX = (tabWidth - mTriangleWidth) / 2;
        //三角形的高度
        mTriangleHeight = mTriangleWidth / 3;

        //绘制三三角形路径
        mTrianglePath = new Path();
        mTrianglePath.moveTo(0,0);
        mTrianglePath.lineTo(mTriangleWidth,0);
        mTrianglePath.lineTo(mTriangleWidth / 2,- mTriangleHeight);
        mTrianglePath.close();
    }

    /**
     * 水平滚动
     *
     * @param position
     * @param offset
     */
    public void scroll(int position,float offset)
    {
        int tabWidth = getWidth() / mDefaultVisibleCounts;
        //指示器移动的距离
        mMoveX = (int)(tabWidth * (position + offset));

        //移动Tab
        if(position >= (mDefaultVisibleCounts - 2) && offset > 0
                && getChildCount() > mDefaultVisibleCounts
                && position != getChildCount() - 2)
        {
            if(mDefaultVisibleCounts != 1)
            {
                int scrollX = (position - (mDefaultVisibleCounts - 2)) * tabWidth
                        + (int)(tabWidth * offset);
                this.scrollTo(scrollX,0);
            } else
            {
                this.scrollTo((position * tabWidth
                        + (int)(tabWidth * offset)),0);
            }

        }
        //重新绘制
        invalidate();
    }

    /**
     * 设置绘制的类型
     * 1.STYLE_LINE    直线
     * 2.STYLE_TRIANGLE 三角形
     */
    public void setDrawStyle(int style)
    {
        mDrawStyle = style;
        invalidate();
    }

    public void setDefaultVisibleCounts(int counts)
    {
        mDefaultVisibleCounts = counts;
        if(counts < DEFAULT_VISIBLE_COUNTS)
            mDefaultVisibleCounts = DEFAULT_VISIBLE_COUNTS;

        //直线的宽度
        mLineWidth = getScreenWidth() / mDefaultVisibleCounts;
    }

    /**
     * 不用加载布局文件,代码生成
     *
     * @param titles
     */
    public void setTabItems(List<String> titles)
    {
        if(titles == null)
            return;
        //首先移除所有的View
        this.removeAllViews();
        //根据标题生成TextView
        for(String title : titles)
        {
            this.addView(generateTitleView(title));
        }
        //设置监听
        setItemClickListener();
    }

    /**
     * 设置ViewPager
     *
     * @param viewPager
     * @param currentPos 当前选的位置
     */
    private ViewPager mViewPager;

    public void setViewPager(ViewPager viewPager,int currentPos)
    {
        mViewPager = viewPager;
        viewPager.addOnPageChangeListener(mListener);
        //设置当前选中项
        viewPager.setCurrentItem(currentPos);
    }

    /**
     * ViewPager监听
     */
    private IndicatorListener mListener = new IndicatorListener()
    {

        @Override
        public void scrollChanged(int position,float offset)
        {
            //进行Tab滚动
            scroll(position,offset);
        }

        @Override
        public void selected(int position)
        {
            //设置高亮文本,当前ViewPager与Tab一一对应
            setHighLightText(position);
        }
    };

    /**
     * Tab Item的点击监听
     */
    private void setItemClickListener()
    {
        for(int i = 0;i < getChildCount();i++)
        {
            //点击的位置
            final int clickPosition = i;
            View view = getChildAt(i);
            if(view instanceof TextView)
            {
                view.setOnClickListener(new OnClickListener()
                {

                    @Override
                    public void onClick(View view)
                    {
                        //ViewPager跳到对应的选中项
                        mViewPager.setCurrentItem(clickPosition);
                    }
                });
            }
        }
    }

    /**
     * 根据标题生成TextView
     *
     * @param title
     * @return
     */
    private View generateTitleView(String title)
    {
        TextView tv = new TextView(getContext());
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT);
        params.width = getScreenWidth() / mDefaultVisibleCounts;
        tv.setGravity(Gravity.CENTER);
        tv.setText(title);
        tv.setTextSize(TypedValue.COMPLEX_UNIT_SP,mTextSize);
        tv.setTextColor(mNormalTextColor);
        tv.setLayoutParams(params);
        return tv;
    }

    /**
     * 设置高亮显示的文本
     * 也就是当前选中的文本
     *
     * @param position
     */
    private void setHighLightText(int position)
    {
        for(int i = 0;i < getChildCount();i++)
        {
            View view = getChildAt(i);
            if(view instanceof TextView)
            {
                //高亮颜色
                if(i == position)
                    ((TextView)view).setTextColor(mHighLightColor);
                    //正常颜色
                else
                    ((TextView)view).setTextColor(mNormalTextColor);
            }
        }
    }

    /**
     * 获取屏幕的宽度
     *
     * @return
     */
    private int getScreenWidth()
    {
        WindowManager manager = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics metrics = new DisplayMetrics();
        manager.getDefaultDisplay().getMetrics(metrics);
        return metrics.widthPixels;
    }

}

自定义ViewPager监听类(IndicatorListener.java)

package jfsl.view.toptab.listener;

import android.support.v4.view.ViewPager;

/**
 * @version 1.0
 * @aduthor JFSL
 * @date 2016/11/13 0013
 */

public abstract class IndicatorListener implements ViewPager.OnPageChangeListener
{
    @Override
    public void onPageScrolled(int position,float positionOffset,int positionOffsetPixels)
    {
        scrollChanged(position,positionOffset);
    }

    @Override
    public void onPageSelected(int position)
    {
        selected(position);
    }

    @Override
    public void onPageScrollStateChanged(int state)
    {

    }

    /**
     * ViewPager滑动
     * @param position
     * @param offset
     */
    public abstract void scrollChanged(int position,float offset);

    /**
     * 选择当前页
     * @param position
     */
    public abstract void selected(int position);
}

ViewPager指示器类(TopViewPagerAdapter.java)

package jfsl.view.toptab.adapter;

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

import java.util.List;

import jfsl.view.toptab.fragment.SimpleFragment;

/**
 * @version 1.0
 * @aduthor JFSL
 * @date 2016/11/12 0012
 */

public class TopViewPagerAdapter  extends FragmentPagerAdapter
{
    private Context mContext;
    private List<SimpleFragment> mFragments;

    public TopViewPagerAdapter(FragmentManager fm,Context context,List<SimpleFragment> fragments)
    {
        super(fm);
        mContext = context;
        mFragments = fragments;
    }
    @Override
    public Fragment getItem(int position)
    {
        return mFragments.get(position);
    }

    @Override
    public int getCount()
    {
        return mFragments.size();
    }
}

测试用的Fragment(SimpleFragment.java)

package jfsl.view.toptab.fragment;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

/**测试用的Fragment
 * @version 1.0
 * @aduthor JFSL
 * @date 2016/11/12 0012
 */

public class SimpleFragment extends Fragment
{
    public static final String BUNDLE_TITLE = "title";
    private String mTitle;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState)
    {
        Bundle bundle = getArguments();
        if(bundle != null)
            mTitle = bundle.getString(BUNDLE_TITLE);

        TextView textView = new TextView(getActivity());
        textView.setText(mTitle);
        textView.setGravity(Gravity.CENTER);

        return textView;
    }

    /**
     * 获取实例
     * @param title
     * @return
     */
    public static SimpleFragment newInstance(String title)
    {
        Bundle bundle = new Bundle();
        bundle.putString(BUNDLE_TITLE,title);
        SimpleFragment fragment = new SimpleFragment();
        fragment.setArguments(bundle);
        return fragment;
    }
}

测试的Activity(ChangeableMainActivity .java)

package jfsl.view.toptab;

import android.os.Bundle;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.view.Window;

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

import jfsl.view.toptab.adapter.TopViewPagerAdapter;
import jfsl.view.toptab.fragment.SimpleFragment;
import jfsl.view.toptab.view.ChangeablePagerIndicator;

/**
 * 测试自定义View的效果
 */
public class ChangeableMainActivity extends AppCompatActivity
{
    private ViewPager mViewPager;
    private ChangeablePagerIndicator mIndicator;
    private List<String> mTitles = Arrays.asList("国际","军事","社会","娱乐","体育","财经","历史","本地","中国");
    private List<SimpleFragment> mFragments = new ArrayList<>();
    private FragmentPagerAdapter mPagerAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_main_changeable2);

        initViews();
        initDatas();
        initEvent();
    }

    private void initEvent()
    {
    }

    private void initDatas()
    {
        for(String title : mTitles)
        {
            mFragments.add(SimpleFragment.newInstance(title));
        }
        mPagerAdapter = new TopViewPagerAdapter(getSupportFragmentManager(),this,mFragments);
        mViewPager.setAdapter(mPagerAdapter);

//        mIndicator.setDefaultVisibleCounts(3);
        //设置绘制的类型
//        mIndicator.setDrawStyle(ChangeablePagerIndicator.STYLE_TRIANGLE);
        //注意:其他设置要放在这个之前
        mIndicator.setTabItems(mTitles);
        mIndicator.setViewPager(mViewPager,1);
    }

    private void initViews()
    {
        mIndicator = (ChangeablePagerIndicator)findViewById(R.id.id_pager_indicator);
        mViewPager = (ViewPager)findViewById(R.id.id_viewpager);

    }
}

自定义属性文件(indicator_attrs.xml)

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--默认的显示的Tab数量-->
    <attr name="default_display_counts" format="integer"/>
    <!--高亮文本的颜色-->
    <attr name="high_light_color" format="color"/>
    <!--正常文本的颜色-->
    <attr name="normal_text_color" format="color"/>
    <!--图形的颜色-->
    <attr name="graphics_color" format="color"/>
    <!--文本的大小-->
    <attr name="text_size" format="integer"/>
    <!--图形的高度-->
    <attr name="graphics_height" format="integer"/>
    <!--图形的类型-->
    <attr name="is_draw_line" format="boolean"/>

    <declare-styleable name="ChangeablePagerIndicator">
        <!--默认的显示的Tab数量-->
        <attr name="default_display_counts"/>
        <!--高亮文本的颜色-->
        <attr name="high_light_color"/>
        <!--正常文本的颜色-->
        <attr name="normal_text_color"/>
        <!--图形的颜色-->
        <attr name="graphics_color"/>
        <!--文本的大小-->
        <attr name="text_size"/>
        <!--图形的高度-->
        <attr name="graphics_height"/>
        <!--图形的类型-->
        <attr name="is_draw_line"/>
    </declare-styleable>
</resources>

颜色值文件(colors.xml)

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#009688</color>
    <color name="colorPrimaryDark">#06776d</color>
    <color name="colorAccent">#FF4081</color>
</resources>

代码地址:http://114.215.186.20/14551100130/toptab.zip


参考资料:
1.http://blog.csdn.net/scorplopan/article/details/6302827 ondraw() 和dispatchdraw()的区别

打开App,阅读手记
1人推荐
发表评论
随时随地看视频慕课网APP

热门评论

请问下代码地址不能载可以分享下代码给我参考吗谢谢

查看全部评论