自定义控件之-ViewPagerIndicator

经常使用ViewPagerIndicator,今天自己写了一个,记录下来作为以后参考使用。先看一下效果:
这里写图片描述
先贴出使用方法的代码:
MainActivity代码:

public class MainActivity extends Activity {
    private ViewPager vp;
    private Indicator1 indicator;
    private String[] titles = { "新闻", "美女", "健康", "正能量", "特卖", "图片", "推荐",
            "热点", "淄博", "视频", "社会", "小日本", "哈哈哈" };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        indicator = (Indicator1) findViewById(R.id.indicator);
        vp = (ViewPager) findViewById(R.id.vp);
        indicator.setTitles(vp, titles, new OnTitleClickListener() {

            @Override
            public void onClick(int position) {
                Toast.makeText(getApplicationContext(), titles[position],
                        Toast.LENGTH_SHORT).show();
            }
        });
        vp.setAdapter(new PagerAdapter() {

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

            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                TextView tv = new TextView(MainActivity.this);
                tv.setGravity(Gravity.CENTER);
                tv.setTextSize(40);
                tv.setText(titles[position]);
                container.addView(tv);
                return tv;
            }

            @Override
            public boolean isViewFromObject(View arg0, Object arg1) {
                return arg0 == arg1;
            }

            @Override
            public int getCount() {
                return titles.length;
            }
        });

    }
}

activity_main.xml代码:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <com.example.myindicator.Indicator1
        android:id="@+id/indicator"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >
    </com.example.myindicator.Indicator1>

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

</LinearLayout>

上面都非常好理解,就是简单的使用,下面贴出Indicator1的代码:

public class Indicator1 extends LinearLayout implements OnPageChangeListener,
        OnClickListener {

    private int blockWidth;// 滑块宽度
    private int blockHeight;// 滑块高度
    private int blockTop;// 滑块顶部的坐标
    private int blockLeft;// 滑块左上角的坐标
    private String[] titles;// 保存导航的标题
    private int titleLength;// 标题的个数
    private int screenWidth;// 屏幕的宽度
    private Paint paint;// 画滑块的画笔
    private int visibleTitleCount = 4;// 默认的可见的标题栏数量
    private boolean isFirst = true;// 是否是第一次加载
    private OnTitleClickListener listener;// 点击某个标题的时间监听器
    private ViewPager viewPager;// 关联的ViewPager

    public Indicator1(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public Indicator1(Context context) {
        super(context);
        init(context);
    }

    private void init(Context context) {
        // 将滑块的高度转成px,默人为10dp
        blockHeight = dp2px(10);
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);// 抗锯齿
        paint.setColor(Color.RED);// 设置滑块颜色
        setOrientation(LinearLayout.HORIZONTAL);// 水平布局
        // 这里需要设置背景,否则onDraw不会调用;或者调用setWillNotDraw(false)方法,也会调用onDraw方法
        setBackgroundColor(Color.TRANSPARENT);
        setGravity(Gravity.CENTER_VERTICAL);// 设置对其方式为垂直居中
        // 获取屏幕的宽度
        WindowManager wm = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics dm = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(dm);
        screenWidth = dm.widthPixels;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int left = blockLeft;
        int top = blockTop;
        int right = blockLeft + blockWidth;
        int bottom = blockHeight + blockTop;
        // 绘制滑块
        canvas.drawRect(left, top, right, bottom, paint);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // 计算每个滑块的宽度
        blockWidth = screenWidth / visibleTitleCount;
        titleLength = titles.length;// 给标题个数赋值
        // 计算加入标题后的宽度,这里是总的标题的个数乘以每个标题的宽度
        int width = titleLength * blockWidth;
        int height = getMeasuredHeight();// 得到测量的高度
        int topGap = dp2px(5);// 增加一个滑块和标题的距离,不然会挨太近不好看
        blockTop = height + topGap;// 计算滑块顶部的位置
        height = height + blockHeight;
        // 重新测量宽高
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (isFirst) {
            MarginLayoutParams lp = null;
            TextView tv = null;
            // 循环添加标题
            for (int i = 0; i < titleLength; i++) {
                tv = new TextView(getContext());
                tv.setText(titles[i]);
                tv.setTextSize(16);
                tv.setTag(i);// 为了识别点击时间中点击了哪个位置的标题,这里将下表设置为tag
                tv.setGravity(Gravity.CENTER);
                lp = new MarginLayoutParams(blockWidth,
                        MarginLayoutParams.WRAP_CONTENT);
                lp.leftMargin = i * blockWidth;
                tv.setOnClickListener(this);// 设置点击事件
                addView(tv, lp);
            }
            isFirst = false;
        }
    }

    /**
     * 为Indicator设置标题栏
     * 
     * @param viewPager
     *            关联的ViewPager
     * @param titles
     *            标题数组
     * @param listener
     *            OnTitleClickListener
     */
    public void setTitles(ViewPager viewPager, String[] titles,
            OnTitleClickListener listener) {
        if (viewPager == null) {
            throw new IllegalArgumentException("ViewPager不能为空");
        }
        if (titles == null || titles.length == 0) {
            throw new IllegalArgumentException("titles不能为空,或者长度必须大于0");
        }
        this.viewPager = viewPager;
        this.titles = titles;
        viewPager.setOnPageChangeListener(this);
        this.listener = listener;
    }

    @Override
    public void onPageScrollStateChanged(int position) {

    }

    @Override
    public void onPageScrolled(int position, float fraction, int arg2) {
        // 计算滑块的左边位置
        blockLeft = (int) ((position + fraction) * blockWidth);
        moveTitle(position, fraction);
        invalidate();
    }

    @Override
    public void onPageSelected(int position) {

    }

    /**
     * 移动标题
     * 
     * @param position
     *            当前viewPager的位置
     * @param fraction
     *            百分比
     */
    private void moveTitle(int position, float fraction) {
        // 如果滑块移动到屏幕可视标题个数的倒数第1个,并且标题个数大于一屏的可是个数,则开始移动整个标题栏
        if (position >= visibleTitleCount - 2
                && titleLength > visibleTitleCount) {
            if (position >= titles.length - 2) {
                // 如果移动到了最后一个标题,则停止移动,防止后面出现空白
                return;
            }
            // 计算移动的距离
            int temp = (position - (visibleTitleCount - 2)) * blockWidth
                    + (int) (blockWidth * fraction);
            scrollTo(temp, 0);
        }
    }

    /**
     * 将dp转成px
     * 
     * @param dp
     * @return
     */
    private int dp2px(int dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
                getResources().getDisplayMetrics());
    }

    @Override
    public void onClick(View v) {
        // 得到对应的点击标题的下标
        int position = (Integer) v.getTag();
        // 计算点击的标题对应的滑块需要滑动的左边位置
        blockLeft = (int) (position * blockWidth);
        // 将ViewPager设置显示到这个标题对应的位置
        viewPager.setCurrentItem(position);
        // 回调OnTitleClickListener中的onClick方法
        if (listener != null) {
            listener.onClick(position);
        }
        // 重绘
        invalidate();
    }

    /**
     * 某个标题被点击的监听器
     * 
     * @author Administrator
     * 
     */
    public interface OnTitleClickListener {
        /**
         * 返回对应的下标
         * 
         * @param position
         */
        public void onClick(int position);
    }

}

这里简直实现了一些功能,还可以加一些自定义属性等使功能更加丰富。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值