VerticalBannerView使用方法及解析

本文介绍了一款模仿淘宝头条的自定义轮播控件,通过简单的代码实现垂直轮播效果。包括Model定义、Adapter适配器及MainActivity集成。

这一次要介绍的是一个简单的类似淘宝头条的自定义控件,

首先先展示一下具体的效果

实现了一个自定义item的轮换
下面给出一下具体的使用方法
首先是item的Model

public class Model {
      private ImageView picture;//item的图片
      public String  title;   //item的标题
      public String content;  //item的内容
    //构造方法
      public Model(String title, String content){
            this.content=content;
            this.title=title;
      }

}


然后需要一个适配器Adapter
public class MyAdapter extends BaseBannerAdapter<Model> //继承的是BaseBannerAdapter泛型为Model{
    private List<Model> myData;   //Model的数据list

   //构造方法
    public MyAdapter(List<Model> datas) {
        super(datas);
    }


   //重写getView方法
    @Override
    public View getView(VerticalBannerView parent) {
        return LayoutInflater.from(parent.getContext()).inflate(R.layout.item,null);//绑定item布局
    }

   //设置item
    @Override
    public void setItem(View view, Model data) {
        TextView title,content;
       //绑定id
        title= (TextView) view.findViewById(R.id.title);
        content= (TextView) view.findViewById(R.id.content);
       //赋值
        title.setText(data.title);
        content.setText(data.content);
    }
}



接下去给出MainActivity
public class MainActivity extends AppCompatActivity { 
private VerticalBannerView vbv; 
@Override  protected void onCreate(Bundle savedInstanceState) { 
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main); 
         vbv= (VerticalBannerView) findViewById(R.id.vbv);
          List<Model> list=new ArrayList<Model>(); 
          for(int i=0;i<10;i++){
            list.add(new Model("title"+i,"saber"+i));
        }
        MyAdapter myAdapter=new MyAdapter(list); 
       vbv.setAdapter(myAdapter); 
        vbv.start();//注意要start
    }
}


layout的代码很简单就不给出了 
这样就实现了类似淘宝头条的功能
我们来进一步地看一下VerticalBannerView的源代码
public class VerticalBannerView extends LinearLayout implements BaseBannerAdapter.OnDataChangedListener
 
 
 
 
从一开始看出来这其实是一个布局
继承于Layout 实现了数据变化的一个监听器

然后是一些变量
    private float mBannerHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,40,getResources().getDisplayMetrics());//高度
    private int mGap = 4000;     //切换时间
    private int mAnimDuration = 1000;//每次切换动画的时间

    private BaseBannerAdapter mAdapter; //适配器
    //两个先后View
    private View mFirstView;
    private View mSecondView;
   //位置
    private int mPosition;
  //判别是否启动的bool值
    private boolean isStarted;
    private Paint mDebugPaint;
首先是第一个方法,初始化方法
    private void init(Context context, AttributeSet attrs, int defStyleAttr) {
        setOrientation(VERTICAL);
        mDebugPaint = new Paint(Paint.ANTI_ALIAS_FLAG);//抗锯齿
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.VerticalBannerView);//适应gap和animDuration
        //获取gap和animDuration
        mGap = array.getInteger(R.styleable.VerticalBannerView_gap,mGap);
        mAnimDuration = array.getInteger(R.styleable.VerticalBannerView_animDuration,mAnimDuration);
       //如果切换时间小于动画时间,即动画还没结束就又得切换,会出错,因此重置gap和animDuration
        if(mGap <= mAnimDuration){
            mGap = 4000;
            mAnimDuration = 1000;
        }

        array.recycle();//缓存的作用,实现重复调用此对象的功能
    }
然后是setAdapter方法
    public void setAdapter(BaseBannerAdapter adapter){
        if(adapter == null){
            throw new RuntimeException("adapter must not be null");
        }
        if(mAdapter != null){
            throw new RuntimeException("you have already set an Adapter");
        }
        this.mAdapter = adapter;
        mAdapter.setOnDataChangedListener(this);//设置监听
        setupAdapter();
    }
继续看setupAdapter方法
    private void setupAdapter() {
        removeAllViews();//移除View

        if(mAdapter.getCount() == 1){
            mFirstView = mAdapter.getView(this);
            mAdapter.setItem(mFirstView,mAdapter.getItem(0));
            addView(mFirstView);
        }else{
            mFirstView = mAdapter.getView(this);
            mSecondView = mAdapter.getView(this);
            mAdapter.setItem(mFirstView,mAdapter.getItem(0));
            mAdapter.setItem(mSecondView,mAdapter.getItem(1));
            addView(mFirstView);
            addView(mSecondView);

            mPosition = 1;
            isStarted = false;
        }
        setBackgroundDrawable(mFirstView.getBackground());
    }
这个方法主要是设置数据
Measure方法
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if(LayoutParams.WRAP_CONTENT == getLayoutParams().height){
            getLayoutParams().height = (int) mBannerHeight;
        }else{
            mBannerHeight = getHeight();
        }
        if(isInEditMode()){
            setBackgroundColor(Color.GRAY);
            return;
        }
        if(mFirstView != null){
            mFirstView.getLayoutParams().height = (int) mBannerHeight;
        }
        if(mSecondView != null){
            mSecondView.getLayoutParams().height = (int) mBannerHeight;
        }
    }
这个方法主要是适应宽高,不多加赘述
看一下onDraw方法
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if(isInEditMode()){
            mDebugPaint.setColor(Color.WHITE);
            mDebugPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,16,getResources().getDisplayMetrics()));
            mDebugPaint.setStyle(Paint.Style.STROKE);
            canvas.drawText("banner is here",20,getHeight()*2/3,mDebugPaint);
        }
    }
主要是初始的绘制
最为重要的是这一个方法
private void performSwitch(){
        //两个ObjectAnimator对应两个View
        ObjectAnimator animator1 = ObjectAnimator.ofFloat(mFirstView,"translationY",mFirstView.getTranslationY()-mBannerHeight);
        ObjectAnimator animator2 = ObjectAnimator.ofFloat(mSecondView,"translationY",mSecondView.getTranslationY()-mBannerHeight);
        //设置动画同时进行
        AnimatorSet set = new AnimatorSet();
        set.playTogether(animator1,animator2);
        set.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                mFirstView.setTranslationY(0);
                mSecondView.setTranslationY(0);
                View removedView = getChildAt(0);
                mPosition++;
                mAdapter.setItem(removedView,mAdapter.getItem(mPosition%mAdapter.getCount()));
                removeView(removedView);
                addView(removedView,1);
            }

        });
        set.setDuration(mAnimDuration);
        set.start();
    }
Adapter的部分源码较为简单,基本是数据的填充和设置样式,不过多赘述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值