使用自定义Banner
思路
1.添加自定义ViewPager
2.添加title背景
3.添加指示器
4.添加title
5.使用Handler实现自动滑动
自定义Banner
public class Banner extends ConstraintLayout implements LifecycleObserver {
private int mId;
private ArrayList<? extends IBannerData> mBannerData;
private ViewPager2 viewPager2;
private TextView tilte;
LifecycleOwner mLifecycleOwner;
private CirlcleIndicator mCirlcleIndicator;
/**
* 构造方法
*/
public Banner(Context context) {
super(context);
}
public Banner(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public Banner(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/*
* 进行测量
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private void initView() {
// 得到设置布局对象
ConstraintSet constraintSet = new ConstraintSet();
// 克隆布局所有属性
constraintSet.clone(this);
/*step1 创建ViewPager2得到ID和添加View*/
viewPager2 = new ViewPager2(getContext());
viewPager2.setId(mId++);
viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
tilte.setText(mBannerData.get(position % mBannerData.size()).getTitle());
mCirlcleIndicator.setCurrentCount(position % mBannerData.size());
}
});
addView(viewPager2);
// 连线
constraintSet.connect(viewPager2.getId(), ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END);
constraintSet.connect(viewPager2.getId(), ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP);
constraintSet.connect(viewPager2.getId(), ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM);
constraintSet.connect(viewPager2.getId(), ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START);
// 设置大小
constraintSet.constrainWidth(viewPager2.getId(), ConstraintSet.MATCH_CONSTRAINT);
constraintSet.constrainHeight(viewPager2.getId(), ConstraintSet.MATCH_CONSTRAINT);
/*step2 给字体设置背景*/
ImageView mask = new ImageView(getContext());
mask.setBackgroundColor(Color.parseColor("#40000000"));
mask.setId(mId++);
addView(mask);
// 连线
constraintSet.connect(mask.getId(), ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START);
constraintSet.connect(mask.getId(), ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END);
constraintSet.connect(mask.getId(), ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM);
// 设置大小
constraintSet.constrainWidth(mask.getId(), ConstraintSet.MATCH_CONSTRAINT);
constraintSet.constrainHeight(mask.getId(), dipTopx(30));
/* step3 设置指示器*/
mCirlcleIndicator = new CirlcleIndicator(getContext());
mCirlcleIndicator.setSelectorColor(Color.WHITE);
mCirlcleIndicator.setUnSelectorColor(Color.GREEN);
mCirlcleIndicator.setRadio(8);
mCirlcleIndicator.setMargin(dipTopx(5));
mCirlcleIndicator.setId(mId++);
// 添加View
addView((View) mCirlcleIndicator);
// 连线
constraintSet.connect(mCirlcleIndicator.getId(), ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END);
constraintSet.connect(mCirlcleIndicator.getId(), ConstraintSet.TOP, mask.getId(), ConstraintSet.TOP);
constraintSet.connect(mCirlcleIndicator.getId(), ConstraintSet.BOTTOM, mask.getId(), ConstraintSet.BOTTOM);
// 设置大小
constraintSet.constrainWidth(mCirlcleIndicator.getId(), ConstraintSet.WRAP_CONTENT);
constraintSet.constrainHeight(mCirlcleIndicator.getId(), ConstraintSet.WRAP_CONTENT);
/* step4 设置标题*/
tilte = new TextView(getContext());
tilte.setId(mId++);
tilte.setTextColor(Color.WHITE);
tilte.setSingleLine(true);
boolean mTitleMarquee=true;
if(mTitleMarquee){
tilte.setEllipsize(TextUtils.TruncateAt.MARQUEE);
tilte.setSelected(true);
tilte.setMarqueeRepeatLimit(-1);
}else{
tilte.setEllipsize(TextUtils.TruncateAt.END);
}
// 添加文字
addView(tilte);
// 连线
constraintSet.connect(tilte.getId(), ConstraintSet.START,ConstraintSet.PARENT_ID, ConstraintSet.START);
constraintSet.connect(tilte.getId(), ConstraintSet.END, mCirlcleIndicator.getId(), ConstraintSet.END);
constraintSet.connect(tilte.getId(), ConstraintSet.BOTTOM, mask.getId(), ConstraintSet.BOTTOM);
constraintSet.connect(tilte.getId(), ConstraintSet.TOP, mask.getId(), ConstraintSet.TOP);
// 设置大小
constraintSet.constrainWidth(tilte.getId(), ConstraintSet.MATCH_CONSTRAINT);
constraintSet.constrainHeight(tilte.getId(), ConstraintSet.WRAP_CONTENT);
// 应用该布局
constraintSet.applyTo(this);
}
// 给banner控件设置数据
public void setBannerData(BannerAdapter adapter) {
// 得到banner数据
mBannerData = adapter.getBannerData();
// 设置数据
viewPager2.setAdapter(adapter);
viewPager2.setUserInputEnabled(true);
// 得到当前banner的位置
int position = Integer.MAX_VALUE / 2 - Integer.MAX_VALUE / 2 % mBannerData.size();
viewPager2.setCurrentItem(position, false);
// 设置指示器
mCirlcleIndicator.setCount(mBannerData.size());
mCirlcleIndicator.setCurrentCount(position % mBannerData.size());
}
// dip转px
public int dipTopx(float dpValue) {
final float scale = getContext().getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* 设置循环轮播
*/
private Runnable mLoopTask = new Runnable() {
@Override
public void run() {
// 获取当前下标
int cIndex = viewPager2.getCurrentItem();
// 下标加一
viewPager2.setCurrentItem(++cIndex, true);
viewPager2.postDelayed(this, 3000);
}
};
public void startLoop() {
// 循环轮播
if ((mBannerData != null && mBannerData.size() > 1) && (getVisibility() == VISIBLE)) {
viewPager2.postDelayed(mLoopTask, 3000);
}
}
// 停止轮播
public void stopLoop() {
// 移除该任务
viewPager2.removeCallbacks(mLoopTask);
}
// 查看当前页面是否可见
@Override
protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
if (visibility == VISIBLE) {
startLoop();
} else {
stopLoop();
}
}
/**
*
* @param lifecycleOwner
* 获得lifecycle监听生命周期
*/
public void setLifecycleOwner(LifecycleOwner lifecycleOwner) {
this.mLifecycleOwner = lifecycleOwner;
mLifecycleOwner.getLifecycle().addObserver(this);
}
// 通过Lifecycle监听生命周期
private boolean isOnResume = false;
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void onResume() {
isOnResume = true;
startLoop();
}
// 通过Lifecycle监听生命周期
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void onPause() {
isOnResume = false;
Log.d("TAG", "onPause: ");
stopLoop();
}
/**
* 解决滑动冲突
* @param ev
* @return
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
stopLoop();
break;
}
case MotionEvent.ACTION_MOVE: {
// 阻止滑动事件交给ViewGroup让子view自己处理
getParent().requestDisallowInterceptTouchEvent(true);
}
case MotionEvent.ACTION_UP: {
startLoop();
}
}
return super.dispatchTouchEvent(ev);
}
/**
* 解决滑动时间
* @return
*/
public int getScrollTime() {
return 0;
}
public ViewPager2 getViewPager2() {
return viewPager2;
}
}
创建指示器
思路
1.创建接口设置需要的数据
2.设置画笔
3.得到数量测量需要的绘制的大小
4.调用onMeasure()方法重新测量
5.进行绘制圆
创建指示器接口
interface Indicator {
// 设置半径
void setRadio(int radio);
// 设置条目数量
void setCount(int current);
// 设置当前下标
void setCurrentCount(int current);
// 设置为选中的颜色
void setUnSelectorColor(int unSelectColor);
// 设置选中的颜色
void setSelectorColor(int selectColor);
// 设置边距
void setMargin(int margin);
// 设置ID
void setId(int id);
int getId();
}
创建指示器
public class CirlcleIndicator extends View implements Indicator {
private static final int MAX_COUNT = 10;
private int mRadio;//半径
private int mCurrent;//当前条目
private int mRealCount;//真正的数量
private int mUnSelectColor;//为选中yanse
private int mSelectColor;//选中颜色
private int mMargin;//边距
private int mCount = 10;
private Paint mPaint;
private int mHeight;
private int mWidth;
public CirlcleIndicator(Context context) {
super(context);
initPaint();
}
public CirlcleIndicator(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initPaint();
}
public CirlcleIndicator(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPaint();
}
// 设置画笔
private void initPaint() {
mPaint = new Paint();
mPaint.setAntiAlias(true);//消除边距
mPaint.setStyle(Paint.Style.FILL);//绘画的风格
mPaint.setColor(Color.WHITE);
}
// 计算绘制的长度
private void calculation() {
// 得到指示器最大长度
mCount = Math.min(mRealCount, MAX_COUNT);
mHeight = mRadio * 2;
mWidth = (mCount * mRadio * 2) + (mCount - 1) * mMargin;
// 刷新页面重新走onDrawer(),onLayout(),onMeasuer();
invalidate();
}
/**
*
* @param widthMeasureSpec
* @param heightMeasureSpec
* 测量
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 重新计算绘制的高度和宽度
setMeasuredDimension(MeasureSpec.makeMeasureSpec(mWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(mHeight, MeasureSpec.EXACTLY));
}
//绘制
@Override
protected void onDraw(Canvas canvas) {
// super.onDraw(canvas);
for (int i = 0; i < mCount; i++) {
// 如果等于当前下标
if (i == mCurrent % mCount) {
mPaint.setColor(mSelectColor);
} else {
// 如果不等于
mPaint.setColor(mUnSelectColor);
}
// 开始绘制
canvas.drawCircle((i * (mRadio * 2) + (i * mMargin) + mRadio), mRadio, mRadio, mPaint);
}
}
@Override
public void setRadio(int radio) {
mRadio = radio;
}
/**
* 计数
* @param count
*/
@Override
public void setCount(int count) {
// 如果真是数量发生改变
if (mRealCount != count) {
// 设置真是数量
mRealCount = count;
// 计算
calculation();
}
}
@Override
public void setCurrentCount(int current) {
// 如果传入当前下标与当前下标不一样刷新
if (mCurrent != current) {
mCurrent = current;
invalidate();
}
}
// 设置未选中的颜色
@Override
public void setUnSelectorColor(int unSelectColor) {
mUnSelectColor = unSelectColor;
}
// 设置未选中的颜色
@Override
public void setSelectorColor(int selectColor) {
mSelectColor = selectColor;
}
// 设置margin
@Override
public void setMargin(int margin) {
mMargin = margin;
}
}
网友评论