Android自定义图片轮播Banner控件使用解析

图片轮播控件,可以说是每个App基本上都会用到的。它可以用来动态的展示多个图片,之前写过两篇博客:实现ViewPager无限循环的方式一和实现ViewPager无限循环的方式二,在这两篇博客中,分析了两种实现ViewPager无限循环的原理,但是在使用的过程中,代码的解偶性很低,所以就使用自定义View的方式,实现无限循环的图片轮播的封装。

先看看效果:

功能特点

  1. 支持自定义宽高比例
  2. 支持自定义图片切换时间
  3. 支持自定义指示点的颜色
  4. 支持自定义指示点的背景色
  5. 支持自定义指示点的高度
  6. 支持是否显示指示点
  7. 支持每个图片设置不同的点击事件

使用简单

<com.xiaomai.bannerview.BannerView

android:id="@+id/bannerView"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

app:aspectRatio="1.5"

app:defaultSrc="@mipmap/ic_launcher"

app:indicatorBackground="@color/white"

app:indicatorHeight="50dp"

app:indicatorPositionSize="8dp"

app:updateTime="3000" />

实现步骤

  • 声明自定义的属性
  • 创建一个类继承RelativeLayout
  • 解析属性

声明自定义的属性

在values/attrs文件中创建自定义的属性

<resources>

<declare-styleable name="BannerView">

<attr name="aspectRatio" format="float" /> <!-- 宽高比 -->

<attr name="defaultSrc" format="integer|reference" /> <!-- 占位图 -->

<attr name="updateTime" format="integer" /> <!-- 图片切换时间 -->

<attr name="indicatorVisible" format="boolean" /> <!-- 是否显示指示器 -->

<attr name="indicatorHeight" format="dimension" /> <!-- 指示器的高度 -->

<attr name="indicatorBackground" format="color|reference" /> <!-- 指示器的背景颜色 -->

<attr name="indicatorPositionSize" format="dimension" /> <!-- 指示点的大小 -->

</declare-styleable>

</resources>

创建BannerView类

public class BannerView extends RelativeLayout {

public BannerView(Context context) {

this(context, null);

}

public BannerView(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public BannerView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);}

在BannerView中声明变量属性

private Context context;

private Handler handler;

private ImageLoader imageLoader;

private DisplayImageOptions options;

private boolean isHaveHandler = true;// 当用户点击轮播图时,取消handler队列,也就是取消滚动

// 控件Start

private ViewPager viewPager;

private LinearLayout indicator;// 指示器

private onItemClickListener listener;

// 控件End

// 自定义属性Start

private float mAspectRatio; // 宽高比

private int defaultImageResource; // 默认占位图

private int updateTime; // 图片切换的时间间隔,默认3秒

private boolean showIndicator; // 是否显示指示器,默认显示

private int indicatorHeight;// 指示器的高度,默认35dp

private int indicatorPositionSize; // 指示器的大小

private int indicatorBackground; // 指示器的背景颜色

// 自定义属性End

// 数据Start

private int imageCount;

private int lastPosition;

private List<Integer> imageResources;

private List<Image> imageUrls;

// 数据End

解析自定义属性的值

接下来为自定义的属性赋值,在3个参数的构造方法中初始化变量。

public BannerView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

parseCustomAttributes(context, attrs);

this.context = context;

handler = new Handler();

imageLoader = ImageLoader.getInstance();

options = HSApplication.getDisplayOptions().build();

initViews();

}

/**

* 解析自定义属性

*

* @param context

* @param attrs

*/

private void parseCustomAttributes(Context context, AttributeSet attrs) {

TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BannerView);

mAspectRatio = typedArray.getFloat(R.styleable.BannerView_aspectRatio, 0f);

defaultImageResource = typedArray.getResourceId(R.styleable.BannerView_defaultSrc,

R.drawable.about_us);

updateTime = typedArray.getInt(R.styleable.BannerView_updateTime, 3000);

showIndicator = typedArray.getBoolean(R.styleable.BannerView_indicatorVisible, true);

indicatorHeight = (int) (typedArray.getDimension(R.styleable.BannerView_indicatorHeight,

Utils.dip2px(context, 35)));

indicatorBackground = typedArray.getResourceId(R.styleable.BannerView_indicatorBackground,

R.color.white_alpha00);

indicatorPositionSize = (int) typedArray.getDimension(

R.styleable.BannerView_indicatorPositionSize, Utils.dip2px(context, 5));

typedArray.recycle();

}

private void initViews() {

viewPager = new ViewPager(context);

viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {

@Override

public void onPageScrolled(int position, float positionOffset,

int positionOffsetPixels) {

}

@Override

public void onPageSelected(int position) {

if (showIndicator) {

for (int i = 0; i < indicator.getChildCount(); i++) {

indicator.getChildAt(i).setSelected(false);

}

indicator.getChildAt(position % imageCount).setSelected(true);

}

lastPosition = position;

}

@Override

public void onPageScrollStateChanged(int state) {

switch (state) {

case ViewPager.SCROLL_STATE_IDLE:// 空闲状态

if (!isHaveHandler) {

isHaveHandler = true;

handler.postDelayed(updateRunnable, updateTime);

}

break;

case ViewPager.SCROLL_STATE_DRAGGING:// 用户滑动状态

handler.removeCallbacks(updateRunnable);

isHaveHandler = false;

break;

}

}

});

addView(viewPager, new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,

ViewGroup.LayoutParams.WRAP_CONTENT));

if (showIndicator) {

indicator = new LinearLayout(context);

indicator.setOrientation(LinearLayout.HORIZONTAL);

indicator.setGravity(Gravity.CENTER);

indicator.setBackgroundResource(indicatorBackground);

RelativeLayout.LayoutParams layoutParams = new LayoutParams(

ViewGroup.LayoutParams.MATCH_PARENT, indicatorHeight);

layoutParams.addRule(ALIGN_PARENT_BOTTOM);

addView(indicator, layoutParams);

}

}

控件和自定义的属性都经过赋值和初始化了,接下来,该为设置图片资源了。

public void setImageResources(List<Integer> imageResources) {

if (imageResources == null || imageResources.size() == 0) {

throw new RuntimeException("图片资源为空");

}

this.imageResources = imageResources;

imageCount = imageResources.size();

}

public void setImageUrls(List<Image> imageUrls) {

if (imageUrls == null || imageUrls.size() == 0) {

throw new RuntimeException("图片地址资源为空");

}

this.imageUrls = imageUrls;

imageCount = imageUrls.size();

loadImages();

}

private void loadImages() {

if (showIndicator) {

addIndicationPoint();

}

viewPager.setAdapter(new MyViewPageAdapter());

viewPager.setCurrentItem(200 - (200 % imageCount));

handler.removeCallbacks(updateRunnable);

handler.postDelayed(updateRunnable, updateTime);

}

/**

* 添加指示点到指示器中

*/

private void addIndicationPoint() {

// 防止刷新重复添加

if (indicator.getChildCount() > 0) {

indicator.removeAllViews();

}

View pointView;

int margin = Utils.dip2px(context, 5f);

LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(

indicatorPositionSize, indicatorPositionSize);

layoutParams.setMargins(margin, margin, margin, margin);

for (int i = 0; i < imageCount; i++) {

pointView = new View(context);

pointView.setBackgroundResource(R.drawable.indicator_selector);

if (i == lastPosition) {

pointView.setSelected(true);

} else {

pointView.setSelected(false);

}

indicator.addView(pointView, layoutParams);

}

}

private class MyViewPageAdapter extends PagerAdapter {

@Override

public int getCount() {

return Integer.MAX_VALUE;

}

@Override

public boolean isViewFromObject(View view, Object object) {

return view == object;

}

@Override

public Object instantiateItem(ViewGroup container, final int position) {

final ImageView imageView = new ImageView(container.getContext());

imageView.setImageResource(defaultImageResource);

imageView.setScaleType(ImageView.ScaleType.FIT_XY);

final Image image = imageUrls.get(position % imageCount);

imageLoader.displayImage(image.getImageUrl(), imageView, options);

imageView.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

if (listener != null) {

listener.onClick(v, position % imageCount, image.getAction(),

image.getUrl());

}

}

});

container.addView(imageView);

return imageView;

}

@Override

public void destroyItem(ViewGroup container, int position, Object object) {

container.removeView((View) object);

}

}

private Runnable updateRunnable = new Runnable() {

@Override

public void run() {

viewPager.setCurrentItem(lastPosition + 1);

handler.postDelayed(updateRunnable, updateTime);

}

/**

* 点击监听回调事件

*/

public interface onItemClickListener {

void onClick(View view, int position, String action, String url);

}

public void setOnItemClickListener(onItemClickListener listener) {

this.listener = listener;

}

时间太仓促,解释的不是太详细,可以移步我的GitHub查看完整代码。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

以上是 Android自定义图片轮播Banner控件使用解析 的全部内容, 来源链接: utcz.com/p/240560.html

回到顶部