1. 程式人生 > >一款好用的banner輪播圖控制元件

一款好用的banner輪播圖控制元件

banner輪播圖控制元件介紹

我們在日常開發過程中經常會碰到輪播圖的需求,一般來說都是自己用ViewPager實現的,但是這種實現過程沒有經過封裝,日常呼叫起來也比較繁瑣,有著各式各樣的問題,因此我在github上找到一款非常好用的開源輪播圖控制元件banner,呼叫起來非常方便,還支援各種效果,部分效果如下圖所示。使用時的版本是1.4.9。

1
2

基本使用

要使用這個控制元件,首先我們需要在module的build.gradle中新增依賴

dependencies{
    compile 'com.youth.banner:banner:1.4.9'
}

如果要使用網路圖片或本地圖片要需要在AndroidManifest.xml新增許可權

<!-- if you want to load images from the internet -->
<uses-permission android:name="android.permission.INTERNET" /> 

<!-- if you want to load images from a file OR from the internet -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

接下來就可以使用了

最簡單的使用方法是在activity或fragment佈局檔案中

<com.youth.banner.Banner
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/banner"
    android:layout_width="match_parent"
    android:layout_height="高度自己設定" />

或者自己new出來控制元件。

設定圖片載入器繼承ImageLoader

public class GlideImageLoader extends ImageLoader {
    @Override
    public void displayImage(Context context, Object path, ImageView imageView) {
        /**
          注意:
          1.圖片載入器由自己選擇,這裡不限制,只是提供幾種使用方法
          2.返回的圖片路徑為Object型別,由於不能確定你到底使用的那種圖片載入器,
          傳輸的到的是什麼格式,那麼這種就使用Object接收和返回,你只需要強轉成你傳輸的型別就行,
          切記不要胡亂強轉!
         */
        eg:

        //Glide 載入圖片簡單用法
        Glide.with(context).load(path).into(imageView);

        //Picasso 載入圖片簡單用法
        Picasso.with(context).load(path).into(imageView);

        //用fresco載入圖片簡單用法,記得要寫下面的createImageView方法
        Uri uri = Uri.parse((String) path);
        imageView.setImageURI(uri);
    }

    //提供createImageView 方法,如果不用可以不重寫這個方法,主要是方便自定義ImageView的建立
    @Override
    public ImageView createImageView(Context context) {
        //使用fresco,需要建立它提供的ImageView,當然你也可以用自己自定義的具有圖片載入功能的ImageView
        SimpleDraweeView simpleDraweeView=new SimpleDraweeView(context);
        return simpleDraweeView;
    }
}

最後,在Activity或者Fragment中配置Banner

banner.setImages(image)
        .setImageLoader(new GlideImageLoader())
        .setOnBannerListener(this)
        .start();

實現原始碼分析

知其然還要知其所以然,我們用了這個控制元件還要知道這個控制元件是怎麼實現的。

首先我們從Banner類切入,因為它是輪播圖的實現控制元件

從原始碼中可以看到,Banner類繼承FrameLayout,然後在它的建構函式中inflate了banner.xml,這個佈局的結構如下:

<RelativeLayout
    android:clipChildren="false">
    <!--輪播圖-->
    <ViewPager
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <!--底部佈局,包括指示器,title,頁碼等-->
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true">
        ......
    </RelativeLayout>
</RelativeLayout>

同時,在初始化函式中,還初始化了自定義屬性等。

接下來我們要關注的就是這個控制元件是如何實現無限輪播的

可以看到在Activity中通過

banner.setImages(image)
        .setImageLoader(new GlideImageLoader())
        .setOnBannerListener(this)
        .start();

開啟輪播,setImages()方法設定了輪播圖的圖片路徑,配合ImageLoader載入圖片,繼承ImageLoader抽象類並重寫displayImage方法來具體實現圖片的載入邏輯,setOnBannerListener()方法設定banner的點選事件,start()方法開始輪播。

我們具體看一下start()

public Banner start() {
    setBannerStyleUI(); //設定ui
    setImageList(imageUrls); //初始化ImageViews
    setData(); //初始化ViewPager並開始播放
    return this;
}

setBannerStyleUI()

第一個函式setBannerStyleUI()用於設定UI顯示的,包括指示器樣式,標題樣式等等。

setImageList(imageUrls)

第二個函式是我們關注的重點,在這個方法中我們通過setImages()方法獲取到的物件List,來初始化輪播圖顯示的ImageView,這裡用了一個技巧來實現無限輪播:ImageView數量比圖片數量大2,imageViews.get(0)為最後一張圖片,imageViews.get(size-1)為第一張圖片

if (i == 0) {
    url = imagesUrl.get(count - 1);
} else if (i == count + 1) {
    url = imagesUrl.get(0);
} else {
    url = imagesUrl.get(i - 1);
}

這樣在滑動到第一張或者最後一張後,接下來的一張圖片是最後一張或者第一張,同時在onPageScrollStateChanged中檢測,在停止滑動的狀態下如果是最後一個ImageView或者第0個ImageView則更新ViewPager狀態,利用viewPager.setCurrentItem()方法設定其狀態為最後一張或者第一張,這樣就平滑過度了。

@Override
public void onPageScrollStateChanged(int state) {
    if (mOnPageChangeListener != null) {
        mOnPageChangeListener.onPageScrollStateChanged(state);
    }
    currentItem = viewPager.getCurrentItem();
    switch (state) {
        case 0://No operation
            if (currentItem == 0) {
                viewPager.setCurrentItem(count, false);
            } else if (currentItem == count + 1) {
                viewPager.setCurrentItem(1, false);
            }
            break;
        case 1://start Sliding 正在滑動
            if (currentItem == count + 1) {
                viewPager.setCurrentItem(1, false);
            } else if (currentItem == 0) {
                viewPager.setCurrentItem(count, false);
            }
            break;
        case 2://end Sliding
            break;
    }
}

setData()

setData()方法中初始化了ViewPager,如果開啟了自動輪播,會呼叫startAutoPlay()方法利用handler.postDelayed去自動切換ViewPager。

這裡額外提一下設定切換動畫,是利用viewPager.setPageTransformer()方法進行設定,這裡作者給我們提供了很多動畫的預設實現,如果沒有需要的切換動畫效果,就需要自己去實現PagerTransformer介面去實現自己想要的切換動畫,關於切換動畫和clipChildren屬性,這篇文章介紹的很透徹http://blog.csdn.net/u012702547/article/details/52334161

public Banner setPageTransformer(boolean reverseDrawingOrder, PageTransformer transformer) {
    viewPager.setPageTransformer(reverseDrawingOrder, transformer);
    return this;
}