自定义ViewPagerIndicator:100行代码实现两种可滑动指示器

按照惯例先上图,一种是三角形,一种是最常用的下划线





实现思路,主要是在onPageScroll里面进行指示器滑动距离和父容器滑动距离的计算,然后进行滑动,滑动解决了其他就比较简单了。

顶部就是自定义的ViewPagerIndicator,下面就是Fragment+FragmentPagerAdagter


主MainActivity代码,就是常规的ViewPagerIndicator结合Fragment

public class IndicatorActivity extends AppCompatActivity {

    private ViewPagerIndicator indicator;
    private ViewPager mViewPager;

    private List<Fragment> mList = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_indicator);

        mList.add(TitleFragment.newInstance("标题1"));
        mList.add(TitleFragment.newInstance("标题2"));
        mList.add(TitleFragment.newInstance("标题3"));
        mList.add(TitleFragment.newInstance("标题4"));
        mList.add(TitleFragment.newInstance("标题5"));
        mList.add(TitleFragment.newInstance("标题6"));
        mList.add(TitleFragment.newInstance("标题7"));
        mList.add(TitleFragment.newInstance("标题8"));
        mList.add(TitleFragment.newInstance("标题9"));

        indicator = (ViewPagerIndicator) findViewById(R.id.indicator_activity);
        indicator.setSelected_indicator(ViewPagerIndicator.LINE);//使用三角形
        indicator.selectText(0);//默认选中第一个

        mViewPager = (ViewPager) findViewById(R.id.viewpager_indicator);
        mViewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager(), mList));
        mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                indicator.move(position, positionOffset); //position当前fragment,offset滑动值0-1
            }

            @Override
            public void onPageSelected(int position) {
                indicator.selectText(position);//textview选中效果
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
    }
}

Fragment里面就一个textview很简洁

public class TitleFragment extends Fragment {

    private static final String PARAM1 = "param1";

    private String mParam1;

    private Context mContext;

    private callback mCb;

    public static TitleFragment newInstance(String text) {
        TitleFragment fragment = new TitleFragment();
        Bundle bundle = new Bundle();
        bundle.putString(PARAM1, text);
        fragment.setArguments(bundle);
        return fragment;
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context != null) {
            mContext = context;
            if (context instanceof callback) {
                mCb = (callback) context;
            }
        }
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mParam1 = getArguments().getString(PARAM1);
        }
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        //不写xml文件
        TextView textView = new TextView(mContext);
        textView.setText(mParam1);
        textView.setGravity(Gravity.CENTER);
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        lp.gravity = Gravity.CENTER;
        textView.setLayoutParams(lp);
        return textView;
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mCb = null;
    }

    public interface callback {
        void success(String msg);
    }
}

Adapter没什么好说的

public class ViewPagerAdapter extends FragmentPagerAdapter {

    private List<Fragment> mList = new ArrayList<>();

    public ViewPagerAdapter(FragmentManager fm, List<Fragment> mList) {
        super(fm);
        this.mList = mList;
    }

    @Override
    public Fragment getItem(int position) {
        return mList.get(position);
    }

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

主角自定义的ViewPagerIndicator,继承的LinnerLayout,在里面加TextView的方式,加了挺多注释的应该很好理解

public class ViewPagerIndicator extends LinearLayout {

    private static final String TAG = "ViewPagerIndicator";

    public static final int TRIANGLE = 1;//三角形
    public static final int LINE = 2;//下划线
    public static int selected_indicator = TRIANGLE;//要使用的指示器

    private int mScreenWidth;//屏幕宽
    private int mTitleWidth;//每个标题宽
    private int mTriangleWidth;//三角宽
    private int mInitLeftMargin;//初始化的三角x位置
    private int mMoveMargin = 0;//计算出来的移动x位置
    private int mTriangleY;//三角形底部的位置Y
    private int mTitleCount = 9;//标题总数
    private int mVisibableCount = 3;//一屏显示标题数量

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

    public ViewPagerIndicator(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ViewPagerIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        mScreenWidth = wm.getDefaultDisplay().getWidth();

        //初始化一些指示器的宽高参数
        mTitleWidth = mScreenWidth / 3;//默认每个标题占屏幕三分之一宽
        mTriangleWidth = mScreenWidth / 3 / 6;//一个三角形底边占每个标题六分之一
        mInitLeftMargin = mScreenWidth / 3 / 2 - (mTriangleWidth / 2);//初始化第一次三角在标题下居中
        mTriangleY = DensityUtil.dip2px(context, 50);//xml标题栏高50dp
        Log.d(TAG, mScreenWidth + "-" + mTriangleWidth + "-" + mInitLeftMargin);

        //获取标题数量
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.ViewPagerIndicator);
        mTitleCount = array.getInt(R.styleable.ViewPagerIndicator_titleCount, mTitleCount);
        array.recycle();

        //生成标题
        for (int i = 0; i < mTitleCount; i++) {
            TextView textView = new TextView(context);
            textView.setText("标题" + (i + 1));
            textView.setTextColor(getResources().getColor(R.color.titile_text_color));
            textView.setGravity(Gravity.CENTER);
            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(mScreenWidth / mVisibableCount, ViewGroup.LayoutParams.MATCH_PARENT);
            textView.setLayoutParams(lp);
            addView(textView);
        }
    }

    //指示器+容器滚动
    public void move(int pos, float offset) {
        if (selected_indicator == TRIANGLE) {
            mMoveMargin = (int) (mInitLeftMargin + pos * mTitleWidth + (offset * mTitleWidth));//三角形移动
        }else if (selected_indicator == LINE) {
            mMoveMargin = (int) (pos * mTitleWidth + (offset * mTitleWidth));//线移动
        }
        //容器滚动,在一屏倒数第二个才允许
        if (pos >= mVisibableCount - 2 && pos < mTitleCount - 2) {
            scrollTo((int) ((pos - (mVisibableCount - 2)) * mTitleWidth + (mTitleWidth * offset)), 0);
        }
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //画三角形画笔
        Paint paint = new Paint();
        paint.setColor(getResources().getColor(R.color.master_color));
        paint.setStyle(Paint.Style.FILL);
        paint.setStrokeWidth(10.0f);//线宽

        if (selected_indicator == TRIANGLE) {
            if (mMoveMargin == 0) {//不是第一次draw,使用移动的值
                mMoveMargin = mInitLeftMargin;
            }
            //直角三角形
            Path path = new Path();
            path.moveTo(mMoveMargin, mTriangleY);//左点
            path.lineTo(mMoveMargin + mTriangleWidth, mTriangleY);//右点
            path.lineTo(mMoveMargin + (mTriangleWidth / 2), mTriangleY - (mTriangleWidth / 2));//上点
            path.close();
            canvas.drawPath(path, paint);
        }else if (selected_indicator == LINE) {
            canvas.drawLine(mMoveMargin, mTriangleY, mTitleWidth + mMoveMargin, mTriangleY, paint);
        }
    }

    public void setSelected_indicator(int selected_indicator) {
        this.selected_indicator = selected_indicator;
    }

    //选中改变字体颜色
    public void selectText(int position) {
        TextView textView;
        for (int i = 0; i < mTitleCount; i++) {
            textView = (TextView) getChildAt(i);
            if (position == i) {
                textView.setTextColor(getResources().getColor(R.color.colorAccent));
            } else {
                textView.setTextColor(getResources().getColor(R.color.titile_text_color));
            }
        }
    }
}


代码基本贴完了,就不上传工程了,写了大半天时间,有些问题可能没考虑到,见谅一下,毕竟才一百行,不过麻雀虽小五脏俱全啊。







猜你喜欢

转载自blog.csdn.net/PK0071/article/details/51648198