zoukankan      html  css  js  c++  java
  • Android高仿京东淘宝自动无限循环轮播控件的实现思路和过程

    在App的开发中,很多的时候都需要实现类似京东淘宝一样的自动无限轮播的广告栏,所以就自己写了一个,下面是我自定义控件的实现思路和过程。

    一、自定义控件属性

    新建自定义控件SliderLayout继承于RelativeLayout,首先要考虑的就是自定义的控件需要扩展那些属性,把这些属性列出来。在这里是要实现类似于京东淘宝的无限轮播广告栏,那么首先想到的就是轮播的时长、轮播指示器的样式等等。我在这里列举了一些并且结合到了代码中。

    1、扩展属性

    (1)是否开启自动轮播的功能。

    (2)指示器的图形样式,一般为圆形和方形两种。

    (3)指示器的位置,一般为底部或者顶部。

    (4)指示器被选中和不被选中时的样式:颜色、高度、宽度、间隔等。

    (5)轮播的时长。

    (6)加载的如果是网络图片的话,需要默认图片和错误图片等。

    2、在attrs.xml文件中添加这些扩展的属性。

     1 <declare-styleable name="SliderLayout">
     2         <attr name="sl_is_auto_play" format="boolean"/>
     3         <attr name="sl_indicator_shape" format="enum">
     4             <enum name="oval" value="0" />
     5             <enum name="rect" value="1" />
     6         </attr>
     7         <attr name="sl_indicator_position" format="enum">
     8             <enum name="centerBottom" value="0" />
     9             <enum name="rightBottom" value="1" />
    10             <enum name="leftBottom" value="2" />
    11             <enum name="centerTop" value="3" />
    12             <enum name="rightTop" value="4" />
    13             <enum name="leftTop" value="5" />
    14         </attr>
    15         <attr name="sl_selected_indicator_color" format="color|reference" />
    16         <attr name="sl_unselected_indicator_color" format="color|reference" />
    17 
    18         <attr name="sl_selected_indicator_height" format="dimension|reference" />
    19         <attr name="sl_selected_indicator_width" format="dimension|reference" />
    20 
    21         <attr name="sl_unselected_indicator_height" format="dimension|reference" />
    22         <attr name="sl_unselected_indicator_width" format="dimension|reference" />
    23 
    24         <attr name="sl_indicator_space" format="dimension|reference" />
    25         <attr name="sl_indicator_margin" format="dimension|reference" />
    26         <attr name="sl_auto_play_duration" format="integer|reference" />
    27         <attr name="sl_default_image" format="reference"/>
    28         <attr name="sl_error_image" format="reference"/>
    29     </declare-styleable>

    二、自定义轮播控件的初始化

    1、获取到扩展属性的值

    在自定义SliderLayout中获取到扩展的样式,然后根据样式获取相应的属性值,最好是要先设置好默认值。

     1 TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.SliderLayout, defStyleAttr, 0);
     2         if (array != null) {
     3             isAutoPlay = array.getBoolean(R.styleable.SliderLayout_sl_is_auto_play, isAutoPlay);
     4             //get the shape of indicator
     5             int intShape = array.getInt(R.styleable.SliderLayout_sl_indicator_shape, indicatorShape.ordinal());
     6             for (IndicatorShape shape : IndicatorShape.values()) {
     7                 if (shape.ordinal() == intShape) {
     8                     indicatorShape = shape;
     9                     break;
    10                 }
    11             }
    12             //get the position of indicator
    13             int intPosition = array.getInt(R.styleable.SliderLayout_sl_indicator_position, IndicatorPosition.centerBottom.ordinal());
    14             for (IndicatorPosition position : IndicatorPosition.values()) {
    15                 if (position.ordinal() == intPosition) {
    16                     indicatorPosition = position;
    17                     break;
    18                 }
    19             }
    20             unSelectedIndicatorColor = array.getColor(R.styleable.SliderLayout_sl_unselected_indicator_color, unSelectedIndicatorColor);
    21             selectedIndicatorColor = array.getColor(R.styleable.SliderLayout_sl_selected_indicator_color, selectedIndicatorColor);
    22             unSelectedIndicatorHeight = array.getDimension(R.styleable.SliderLayout_sl_unselected_indicator_height, unSelectedIndicatorHeight);
    23             unSelectedIndicatorWidth = array.getDimension(R.styleable.SliderLayout_sl_unselected_indicator_width, unSelectedIndicatorWidth);
    24             selectedIndicatorHeight = array.getDimension(R.styleable.SliderLayout_sl_selected_indicator_height, selectedIndicatorHeight);
    25             selectedIndicatorWidth = array.getDimension(R.styleable.SliderLayout_sl_selected_indicator_width, selectedIndicatorWidth);
    26             indicatorSpace = array.getDimension(R.styleable.SliderLayout_sl_indicator_space, indicatorSpace);
    27             indicatorMargin = array.getDimension(R.styleable.SliderLayout_sl_indicator_margin, indicatorMargin);
    28             autoPlayDuration = array.getInt(R.styleable.SliderLayout_sl_auto_play_duration, autoPlayDuration);
    29             defaultImage = array.getResourceId(R.styleable.SliderLayout_sl_default_image, defaultImage);
    30             errorImage = array.getResourceId(R.styleable.SliderLayout_sl_error_image, errorImage);
    31         }

    2、初始化控件

    根据这里所需要实现的功能,首先需要一个图像切换器ImageSwticher,还要指示器,这里就用ImageView了。

     1 switcherImage = new ImageSwitcher(context);
     2         switcherImage.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
     3 
     4 for (int i = 0; i < itemCount; i++) {
     5             ImageView indicator = new ImageView(context);
     6             indicator.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
     7             indicator.setPadding((int) (indicatorSpace), (int) (indicatorSpace), (int) (indicatorSpace), (int) (indicatorSpace));
     8             indicator.setImageDrawable(unSelectedDrawable);
     9             indicatorContainer.addView(indicator);
    10             final int finalI = i;
    11             indicator.setOnClickListener(new OnClickListener() {
    12                 @Override
    13                 public void onClick(View view) {
    14                     stopAutoPlay();
    15                     switchIndicator(finalI);
    16                     pictureIndex = finalI;
    17                     handler.sendEmptyMessageDelayed(START_AUTO_PLAY,autoPlayDuration);
    18                 }
    19             });
    20         }

    3、初始化选中第一张图片

    专门写一个针对指示器切换的函数,然后在初始化的时候直接调用,选中第一个指示器,就是选中第一张图片了。

    函数代码如下。

    1 private void switchIndicator(int index) {
    2         for (int i = 0; i < indicatorContainer.getChildCount(); i++) {
    3             ((ImageView) indicatorContainer.getChildAt(i)).setImageDrawable(i == index ? selectedDrawable : unSelectedDrawable);
    4         }
    5         loadImage(index);
    6     }

    调用选中第一张图。

      1 switchIndicator(0); 

    三、图片的加载

    1、网路图片的加载

    在这里使用Picasso框架来加载图片,根据url来加载显示图片,同时也要显示图片的加载进度,这里就需要一个Dialog提示框了,Dialog的样式最好是可以自定义的。

     1 private void loadNetImage(int pictureIndex) {
     2         if (list != null && list.size() != 0) {
     3             Picasso.with(context)
     4                     .load((String) list.get(pictureIndex))
     5                     .placeholder(defaultImage)
     6                     .error(errorImage)
     7                     .tag(context)
     8                     .into(mTarget);
     9         }
    10     }

    下面是图片的加载提示过程。

     1 private Target mTarget = new Target() {
     2 
     3         @Override
     4         public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
     5             dismissDialog();
     6             ((ImageView) switcherImage.getCurrentView()).setScaleType(ImageView.ScaleType.CENTER_CROP);
     7             ((ImageView) switcherImage.getCurrentView()).setLayoutParams(new ImageSwitcher.LayoutParams(ImageSwitcher.LayoutParams.MATCH_PARENT, ImageSwitcher.LayoutParams.MATCH_PARENT));
     8             ((ImageView) switcherImage.getCurrentView()).setImageBitmap(bitmap);
     9         }
    10 
    11         @Override
    12         public void onBitmapFailed(Drawable errorDrawable) {
    13             dismissDialog();
    14             ((ImageView) switcherImage.getCurrentView()).setImageDrawable(errorDrawable);
    15         }
    16 
    17         @Override
    18         public void onPrepareLoad(Drawable placeHolderDrawable) {
    19             showDialog();
    20         }
    21     };

    2、加载资源图片

    只能加载网络图片是不够的呢,还需要可以加载资源图片,加载资源图片的办法就更加简单了。

    1 private void loadFileImage(int pictureIndex) {
    2         if (list != null && list.size() != 0) {
    3             switcherImage.setImageResource((Integer) list.get(pictureIndex));
    4         }
    5     }

    四、设置图片切换的动画

    设置图片从左往右以及从右往左的动画效果,并且当滑动到该图片时,指示器也要一起变化,这里就简单说下从左往右的动画了。

     1 private void SliderLeftToRight() {
     2         // get current index
     3         pictureIndex = pictureIndex == 0 ? itemCount - 1
     4                 : pictureIndex - 1;
     5         // set Animation
     6         switcherImage.setInAnimation(AnimationUtils.loadAnimation(context,
     7                 android.R.anim.slide_in_left));
     8         switcherImage.setOutAnimation(AnimationUtils.loadAnimation(context,
     9                 android.R.anim.slide_out_right));
    10         switchIndicator(pictureIndex);
    11     }

    从右往左滑动时的代码和这个是一样的,就是换了下方向,需要自己定义下。

    五、定义图片的点击事件

    1、定义interface来监听事件

    在自定义控件中自定义一个interface来监听事件就可以了。

     

    1 public interface IOnClickListener {
    2 
    3         void onItemClick(View view, int position);
    4 
    5 }

    2、在onTouch中调用点击事件。

    这里需要说明下为什么在onTouch中处理,因为onTouch是触摸事件,在滑动的过程中,用户是触摸了屏幕的,所以根据用户触摸屏幕时点击下的X坐标和点击起来时的X坐标的对比来判断是左滑还是右滑了,这样的话,就会和onClick事件相冲了,所以就想到了一个办法,那就是在范围内的话,就默认为点击事件,范围外就是滑动事件了。

    1 if (0==(Math.abs(touchUpX - touchDownX))||(Math.abs(touchUpX - touchDownX))<50) {
    2 
    3                 if (listener != null) {
    4 
    5                     stopAutoPlay();
    6                     listener.onItemClick(view, pictureIndex);
    7                     handler.sendEmptyMessageDelayed(START_AUTO_PLAY,autoPlayDuration);
    8                 }
    9 }

    六、效果图

    说到了这里,应该有所思路了吧,现在就来看下效果吧。

    源代码目前已经开放了,放在Github上面,欢迎指导建议。http://www.github.com/LT5505/SliderLayout

  • 相关阅读:
    vim实用技巧
    《C程序设计语言》学习笔记
    《鸟哥的Linux私房菜:服务器搭建篇》第一部分学习笔记
    入职培训学习心得
    [NOI2013]树的计数
    bzoj1779 [Usaco2010 Hol]Cowwar 奶牛战争(网络流)
    P2944 [USACO09MAR]地震损失2Earthquake Damage 2(网络流)
    bzoj3218 a + b Problem(网络流+主席树)
    P4542 [ZJOI2011]营救皮卡丘(Floyd+网络流)
    P4843 清理雪道(上下界网络流)
  • 原文地址:https://www.cnblogs.com/LT5505/p/6652449.html
Copyright © 2011-2022 走看看