美文网首页Android优秀开源Android开发Android潜修者
自己造轮子--一款实用的Android广告栏实现过程(二)

自己造轮子--一款实用的Android广告栏实现过程(二)

作者: dongjunkun | 来源:发表于2016-01-05 11:11 被阅读3621次

    这一篇是接着自己造轮子--一款实用的Android广告栏实现过程(一)写的,没看过的先看上一篇,在上一篇中我提到对轮子的要求,也分析了部分关键实现代码(轮播,修复原生切换速度过快问题,自动切换),今天分析剩余的部分,github地址BannerLayoutDemo

    bannerLayoutDemo.gif

    添加指示器--绘制指示器样式

    github上也有各种各样很棒的指示器,可作为独立控件,这里我先简单处理直接集成到内部,后期有需求再进行重构,最简单的指示器是用两张不同状态的小图片做的,但我认为这样做相对实现是简单的,但对于修改却显得有些麻烦,适配也是问题,简单修改何必大动干戈呢?

    这里借鉴了daimajia的思路,指示器是用代码绘出来的,怎么绘呢?看代码,以选中的状态为例,绘制一次便可,将drawable存起来使用:

    Drawable selectedDrawable;
    GradientDrawable selectedGradientDrawable = new GradientDrawable();
    //设置指示器的颜色
    selectedGradientDrawable.setColor(selectedIndicatorColor);
    //设置指示器的形状
    selectedGradientDrawable.setShape(GradientDrawable.RECTANGLE);
    //设置指示器的大小
    selectedGradientDrawable.setSize(selectedIndicatorWidth, selectedIndicatorHeight);
    selectedLayerDrawable = new LayerDrawable(new Drawable[]{selectedGradientDrawable});
    selectedDrawable = selectedLayerDrawable;
    

    这样指示器的形状,大小,颜色可以随意换了,支持换肤也更容易

    添加指示器--位置

    大家都知道在xml文件中使用RelativeLayout父布局可以控制子布局的位置,用代码怎么去做呢?首先,BannerLayout是继承与RelativeLayout的,看代码

      RelativeLayout.LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
      switch (indicatorPosition) {
          case centerBottom://下中
              params.addRule(RelativeLayout.CENTER_HORIZONTAL);
              params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
              break;
          case rightBottom://右下
              params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
              params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
              break;
      }
    //添加指示器容器布局到BannerLayout
     addView(indicatorContainer, params);
    

    两个属性必须分开添加不能写成

    params.addRule(RelativeLayout.ALIGN_PARENT_RIGHT|RelativeLayout.ALIGN_PARENT_BOTTOM);
    

    如何设置指示器margin和padding这里就不再多说

    切换指示器

    我之前的想法是这样的,不用循环做,只需知道上一个选中的页面和即将要跳转的页面位置即可,实现思路是这样的

    private void switchIndicator(int currentPosition) {
        if (oldPosition != -1){
            ((ImageView)indicatorContainer.getChildAt(oldPosition)).setImageDrawable(unSelectedDrawable);
        }
        ((ImageView)indicatorContainer.getChildAt(currentPosition)).setImageDrawable(selectedDrawable);
        oldPosition = currentPosition;
    }~~~
    但实际的运行效果却可能出现错乱的现象,不知是哪里出了问题,目前就采用了循环来做,后期可能会改进,这样做虽然简单,但效率始终不高
    

    private void switchIndicator(int currentPosition) {
    for (int i = 0; i < indicatorContainer.getChildCount(); i++) {
    ((ImageView) indicatorContainer.getChildAt(i)).setImageDrawable(i == currentPosition ? selectedDrawable : unSelectedDrawable);
    }
    }~~~

    添加页面点击监听回调

    用法就像ListView的setOnItemClickListener一样,来看看代码如何实现

    private OnBannerItemClickListener onBannerItemClickListener;
    //给每个页面添加点击事件
     imageView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (onBannerItemClickListener != null) {
                        //不直接处理点击事件,转交给onBannerItemClickListener
                        onBannerItemClickListener.onItemClick(position);
                    }
                }
            });
    public void setOnBannerItemClickListener(OnBannerItemClickListener onBannerItemClickListener) {
        this.onBannerItemClickListener = onBannerItemClickListener;
    }
    public interface OnBannerItemClickListener {
        void onItemClick(int position);
    }~~~
    使用
    

    bannerLayout.setOnBannerItemClickListener(new BannerLayout.OnBannerItemClickListener() {
    @Override
    public void onItemClick(int position) {
    //处理点击事件
    }
    });

    ####遇到的一些坑
    上篇讲到了[BGABanner-Android](https://github.com/bingoogolapple/BGABanner-Android),部分思想也是参考这个库的,例如指示器位置的处理方案,但我要说的坑也在这里,低于3张图片就会直接抛异常,我试着将异常不抛出看看,一张或者两张图片的时候切换效果惨不忍睹(我猜想和ViewPager的懒加载机制有关),所以作者处理为直接抛异常,但这样不行啊,需求不可控制啊,必须解决这个问题,不然就像定时炸弹。
    
    问题解决思路:既然轮播是伪的,图片的张数也可以是伪的,只需要给用户看起来是那样就行了,1张也可以是3x1张相同的图片,2张也可以是2x2张相同图片,3张及以上没问题就无需处理,关键代码
    

    //添加本地图片路径
    public void setViewRes(List<Integer> viewRes) {
    List<View> views = new ArrayList<>();
    itemCount = viewRes.size();
    //主要是解决当item为小于3个的时候滑动有问题,这里将其拼凑成3个以上
    if (itemCount < 1) {//当item个数0
    throw new IllegalStateException("item count not equal zero");
    } else if (itemCount < 2) {//当item个数为1
    views.add(getImageView(viewRes.get(0), 0));
    views.add(getImageView(viewRes.get(0), 0));
    views.add(getImageView(viewRes.get(0), 0));
    } else if (itemCount < 3) {//当item个数为2
    views.add(getImageView(viewRes.get(0), 0));
    views.add(getImageView(viewRes.get(1), 1));
    views.add(getImageView(viewRes.get(0), 0));
    views.add(getImageView(viewRes.get(1), 1));
    } else {
    for (int i = 0; i < viewRes.size(); i++) {
    views.add(getImageView(viewRes.get(i), i));
    }
    }
    setViews(views);
    }~~~
    添加网络地址和本地的思路差不多,使用的是Glide来处理加载网络图片,还有就是添加各种自定义属性。

    github地址BannerLayoutDemo

    完整代码实现请看源码,欢迎fork和star以及提出你宝贵的意见

    相关文章

      网友评论

      • Stop_c9f0:楼主,我在github上看到您的轮播图,BannerLayout,图片加载不出来,是怎么回事
        dongjunkun:@9ce5befcfcae 很有可能是没有添加访问网络权限
        9ce5befcfcae:也是一片空白
      • 程思扬:大神,为什么我的设置本地的就不行呢?没有bannerLayout.setViewRes(viewRes);这个方法
      • 安卓Boy:楼主我想请教一下:如果只有一张图的话, 如果禁止用户滑动呢?
        9ce5befcfcae:一张图片 也在滚动 怎么解决
        91db36c26db9:同问,请问你现在解决一张图片的问题了吗
      • e729c7ba6f60:可以做成悬浮的吗
        c20bd44387f5:楼主 你好 !我也在用你的bannerlayout 但遇到个问题 我怎么将解析的数据中的图片适配上去?总感觉少个适配器 指教
        安卓Boy:楼主我想请教一下:如果只有一张图的话, 如果禁止用户滑动呢?
        dongjunkun:@e729c7ba6f60 啥意思
      • 674fa1c36ad3:设置指示器 为何要用LayerDrawable包一层呢?我直接用GradientDrawable 也是可以使用的啊?不是很明白 求指导~
      • 8797e0d3f45b:请问一下怎么可以获得当前的position?
      • IvorHu:你好,关于切换指示器,用不循环的方法我试了也不会出现错乱。想请问下错乱是出现在什么场景下?如果在indicatorContainer.addView(indicator)之前,给每个indicator.setTag(i)呢,能够解决错乱?
      • bf76daf41d17:android studio中gradle加入compile 'com.github.dongjunkun:BannerLayout:1.0.3'后出现failed to resolve,请问是什么原因?
      • sunmoon:github上的代码写得很好啊,学习中。但发现两个小问题,提交pull request了
        dongjunkun:@sunmoon 多多指教
      • __Berial___:扫了一下写的源码,当界面销毁时,handler 持有 pager 的对象,应该会造成内存泄露吧。
        dongjunkun:@__Berial___ 嗯,谢谢提醒
      • 曾樑:gogogo

      本文标题:自己造轮子--一款实用的Android广告栏实现过程(二)

      本文链接:https://www.haomeiwen.com/subject/uzcwhttx.html