本文实例为大家分享了Android自定义轮播图效果的具体代码,供大家参考,具体内容如下
概述
1、写一个布局,其中有ViewPager,TextView,LinearLayout.
- ViewPager:用来承载图片
- TextView:用来展示文字描述
- LinearLayout:用来展示指示器
2、自定义ConstraintLayout, 在该控件中处理页面切换逻辑等.
分析
1、获取自定义属性以及设置一些属性
public BannerY(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
initXmlParams(context, attrs, defStyleAttr);
fixParams();
initListener();
initLists();
initImageLoader();
}
private void initImageLoader() {
ImageLoader.getInstance().init(ImageLoaderConfiguration.createDefault(mContext));
}
private void initView(Context context) {
mContext = context;
LayoutInflater.from(context).inflate(R.layout.layout_banner, this);
mVp = (ViewPager) findViewById(R.id.vp);
mTvDesc = (TextView) findViewById(R.id.tv_desc);
mLLPoint = (LinearLayout) findViewById(R.id.ll_point);
}
private void initXmlParams(Context context, AttributeSet attrs, int defStyleAttr) {
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.BannerY, defStyleAttr, 0);
mPointSize = typedArray.getDimensionPixelSize(R.styleable.BannerY_point_size, 8);
mPointBG = typedArray.getResourceId(R.styleable.BannerY_point_bg, R.drawable.point_selector);
mInterval = typedArray.getInteger(R.styleable.BannerY_banner_interval, 2000);
mTvBottomMargin = typedArray.getDimensionPixelSize(R.styleable.BannerY_desc_bottom_margin, 8);
mPointBottomMargin = typedArray.getDimensionPixelSize(R.styleable.BannerY_point_bottom_margin, 8);
mDescColor = typedArray.getColor(R.styleable.BannerY_desc_color, Color.BLACK);
mDescSize = typedArray.getDimensionPixelSize(R.styleable.BannerY_desc_size, 14);
mScaleType = typedArray.getInt(R.styleable.BannerY_banner_scaletype, -1);
typedArray.recycle();
}
private void fixParams() {
//描述控件
LayoutParams mTvDescLayoutParams = (LayoutParams) mTvDesc.getLayoutParams();
mTvDescLayoutParams.bottomMargin = (int) mTvBottomMargin;
mTvDesc.setLayoutParams(mTvDescLayoutParams);
mTvDesc.setTextColor(mDescColor);
mTvDesc.getPaint().setTextSize(mDescSize);
//指示器
LayoutParams mLLPointLayoutParams = (LayoutParams) mLLPoint.getLayoutParams();
mLLPointLayoutParams.bottomMargin = (int) mPointBottomMargin;
mLLPoint.setLayoutParams(mLLPointLayoutParams);
}
@SuppressLint("HandlerLeak")
private void initLists() {
mImageViewList = new ArrayList<>();
mDescList = new ArrayList<>();
mHandler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
// 获取ViewPager当前展示图片的索引值
int currentItem = mVp.getCurrentItem();
// 切换到下一个图片
mVp.setCurrentItem(currentItem + 1);
// 间隔一定时间发送一个消息,间隔时长由自定义属性值控制.
mHandler.sendEmptyMessageDelayed(1, mInterval);
}
};
}
private void initListener() {
mVp.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
// ViewPager总共设置有Integer.MAX_VALUE个视图
// position取模,转换为mImageViewList对应的索引.
int realPosition = position % mImageViewList.size();
if (mDescList.size() == mImageViewList.size()) {
// 文字描述集合与图片集合长度相等,那么就为文字描述TextView展示对应的文字内容.
String desc = mDescList.get(realPosition);
mTvDesc.setText(desc);
} else {
if (BuildConfig.DEBUG) {
Log.d(TAG, "文字集合和图片集合长度不相等");
}
}
// 上一个页面对应的指示器设置为没有选中
mLLPoint.getChildAt(prePosition).setEnabled(false);
// 从装有指示器的LinearLayout中获得当前视图对应的指示器,然后设置指示器当前是选中,从而改变指示器颜色.
mLLPoint.getChildAt(realPosition).setEnabled(true);
prePosition = realPosition;
}
@Override
public void onPageScrollStateChanged(int state) {
if (state == ViewPager.SCROLL_STATE_DRAGGING) {//正在滑动
// 手动触碰ViewPager,使之正在处于滑动状态,Handler就停止发送消息.
isDragging = true;
mHandler.removeCallbacksAndMessages(null);
}
if (state == ViewPager.SCROLL_STATE_IDLE && isDragging) {//空闲状态
// ViewPager手动滑动停止之后,重新开启Handler发送消息.
mHandler.removeCallbacksAndMessages(null);
mHandler.sendEmptyMessageDelayed(1, mInterval);
}
}
});
}
2、设置图片源集合
public <T> void setImagesRes(ArrayList<T> imagesRes) {
if (judgeLenght(imagesRes)) {
mImageViewList.clear();
// 初始化图片列表
initImageList(imagesRes);
// 创建Adapter
mBannerAdapter = new BannerAdapter(mImageViewList);
mVp.setAdapter(mBannerAdapter);
// 设置ViewPager当前视图为中间位置, 因为ViewPager视图个数为Integer.MAX_VALUE(在ViewPagerAdapter中设置的).
int position = Integer.MAX_VALUE / 2 - Integer.MAX_VALUE / 2 % mImageViewList.size();
// 设置当前ViewPager展示哪个视图
mVp.setCurrentItem(position);
// 开启消息循环
mHandler.sendEmptyMessageDelayed(1, mInterval);
if (mDescList.size() == mImageViewList.size()) {
// 设置文字描述展示
mTvDesc.setText(mDescList.get(prePosition));
}
}
}
private void initImageList(ArrayList imagesRes) {
Class<?> imageResClass = imagesRes.get(0).getClass();
for (int i = 0; i < imagesRes.size(); i++) {
// 创建ImageView
ImageView imageView = createImageView(imagesRes, i, imageResClass);
// 为ImageView设置点击事件
setImageViewListener(imageView);
// 将ImageView添加进集合中
mImageViewList.add(imageView);
//添加指示器
addPoint(i);
}
}
private ImageView createImageView(ArrayList imagesRes, int i, Class<?> imageResClass) {
ImageView imageView = new ImageView(mContext);
ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
imageView.setLayoutParams(layoutParams);
ImageView.ScaleType scaleType = sScaleTypeArray[mScaleType];
imageView.setScaleType(scaleType);
if (imageResClass.equals(String.class)) {
// 假如图片数据源集合是url,网址图片
String url = (String) imagesRes.get(i);
// 使用ImageLoader将图片展示到ImageView中
ImageLoader.getInstance().displayImage(url, imageView);
} else if (imageResClass.equals(Integer.class)) {
// 假如图片数据源集合是图片资源ID
Integer resId = (Integer) imagesRes.get(i);
imageView.setImageResource(resId);
}
return imageView;
}
@SuppressLint("ClickableViewAccessibility")
private void setImageViewListener(ImageView imageView) {
imageView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 当手指在ImageView下按下,那么停止handler发送切换图片的消息
mHandler.removeCallbacksAndMessages(null);
break;
case MotionEvent.ACTION_UP:
// 当手指抬起,正常发送切换图片消息.
mHandler.removeCallbacksAndMessages(null);
mHandler.sendEmptyMessageDelayed(1, mInterval);
break;
}
return false;
}
});
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mIClickBanner != null) {
// 当点击ImageView时,通过getTage()获取图片当前对应的视图索引值.
// 该值是在ViewPagerAdapter中的instantiateItem()中设置的.
int positon = (int) v.getTag();
int i = positon % mImageViewList.size();
mIClickBanner.click(i);
} else {
if (BuildConfig.DEBUG) {
Log.e(TAG, "图片回调方法为不存在");
}
}
}
});
}
3、BannerY的Adapter
public class BannerAdapter<T> extends PagerAdapter {
private final static String TAG = BannerAdapter.class.getName();
ArrayList<ImageView> mImageViewList;
public BannerAdapter(ArrayList<ImageView> mImageViewList) {
this.mImageViewList = mImageViewList;
}
@Override
public int getCount() {
// 设置ViewPager的视图个数,Integer.MAX_VALUE是一个非常大的数字, 不管轮询多久都很难到尽头.
return Integer.MAX_VALUE;
}
@SuppressLint("ClickableViewAccessibility")
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, final int position) {
// position这个数字很大, 取模之后就能够对应mImageViewList集合中的索引值了.
final int realPosition = position % mImageViewList.size();
ImageView imageView = mImageViewList.get(realPosition);
// 将索引值与ImageView绑定,当被点击的时候可以取出该索引值.
imageView.setTag(position);
ViewParent viewParent = imageView.getParent();
if (viewParent != null) {
// 这里是防止ViewPager重复添加图片.
((ViewGroup) viewParent).removeView(imageView);
}
// 将图片添加进ViewPager中
container.addView(imageView);
return imageView;
}
@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
return view == object;
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。