VerticalBannerView使用方法及解析

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

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

实现了一个自定义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的部分源码较为简单,基本是数据的填充和设置样式,不过多赘述
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
现在的APP Banner大多数千篇一律,前几天看到魅族手机上所有魅族自家APP上的Banner效果不错,于是就想着来仿着做一个类似的效果。因此就有了这个库。但是为了使用方便,这个库不仅仅只有仿魅族效果的BannerView使用,还可以当作普通的BannerView使用,还可以当作一个ViewPager 来使用使用很方便,具体使用方法和API 请看后面的示例。 ---  左图为魅族APP上的Banner效果,右图是高仿效果。MZBannerView 有以下功能:1 . 仿魅族BannerView 效果。2 . 当普通Banner 使用3 . 当普通ViewPager 使用。4 . 当普通ViewPager使用(有魅族Banner效果)5 . 仿某视频网站Banner效果。Demo APKgif图片有点模糊,可以扫描下方二维码下载APK体验相关博客ViewPager系列之 仿魅族应用的广告BannerView更新日志v1.1.1 : 增加按住Banner 停止轮播,松开开始自动轮播的功能v1.1.0 : fix 在从网上获取数据后,banner 显示 造成 ANR 的bug(如果在onCreate()中设置资源显示则没问题)v1.1.2 : fix 更改数据之后,调用setPages重新刷新数据会crush的bugv2.0.0 :1,add: 添加仿魅族Banner效果,中间Page覆盖两边。 -- 2,fix 部分bug: 添加OnPageChangeListener 回调 pisition 不对的bug.DependencyAdd it in your root build.gradle at the end of repositories:allprojects {      repositories {           ...           maven { url 'https://jitpack.io' }      } }Step 2. Add the dependencydependencies {          compile 'com.github.pinguo-zhouwei:MZBannerView:v2.0.0' }自定义属性属性名属性意义取值open_mz_mode是否开启魅族模式true 为魅族Banner效果,false 则普通Banner效果canLoop是否轮播true 轮播,false 则为普通ViewPagerindicatorPaddingLeft设置指示器距离左侧的距离单位为 dp 的值indicatorPaddingRight设置指示器距离右侧的距离单位为 dp 的值indicatorAlign设置指示器的位置有三个取值:left 左边,center 剧中显示,right 右侧显示middle_page_cover设置中间Page是否覆盖(真正的魅族Banner效果)true 覆盖,false 无覆盖效果使用方法1 . xml 布局文件2 . activity中代码:mMZBanner = (MZBannerViewview.findViewById(R.id.banner);              // 设置数据         mMZBanner.setPages(list, new MZHolderCreator() {             @Override             public BannerViewHolder createViewHolder() {                 return new BannerViewHolder();             }         });  public static class BannerViewHolder implements MZViewHolder {         private ImageView mImageView;         @Override         public View createView(Context cont
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值