效果圖
前言
在使用別人的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;
}
}