Android高仿京東淘寶自動無限循環輪播控件的實現思路和過程

在App的開發中,不少的時候都須要實現相似京東淘寶同樣的自動無限輪播的廣告欄,因此就本身寫了一個,下面是我自定義控件的實現思路和過程。android

1、自定義控件屬性git

新建自定義控件SliderLayout繼承於RelativeLayout,首先要考慮的就是自定義的控件須要擴展那些屬性,把這些屬性列出來。在這裏是要實現相似於京東淘寶的無限輪播廣告欄,那麼首先想到的就是輪播的時長、輪播指示器的樣式等等。我在這裏列舉了一些而且結合到了代碼中。github

一、擴展屬性網絡

(1)是否開啓自動輪播的功能。框架

(2)指示器的圖形樣式,通常爲圓形和方形兩種。ide

(3)指示器的位置,通常爲底部或者頂部。函數

(4)指示器被選中和不被選中時的樣式:顏色、高度、寬度、間隔等。動畫

(5)輪播的時長。url

(6)加載的若是是網絡圖片的話,須要默認圖片和錯誤圖片等。spa

 

二、在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>

2、自定義輪播控件的初始化

一、獲取到擴展屬性的值

在自定義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         }

二、初始化控件

根據這裏所須要實現的功能,首先須要一個圖像切換器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         }

三、初始化選中第一張圖片

專門寫一個針對指示器切換的函數,而後在初始化的時候直接調用,選中第一個指示器,就是選中第一張圖片了。

函數代碼以下。

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); 

3、圖片的加載

一、網路圖片的加載

在這裏使用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     };

二、加載資源圖片

只能加載網絡圖片是不夠的呢,還須要能夠加載資源圖片,加載資源圖片的辦法就更加簡單了。

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

4、設置圖片切換的動畫

設置圖片從左往右以及從右往左的動畫效果,而且當滑動到該圖片時,指示器也要一塊兒變化,這裏就簡單說下從左往右的動畫了。

 

 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     }

 

從右往左滑動時的代碼和這個是同樣的,就是換了下方向,須要本身定義下。

5、定義圖片的點擊事件

一、定義interface來監聽事件

在自定義控件中自定義一個interface來監聽事件就能夠了。

 

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

二、在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 }

6、效果圖

說到了這裏,應該有所思路了吧,如今就來看下效果吧。

 

源代碼目前已經開放了,放在Github上面,歡迎指導建議。http://www.github.com/LT5505/SliderLayout

相關文章
相關標籤/搜索