Android自定义Viewpager指示器PagerIndicator-仿微博头条效果

平时工作之余,喜欢看看新闻,手机难免会装了几个新闻阅读类的app。新闻类的app风格大致一致,可以选择不同栏目,栏目可以切换。最近就在用微博头条,感觉界面挺清新的。而且它使用的PagerIndicator挺好看的。昨晚居然准时下班了,趁着早就实现了下。今天用博客好好记录下

上图

图片描述

效果分析

1 每个tab都包含色块和文字,而且文字的显示个数不同

2 文字:由未选中到被选中的文字颜色从黑色变成白色;由选中到未被选中的文字颜色从白色变成黑色

3 色块:由未选中到被选中的色块显示高度越来越大;由选中到未被选中的色块显示高度越来越小

4 让处于中间的tab自动滑动到中间显示

实现思路

1 tab实现

1.1 自定义UpDownView,该View继承RelativeLayout

1.2 文字使用TextView显示,色块使用ImageView显示

public UpDownView(Context context, AttributeSet attrs) {
    super(context, attrs);
    imageView = new ImageView(context);
    // 设置ImageView的大小为每个父View(tab)的大小
    LayoutParams imageParams = new LayoutParams(
                    LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    addView(imageView, imageParams);
    textView = new TextView(context);
    // 设置TextView的文字居中显示
    textView.setGravity(Gravity.CENTER);
    // 设置TextView的高度为每个父View(tab)的高度
    LayoutParams textParams = new LayoutParams(
                    LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
    textParams.addRule(RelativeLayout.CENTER_IN_PARENT);
    textView.setPadding(40, 10, 40, 10);
    addView(textView, textParams);
}

1.3 ImageView显示设置

// 当控件的宽高发生变化时回调该方法,可在这里获取控件的高度
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    height = textView.getMeasuredHeight();
    // 通过setTranslationY让ImageView开始时只显示总高度的0.2f
    imageView.setTranslationY((int) (height * 0.8f));
    LayoutParams imageParams = (LayoutParams) imageView
                    .getLayoutParams();
    imageParams.width = textView.getMeasuredWidth();
}

1.4 该View对外提供的方法

// 设置ImageView的颜色
public void setImageColor(int color) {
    imageView.setImageResource(color);
}
// 设置文字
public void setText(String text) {
    textView.setText(text);
}
// 设置文字的颜色
public void setTextColor(int color) {
    textView.setTextColor(color);
}
// 显示色块
public void show() {
    ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView,
            "translationY", 0);
    objectAnimator.setDuration(300);
    objectAnimator.start();
}
// 设置ImageView的偏移量,即改变色块显示的高度
public void setTranslation(float direction) {
    imageView.setTranslationY(direction);
}
// 隐藏色块
public void hide() {
    ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView,
            "translationY", (int) (height * 0.8f));
    objectAnimator.setDuration(300);
    objectAnimator.start();
}
// 主要用于获取当前色块所在的位置
public int getmIndex() {
    return mIndex;
}

2 PagerIndicator指示器的实现

2.1 指示器可以装载很多的tab,而且支持横向滑动,于是可以选择继承HorizontalScrollView

2.2 由于HorizontalScrollView只能有一个子View,所以在初始化的时候,为该View添加一个默认的子View,当需要添加tab时,将其添加到默认的子View中即可。

public PagerIndicatorTwo(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.context = context;
    // 设置横向滚动条不显示
    setHorizontalScrollBarEnabled(false);
    // 添加一个LinearLayout作为默认的子View
    linearLayout = new LinearLayout(context);
    linearLayout.setOrientation(LinearLayout.HORIZONTAL);
    LayoutParams liLayoutParams = new LayoutParams(
            LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
    addView(linearLayout, liLayoutParams);
}

2.3 与ViewPager绑定

public void setmViewPager(ViewPager viewPager) {
    this.mViewPager = viewPager;
    if (mViewPager.getAdapter() == null) {
        throw new NullPointerException();
    }
    // 该PagerIndicator实现了OnPageChangeListener接口,当ViewPager发生变化时,会回调OnPageChangeListener相应的方法,通过这些方法,可以完成指示器相应的变化
    this.mViewPager.setOnPageChangeListener(this);
}

2.4 设置tab

public void setIndicators(List<String> indicators) {
    this.indicators.clear();
    this.indicators.addAll(indicators);
    linearLayout.removeAllViews();
    // 创建对应个数的UpDownView,并添加到linearLayout中去
    for (int i = 0; i < indicators.size(); i++) {
        UpDownView upDownView = new UpDownView(context);
        upDownView.setGravity(Gravity.CENTER);
        upDownView.setImageColor(colors[i % 3]);
        // 设置每个tab所在的位置
        upDownView.mIndex = i;
        upDownView.setText(indicators.get(i));
        // 为每个tab增加点击事件
        upDownView.setOnClickListener(onTadClickListener);

        LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
                LayoutParams.MATCH_PARENT);
        linearLayout.addView(upDownView, params);
    }
    requestLayout();
}

2.5 tab点击事件

private OnClickListener onTadClickListener = new OnClickListener() {
    @Override
    public void onClick(View view) {
        tabClick = true;
        UpDownView upDownView = (UpDownView) view;
        // 获取到tab所在的位置,调用ViewPager的setCurrentItem切换页面
        mViewPager.setCurrentItem(upDownView.mIndex);
    }
};

2.6 onPageScrolled的回调(即滑动ViewPager产生的变化处理):该方法有三个参数,通过这三个参数的变化,改变每个tab对应的变化即可;这里有个学习点,就是颜色的变化可以通过ArgbEvaluator这个类实现

leftDownView = (UpDownView) linearLayout.getChildAt(arg0);
rightDownView = (UpDownView) linearLayout.getChildAt(arg0 + 1);
// 色条变化
leftDownView.setTranslation(arg1 * leftDownView.height * 0.8f);
rightDownView.setTranslation((1 - arg1) * rightDownView.height
        * 0.8f);
// 文字颜色变化
int leftColor = (Integer) new ArgbEvaluator().evaluate(arg1,
        Color.WHITE, Color.BLACK);
leftDownView.setTextColor(leftColor);
int rightColor = (Integer) new ArgbEvaluator().evaluate(1 - arg1,
        Color.WHITE, Color.BLACK);
rightDownView.setTextColor(rightColor);

2.7 自动滑动到中间位置

// 当某一项被选中时会回调onPageSelected方法,在这里我们可以让该PagerIndicator自动滚动:这里主要涉及到移动距离的计算
public void changePager(final int last) {
    final UpDownView lastChild = (UpDownView) linearLayout.getChildAt(last);
    int[] location = new int[2];
    lastChild.getLocationOnScreen(location);
    final int scrollPos = location[0]
            - (getMeasuredWidth() - lastChild.getMeasuredWidth()) / 2;
    smoothScroll(scrollPos, new AnimatorListenerAdapter() {
    });

}

3 外边调用OnPageChangeListener问题

由于该PagerIndicator需要根据OnPageChangeListener的回调变化,所以需要在PagerIndicator中实现该接口,并设置给ViewPager。这就产生个问题,假如项目在使用ViewPager时也需要根据OnPageChangeListener的回调进行某些处理该怎么处理。这个问题可以这样子处理

3.1 在项目中,不调用ViewPager.setOnPageChangeListener,而是PagerIndicator.setOnPageChangeListener,即将回调设置给PagerIndicator,这样就可以正常监听该接口了

3.2 看内部处理

// 将传递进来的OnPageChangeListener对象保存到onPageChangeListener中
private OnPageChangeListener onPageChangeListener;

public void setOnPageChangeListener(
        OnPageChangeListener onPageChangeListener) {
    this.onPageChangeListener = onPageChangeListener;
}
// 当PagerIndicator中的onPageScrollStateChanged方法被调用时,我们手动调用传进来的onPageChangeListener的onPageScrollStateChanged(arg0)方法,其他回调方法一样
@Override
public void onPageScrollStateChanged(int arg0) {
    if (mViewPager.getAdapter().getCount() != indicators.size()) {
        return;
    }
    onPageChangeListener.onPageScrollStateChanged(arg0);
}

总结

至此,一个仿微博头条效果的PagerIndicator就实现了。当然我们可以自定义一些属性,例如文字颜色和大小,ImageView的颜色等,用于设置想要的一些显示。提高该View的灵活性

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值