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

这一篇是接着自己造轮子--一款实用的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以及提出你宝贵的意见

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 210,914评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,935评论 2 383
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,531评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,309评论 1 282
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,381评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,730评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,882评论 3 404
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,643评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,095评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,448评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,566评论 1 339
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,253评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,829评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,715评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,945评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,248评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,440评论 2 348

推荐阅读更多精彩内容