自定义控件-仿QQ导航栏-跟手指示条

效果

滑动演示

涉及控件

LinearLayout + TextView + ViewPager

参考:

ViewPager 详解(四)—-自主实现滑动指示条
http://blog.csdn.net/harvic880925/article/details/38557517
android 打造炫酷导航栏(仿UC头条)
http://blog.csdn.net/qq_16064871/article/details/50682388

实现

自定义控件

自定义控件 ViewPagerIndicator.java 继承自 LinearLayout ,在里面通过 setTitles() 添加子条目 TextView,并且通过相同的 layout_weight = 1 平分父控件宽度: tv.setLayoutParams(new LayoutParams(0, (int) (mMetrics.density * 36), 1)); 需要注意的是通过比重设置宽度时, layout_width 一定要设置为 0dp ,否则文字多少会影响长度。

(1)绘画指示条

mPaint 用来画底下那条灰色线, mPaintSlide 用来画蓝色滑动指示条,在构造函数里初始化。在 dispatchDraw() 里被 canvas 使用,画两个矩形。

dispatchDraw() 在需要刷新的时候就会被调用绘画该控件(还有 onDraw() 等也会被调用)。

canvas.drawRect(0, getMeasuredHeight() - 1, getMeasuredWidth(), getMeasuredHeight(), mPaint);
canvas.drawRect(mSlideRectLeft, getMeasuredHeight() - 6 * mMetrics.density, mSlideRectRight, getMeasuredHeight(), mPaintSlide);

6 * mMetrics.density 的长度就是 6dp 的像素长度。通过 mMetrics = getResources().getDisplayMetrics(); 可以获得当前设备的密度。因为 canvas 绘画的时候单位是像素,所以要进行转换。

(2)设置指示条宽度

指示条的宽度时由条目长度动态决定的,所以在 getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() 设置指示条的宽度,它会在本控件第一次 OnPreDraw() 运行时回调,之后会被 removeOnPreDrawListener()

指示条宽度计算: mWidth = getMeasuredWidth()/count,当然指示条的宽度应该与一个条目的长度相同,所以平分 LinearLayout 的长度。

(3)滑动检测

每个条目的长度记录在 mWidth ,左右长度 mSlideRectLeft 和 mSlideRectRight 计算在 ViewPager.OnPageChangeListeneronPageScrolled() 里。ViewPager 被滑动时, onPageScrolled() 会被不停回调,因此需要不断计算出新的值。

mSlideRectLeft = position * mWidth + (int) (positionOffset * mWidth);
mSlideRectRight = mSlideRectLeft + mWidth;

代码

自定义控件 ViewPagerIndicator.java

package com.example.testslidingtabapplication;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.LinearLayout;
import android.widget.TextView;

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

public class ViewPagerIndicator extends LinearLayout {
    private static final String TAG = "ViewPagerIndicator";
    private final Context mContext;
    private final Paint mPaint;
    private final Paint mPaintSlide;
    private final DisplayMetrics mMetrics;
    private final OnClickListener mOnClickListener;
    private float mSlideRectLeft;
    private float mSlideRectRight;
    private List<TextView> mTvList;
    private ViewPager mViewPager;
    private int mWidth;

    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);
        mContext = context;
        mPaint = new Paint();
        mPaint.setColor(ContextCompat.getColor(mContext, android.R.color.darker_gray));
        mPaint.setStyle(Paint.Style.FILL);
        mPaintSlide = new Paint();
        mPaintSlide.setColor(ContextCompat.getColor(mContext, R.color.colorPrimary));
        mPaintSlide.setStyle(Paint.Style.FILL);

        setBackgroundColor(ContextCompat.getColor(mContext, android.R.color.white));
        setPadding(0, 0, 0, 0);
        getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
            @Override
            public boolean onPreDraw() {
                int count = mViewPager.getAdapter().getCount();
                mWidth = getMeasuredWidth()/count;
                mSlideRectLeft = 0;
                mSlideRectRight = mSlideRectLeft + mWidth;
                mTvList.get(0).setSelected(true);
                getViewTreeObserver().removeOnPreDrawListener(this);
                return true;
            }
        });

        mMetrics = getResources().getDisplayMetrics();

        mOnClickListener = new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                int position = (int) v.getTag();
                mViewPager.setCurrentItem(position);
            }
        };
    }



    @Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.save();

        canvas.drawRect(0, getMeasuredHeight() - 1, getMeasuredWidth(), getMeasuredHeight(), mPaint);
        canvas.drawRect(mSlideRectLeft, getMeasuredHeight() - 6 * mMetrics.density, mSlideRectRight, getMeasuredHeight(), mPaintSlide);

        //Log.d(TAG, "mSlideRectLeft=" + mSlideRectLeft + " mSlideRectRight=" + mSlideRectRight);

        canvas.restore();
        super.dispatchDraw(canvas);
    }

    public void setTitles(List<String> titles) {
        List<TextView> tvList = new ArrayList<>();
        mTvList = tvList;
        int position = 0;
        for (String title : titles) {
            TextView tv = generateTitleView(title, position++);
            tvList.add(tv);
            addView(tv);
        }
    }

    private TextView generateTitleView(String title, int position) {
        TextView tv = new TextView(mContext);
        tv.setLayoutParams(new LayoutParams(0, (int) (mMetrics.density * 36), 1));
        tv.setGravity(Gravity.CENTER);
        tv.setTextColor(ContextCompat.getColorStateList(mContext, R.color.selector_tab_color));
        tv.setTextSize(16);
        tv.setText(title);
        tv.setTag(position);
        tv.setOnClickListener(mOnClickListener);
        return tv;
    }

    public void setViewPager(ViewPager viewPager) {
        mViewPager = viewPager;
        viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                mSlideRectLeft = position * mWidth + (int) (positionOffset * mWidth);
                mSlideRectRight = mSlideRectLeft + mWidth;
                //Log.d(TAG, "addOnPageChangeListener mSlideRectLeft=" + mSlideRectLeft + " mSlideRectRight=" + mSlideRectRight);
                invalidate();
            }

            @Override
            public void onPageSelected(int position) {
                for (TextView view : mTvList) {
                    if (view == mTvList.get(position)) {
                        view.setSelected(true);
                    } else {
                        view.setSelected(false);
                    }
                }
            }

            @Override
            public void onPageScrollStateChanged(int state) {

            }
        });
    }
}

selector

TextView 的颜色配置 selector_tab_color.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_selected="true" android:color="@color/colorPrimary"/>
    <item android:state_pressed="true" android:color="@color/colorPrimary"/>
    <item android:color="@android:color/black"/>
</selector>

Activity

Main2Activity.java

package com.example.testslidingtabapplication;

import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

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

public class Main2Activity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        ViewPager viewPager = (ViewPager) findViewById(R.id.viewPager);
        final List<View> list = new ArrayList<>();
        TextView textView1 = new TextView(this);
        textView1.setText("1");
        list.add(textView1);
        TextView textView2 = new TextView(this);
        textView2.setText("2");
        list.add(textView2);
        TextView textView3 = new TextView(this);
        textView3.setText("3");
        list.add(textView3);
        TextView textView4 = new TextView(this);
        textView3.setText("4");
        list.add(textView4);
        viewPager.setAdapter(new PagerAdapter() {
            @Override
            public int getCount() {
                return list.size();
            }

            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                container.addView(list.get(position));
                return list.get(position);
            }

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

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

        ViewPagerIndicator viewPagerIndicator
                = (ViewPagerIndicator) findViewById(R.id.viewPagerIndicator);
        List<String> titleList = new ArrayList<>();
        titleList.add("消息");
        titleList.add("联系人");
        titleList.add("我");
        titleList.add("关于");
        viewPagerIndicator.setTitles(titleList);
        viewPagerIndicator.setViewPager(viewPager);
    }

}

布局

这是 Android Studio 创建 Activity 时自动生成的布局文件 content_main2.xml 。
在里面添加 自定义的导航栏 com.example.testslidingtabapplication.ViewPagerIndicator ,和 ViewPager 。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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/content_main2"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="0dp"
    android:paddingLeft="0dp"
    android:paddingRight="0dp"
    android:paddingTop="0dp"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.example.testslidingtabapplication.Main2Activity"
    tools:showIn="@layout/activity_main2">

    <com.example.testslidingtabapplication.ViewPagerIndicator
        android:id="@+id/viewPagerIndicator"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <android.support.v4.view.ViewPager
        android:id="@+id/viewPager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@id/viewPagerIndicator"/>

</RelativeLayout>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值