Android BannerPager(廣告輪播)

效果圖

在這裏插入圖片描述

前言

在使用別人的ConvenientBanner也有段時間了,總感覺ConvenientBanner的寫法跟Android總體的設計模式有點衝突,使用起來不是很順手,由於目前項目時間不是很緊張,於是就自己着手來寫一個廣告輪播圖,在看了ConvenientBanner源碼之後感覺他把簡單的控件寫複雜了,沒有其他意思哈只是自己個人感覺,他依然是我們尊敬的前輩,畢竟他寫這個在我之前。SO此次來次Banner控件的代碼勞動。由於使用的核心還是Google自己的SDK中的ViewPager,所以我還是不忘本心給它命名爲BannerPager.

知識點

輪播圖的循環,參考此人博客,此處我就不累述了,畢竟是別人寫的,博客跳轉

使用

類文件 項目 apk
下載 下載 下載

以上提供所有類文件和資源文件的下載,如果是下載類文件請導入對應的文件和圖片到自己的項目,修改對應的包名爲自己項目的包名即可,apk下載安裝看效果。

(1)xml佈局

    <com.android.widget.BannerPager
        android:id="@+id/banner"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        app:duration="3000"
        app:indicatorGravity="center|bottom"
        app:indicatorSelectedResource="@drawable/shape_circle_selected"
        app:indicatorUnSelectedResource="@drawable/shape_circle_unselected"
        app:isAutoPlay="true" />

(2)attrs.xml屬性

    <declare-styleable name="BannerPager">
        <attr name="indicatorSelectedResource" format="reference" />
        <attr name="indicatorUnSelectedResource" format="reference" />
        <attr name="isAutoPlay" format="boolean" />
        <attr name="duration" format="integer" />
        <attr name="indicatorGravity">
            <flag name="left" value="3" />
            <flag name="top" value="48" />
            <flag name="right" value="5" />
            <flag name="bottom" value="80" />
            <flag name="center" value="17" />
            <flag name="center_horizontal" value="1" />
            <flag name="center_vertical" value="16" />
        </attr>
        <attr name="indicatorLayoutMargin" format="dimension" />
        <attr name="indicatorLayoutMarginLeft" format="dimension" />
        <attr name="indicatorLayoutMarginTop" format="dimension" />
        <attr name="indicatorLayoutMarginRight" format="dimension" />
        <attr name="indicatorLayoutMarginBottom" format="dimension" />
        <attr name="indicatorMargin" format="dimension" />
        <attr name="indicatorMarginLeft" format="dimension" />
        <attr name="indicatorMarginTop" format="dimension" />
        <attr name="indicatorMarginRight" format="dimension" />
        <attr name="indicatorMarginBottom" format="dimension" />
    </declare-styleable>

(3)顯示本地圖片
List可以是Uri或文件路徑或資源ID

		List<Integer> list = new ArrayList<>();
        list.add(R.mipmap.ic_banner_1);
        list.add(R.mipmap.ic_banner_2);
        list.add(R.mipmap.ic_banner_3);
        list.add(R.mipmap.ic_banner_4);
        bannerPager.setAdapter(new BannerAdapter(this, list));

(4)網絡圖片

        bannerPager.setAdapter(new IndexBannderAdapter(this, list));

		//Adapter的數據填充根據自己的需求來
        private class IndexBannderAdapter extends BannerAdapter {

        public IndexBannderAdapter(Context context, List list) {
            super(context, list);
        }

        @Override
        public int getCount() {
            return super.getCount();
        }

        @Override
        public View getView(int position, View convertView, ViewGroup container) {
            return super.getView(position, convertView, container);
        }
    }

源碼

(1)BannerPager

import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;

/**
 * Created by Relin
 * on 2018-10-09.
 * </br>
 * 輪播圖視圖頁控件,可以通過自定義的圖片顯示指示器的樣式形狀,shape圖片或者
 * 切圖都可以,頁面點擊事件{@link BannerPager#setOnPageClickListener},
 * 設置數據通過{@link BannerPager#setAdapter},同時支持設置指示器佈局的邊距
 * 和指示器本身的邊距大小,指示器的位置 {@link BannerPager#setIndicatorGravity}
 * </br>
 * rotate the map view page control, which can display the style shape of the indicator, shape or
 * all images are ok. Click on the page event {@link BannerPager#setOnPageClickListener},
 * sets the data through {@link BannerPager#setAdapter}, and supports setting the margins of the indicator layout
 * and the size of the margin of the indicator itself, and the position of the indicator.
 */

public class BannerPager extends FrameLayout implements ViewPager.OnPageChangeListener {

    //上下文
    private Context context;
    //輪播頁
    private ViewPager pager;
    //輪播數據
    private BannerAdapter adapter;
    //指示器佈局
    private LinearLayout indicatorLayout;
    //輪播控制
    private PlayHandler handler;
    //選中圖資源
    private int indicatorSelectedResource = R.drawable.shape_circle_selected;
    //未選中圖資源
    private int indicatorUnSelectedResource = R.drawable.shape_circle_unselected;
    //指示器佈局間距
    private float indicatorLayoutMargin = 0;
    //指示器佈局左間距
    private float indicatorLayoutMarginLeft = dpToPx(10);
    //指示器佈局上間距
    private float indicatorLayoutMarginTop = dpToPx(10);
    //指示器佈局右間距
    private float indicatorLayoutMarginRight = dpToPx(10);
    //指示器佈局下間距
    private float indicatorLayoutMarginBottom = dpToPx(10);
    //指示器間距
    private float indicatorMargin = 0;
    //指示器左間距
    private float indicatorMarginLeft = dpToPx(5);
    //指示器上間距
    private float indicatorMarginTop = 0;
    //指示器右間距
    private float indicatorMarginRight = dpToPx(5);
    //指示器下間距
    private float indicatorMarginBottom = 0;
    //指示器位置
    private int indicatorGravity = Gravity.BOTTOM | Gravity.CENTER;
    //是否自動播放
    private boolean isAutoPlay = true;
    //輪播時間
    private int duration = 3 * 1000;

    public BannerPager(@NonNull Context context) {
        super(context);
        initAttrs(context, null);
    }

    public BannerPager(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initAttrs(context, attrs);
    }

    public BannerPager(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttrs(context, attrs);
    }

    private void initAttrs(Context context, AttributeSet attrs) {
        this.context = context;
        handler = new PlayHandler();
        pager = new ViewPager(context);
        indicatorLayout = new LinearLayout(context);
        //自定義屬性
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BannerPager);
        indicatorSelectedResource = typedArray.getResourceId(R.styleable.BannerPager_indicatorSelectedResource, indicatorSelectedResource);
        indicatorUnSelectedResource = typedArray.getResourceId(R.styleable.BannerPager_indicatorUnSelectedResource, indicatorUnSelectedResource);
        isAutoPlay = typedArray.getBoolean(R.styleable.BannerPager_isAutoPlay, isAutoPlay);
        duration = typedArray.getInt(R.styleable.BannerPager_duration, duration);
        indicatorGravity = typedArray.getInt(R.styleable.BannerPager_indicatorGravity, indicatorGravity);
        indicatorLayoutMargin = typedArray.getDimension(R.styleable.BannerPager_indicatorLayoutMargin, indicatorLayoutMargin);
        indicatorLayoutMarginLeft = typedArray.getDimension(R.styleable.BannerPager_indicatorLayoutMarginLeft, indicatorLayoutMarginLeft);
        indicatorLayoutMarginTop = typedArray.getDimension(R.styleable.BannerPager_indicatorLayoutMarginTop, indicatorLayoutMarginTop);
        indicatorLayoutMarginRight = typedArray.getDimension(R.styleable.BannerPager_indicatorLayoutMarginRight, indicatorLayoutMarginRight);
        indicatorLayoutMarginBottom = typedArray.getDimension(R.styleable.BannerPager_indicatorLayoutMarginBottom, indicatorLayoutMarginBottom);
        indicatorMargin = typedArray.getDimension(R.styleable.BannerPager_indicatorMargin, indicatorMargin);
        indicatorMarginLeft = typedArray.getDimension(R.styleable.BannerPager_indicatorMarginLeft, indicatorMarginLeft);
        indicatorMarginTop = typedArray.getDimension(R.styleable.BannerPager_indicatorMarginTop, indicatorMarginTop);
        indicatorMarginRight = typedArray.getDimension(R.styleable.BannerPager_indicatorMarginRight, indicatorMarginRight);
        indicatorMarginBottom = typedArray.getDimension(R.styleable.BannerPager_indicatorMarginBottom, indicatorMarginBottom);
        typedArray.recycle();
    }

    @Override
    protected void onFinishInflate() {
        //圖片
        LayoutParams pagerParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
        pager.setLayoutParams(pagerParams);
        addView(pager);
        //指示器容器
        LayoutParams indicatorLayoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        Log.e("RRL","indicatorGravity:"+indicatorGravity);
        indicatorLayoutParams.gravity = indicatorGravity;
        if (indicatorLayoutMargin != 0) {
            indicatorLayoutParams.leftMargin = (int) indicatorLayoutMargin;
            indicatorLayoutParams.topMargin = (int) indicatorLayoutMargin;
            indicatorLayoutParams.rightMargin = (int) indicatorLayoutMargin;
            indicatorLayoutParams.bottomMargin = (int) indicatorLayoutMargin;
        } else {
            indicatorLayoutParams.leftMargin = (int) indicatorLayoutMarginLeft;
            indicatorLayoutParams.topMargin = (int) indicatorLayoutMarginTop;
            indicatorLayoutParams.rightMargin = (int) indicatorLayoutMarginRight;
            indicatorLayoutParams.bottomMargin = (int) indicatorLayoutMarginBottom;
        }
        indicatorLayout.setLayoutParams(indicatorLayoutParams);
        indicatorLayout.setOrientation(LinearLayout.HORIZONTAL);
        addView(indicatorLayout);
        super.onFinishInflate();
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        if (pager.getCurrentItem() == 0) {
            setCurrentIndicator(adapter.getCount() - 2);
        }
        if (pager.getCurrentItem() == adapter.getCount() - 1) {
            setCurrentIndicator(1);
        }
    }

    @Override
    public void onPageSelected(int position) {
        setCurrentIndicator(position);
    }

    @Override
    public void onPageScrollStateChanged(int state) {
        if (state != ViewPager.SCROLL_STATE_IDLE) {
            return;
        }
        if (pager.getCurrentItem() == 0) {
            pager.setCurrentItem(adapter.getCount() - 2, false);
        }
        if (pager.getCurrentItem() == adapter.getCount() - 1) {
            pager.setCurrentItem(1, false);
        }
    }

    /**
     * 設置當前指示器位置
     *
     * @param position
     */
    private void setCurrentIndicator(int position) {
        for (int i = 0; i < adapter.getCount(); i++) {
            ImageView indicator = (ImageView) indicatorLayout.getChildAt(i);
            if (i == position) {
                indicator.setImageResource(indicatorSelectedResource);
            } else {
                indicator.setImageResource(indicatorUnSelectedResource);
            }
        }
    }

    /**
     * 播放控制器
     */
    private class PlayHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            pager.setCurrentItem(pager.getCurrentItem() + 1);
            play();
        }
    }

    /**
     * 播放跳轉
     */
    public void play() {
        if (handler != null) {
            handler.sendEmptyMessageDelayed(1, duration);
        }
    }

    /**
     * 停止跳轉
     */
    public void stop() {
        if (handler != null) {
            handler.removeMessages(1);
        }
    }

    /**
     * 銷燬 - 防止內容泄露
     */
    public void destory() {
        if (handler != null) {
            handler.removeCallbacksAndMessages(null);
            handler = null;
        }
    }

    /**
     * 設置頁面轉變動畫 - 同ViewPager
     *
     * @param reverseDrawingOrder
     * @param transformer
     */
    public void setPageTransformer(boolean reverseDrawingOrder, ViewPager.PageTransformer transformer) {
        pager.setPageTransformer(reverseDrawingOrder, transformer);
    }

    /**
     * 設置頁面轉變動畫 - 同ViewPager
     *
     * @param reverseDrawingOrder
     * @param transformer
     * @param pageLayerType
     */
    public void setPageTransformer(boolean reverseDrawingOrder, ViewPager.PageTransformer transformer, int pageLayerType) {
        pager.setPageTransformer(reverseDrawingOrder, transformer, pageLayerType);
    }

    private OnPageClickListener listener;

    public interface OnPageClickListener {
        void onPageClick(int position);
    }

    /**
     * 設置頁面改變監聽
     *
     * @param listener
     */
    public void setOnPageClickListener(OnPageClickListener listener) {
        this.listener = listener;
        if (adapter != null) {
            adapter.setOnPageClickListener(listener);
        }
    }

    /**
     * 設置數據適配器
     *
     * @param adapter
     */
    public void setAdapter(BannerAdapter adapter) {
        this.adapter = adapter;
        this.adapter.setOnPageClickListener(listener);
        pager.setAdapter(adapter);
        pager.addOnPageChangeListener(this);
        //指示器
        for (int i = 0; i < (adapter == null ? 0 : adapter.getCount()); i++) {
            LinearLayout.LayoutParams indicatorImageParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
            if (indicatorMargin != 0) {
                indicatorImageParams.setMargins((int) indicatorMargin, (int) indicatorMargin, (int) indicatorMargin, (int) indicatorMargin);
            } else {
                indicatorImageParams.setMargins((int) indicatorMarginLeft, (int) indicatorMarginTop, (int) indicatorMarginRight, (int) indicatorMarginBottom);
            }
            ImageView indicator = new ImageView(context);
            indicator.setLayoutParams(indicatorImageParams);
            //指示器樣式
            if (i == 1) {
                indicator.setImageResource(indicatorSelectedResource);
            } else {
                indicator.setImageResource(indicatorUnSelectedResource);
            }
            if (i == 0 || i == adapter.getCount() - 1) {
                indicator.setVisibility(GONE);
            }
            //添加指示器到容器
            indicatorLayout.addView(indicator, indicatorImageParams);
        }
        pager.setCurrentItem(1);
        if (isAutoPlay) {
            play();
        }
    }

    /**
     * 設置選中的指示器的圖片
     *
     * @param indicatorSelectedResource
     */
    public void setSelectedIndicatorResource(int indicatorSelectedResource) {
        this.indicatorSelectedResource = indicatorSelectedResource;
    }

    /**
     * 設置未選中的指示器的圖片
     *
     * @param indicatorUnSelectedResource
     */
    public void setUnindicatorSelectedResource(int indicatorUnSelectedResource) {
        this.indicatorUnSelectedResource = indicatorUnSelectedResource;
    }

    /**
     * 設置指示器佈局的外間距
     *
     * @param indicatorLayoutMargin
     */
    public void setIndicatorLayoutMargin(float indicatorLayoutMargin) {
        this.indicatorLayoutMargin = dpToPx(indicatorLayoutMargin);
    }

    /**
     * 設置指示器佈局的左邊間距
     *
     * @param indicatorLayoutMarginLeft
     */
    public void setIndicatorLayoutMarginLeft(float indicatorLayoutMarginLeft) {
        this.indicatorLayoutMarginLeft = dpToPx(indicatorLayoutMarginLeft);
    }

    /**
     * 設置指示器佈局的上邊間距
     *
     * @param indicatorLayoutMarginTop
     */
    public void setIndicatorLayoutMarginTop(float indicatorLayoutMarginTop) {
        this.indicatorLayoutMarginTop = dpToPx(indicatorLayoutMarginTop);
    }

    /**
     * 設置指示器佈局的右邊間距
     *
     * @param indicatorLayoutMarginRight
     */
    public void setIndicatorLayoutMarginRight(float indicatorLayoutMarginRight) {
        this.indicatorLayoutMarginRight = dpToPx(indicatorLayoutMarginRight);
    }

    /**
     * 設置指示器佈局的下邊間距
     *
     * @param indicatorLayoutMarginBottom
     */
    public void setIndicatorLayoutMarginBottom(float indicatorLayoutMarginBottom) {
        this.indicatorLayoutMarginBottom = dpToPx(indicatorLayoutMarginBottom);
    }

    /**
     * 設置指示器之間的間距
     *
     * @param indicatorMargin
     */
    public void setIndicatorMargin(float indicatorMargin) {
        this.indicatorMargin = dpToPx(indicatorMargin);
    }

    /**
     * 設置指示器之間的間距
     *
     * @param indicatorMarginLeft
     */
    public void setIndicatorMarginLeft(float indicatorMarginLeft) {
        this.indicatorMarginLeft = dpToPx(indicatorMarginLeft);
    }

    /**
     * 設置指示器之間的上間距
     *
     * @param indicatorMarginTop
     */
    public void setIndicatorMarginTop(float indicatorMarginTop) {
        this.indicatorMarginTop = indicatorMarginTop;
    }

    /**
     * 設置指示器之間的右間距
     *
     * @param indicatorMarginRight
     */
    public void setIndicatorMarginRight(float indicatorMarginRight) {
        this.indicatorMarginRight = indicatorMarginRight;
    }

    /**
     * 設置指示器之間的下間距
     *
     * @param indicatorMarginBottom
     */
    public void setIndicatorMarginBottom(float indicatorMarginBottom) {
        this.indicatorMarginBottom = indicatorMarginBottom;
    }

    /**
     * 設置指示器的位置
     *
     * @param gravity
     */
    public void setIndicatorGravity(int gravity) {
        this.indicatorGravity = gravity;
    }

    /**
     * 是否自動播放
     *
     * @return
     */
    public boolean isAutoPlay() {
        return isAutoPlay;
    }

    /**
     * 設置自動播放
     *
     * @param autoPlay
     */
    public void setAutoPlay(boolean autoPlay) {
        isAutoPlay = autoPlay;
    }

    /**
     * 獲取Pager對象
     *
     * @return
     */
    public ViewPager getPager() {
        return pager;
    }

    /**
     * 獲取數據適配器
     *
     * @return
     */
    public BannerAdapter getAdapter() {
        return adapter;
    }

    /**
     * 設置輪播時間
     *
     * @param duration
     */
    public void setDuration(int duration) {
        this.duration = duration;
    }

    public static float dpToPx(float dp) {
        return dp * getScreenDensity();
    }

    public static float getScreenDensity() {
        return Resources.getSystem().getDisplayMetrics().density;
    }

}

(2)BannerAdapter

import android.content.Context;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

import java.util.List;

/**
 * Created by Relin
 * on 2018-10-09.
 */
public class BannerAdapter<T> extends PagerAdapter {

    private Context context;
    private List<T> list;
    private BannerPager.OnPageClickListener listener;

    public BannerAdapter(Context context, List<T> list) {
        this.context = context;
        this.list = list;
        if (getCount() > 0) {
            this.list.add(0, list.get((getCount() - 1)));
            this.list.add(list.get(1));
        }
    }

    public void setOnPageClickListener(BannerPager.OnPageClickListener listener) {
        this.listener = listener;
    }

    @Override
    public int getCount() {
        return list == null ? 0 : list.size();
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view == object;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        return getView(position, null, container);
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View) object);
    }

    public View getView(final int position, View convertView, ViewGroup container) {
        ViewHolder holder;
        if (convertView == null) {
            holder = new ViewHolder();
            convertView = new ImageView(context);
            holder.target = (ImageView) convertView;
            holder.target.setScaleType(ImageView.ScaleType.FIT_XY);
            convertView.setTag(holder);
        }
        holder = (ViewHolder) convertView.getTag();
        Object object = list.get(position);
        if (object instanceof Integer) {
            holder.target.setImageResource((int) object);
        }
        if (object instanceof String) {
            holder.target.setImageBitmap(BitmapFactory.decodeFile((String) object));
        }
        if (object instanceof Uri) {
            holder.target.setImageURI((Uri) object);
        }
        container.addView(holder.target);
        convertView = holder.target;
        convertView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (listener != null) {
                    listener.onPageClick(position - 1);
                }
            }
        });
        return convertView;
    }

    public class ViewHolder {
        private ImageView target;
    }

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章