Android 您所在的位置:网站首页 安卓播放控件 Android

Android

2023-09-30 05:01| 来源: 网络整理| 查看: 265

基于https://github.com/youth5201314/banner 扩展,图片+视频无限轮播banner

Demo地址

PicVideoBannerDemo: 基于https://github.com/youth5201314/banner扩展,图片+视频无限轮播banner的demo

demo请自行给予应用权限

说明

使用大佬的banner控件是很方便的,但是对视频+图片无限轮播的支持较弱,所以决定重写几个类实现功能。

不重写无法实现的原因如下:

无限轮播模式下,item大于1时, adapter会自动增加两个item,一个在最前,一个在最后,这样子做是为了滑动的视觉效果。

但是这样子也引发了另外一个问题

在onPageSelected回调中,播放第一个或最后一个视频时无法正确的拿到视频控件,导致通过拿到的position播放的那一个item会有声音但无法见到画面

处理播放时是通过adapter保存的ViewHolder对象来进行播放操作,所以使用HashMap保存对应ViewHolder

这是因为实际使用position获取的ViewHolder并不是当前展示的ViewHolder,实际位置应该是 +1 或者 -1 

重写几个关键类返回真实position,可以拿到当前正确的ViewHolder,即可解决该问题。

demo效果

 

依赖 //banner implementation "com.youth.banner:banner:2.1.0" //视频播放 implementation 'com.shuyu:GSYVideoPlayer:7.1.3' 主要代码 使用方式 public class MainActivity extends AppCompatActivity { @BindView(R.id.banner) ChangeBanner banner; private List dataList; private MediaVideoBannerAdapter mAdapter; private BannerVideoManager mBannerVideoManager; private Unbinder unbinder; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); unbinder = ButterKnife.bind(this); initDataList(); mAdapter = new MediaVideoBannerAdapter(this, dataList); banner.isAutoLoop(false); banner.setAdapter(mAdapter). setIndicator(new CircleIndicator(this)) .setIndicatorGravity(IndicatorConfig.Direction.CENTER); mBannerVideoManager = new BannerVideoManager(this, banner, mAdapter, dataList); mBannerVideoManager.setPageChangeMillis(5000); mBannerVideoManager.setVideoPlayLoadWait(500); } /** * 数据源请自行替换 * MediaVideoBannerAdapter也需要修改数据类型 */ private void initDataList(){ //... } @Override protected void onResume() { super.onResume(); mBannerVideoManager.onResume(); } @Override protected void onPause() { super.onPause(); mBannerVideoManager.onPause(); } @Override public void onDetachedFromWindow() { super.onDetachedFromWindow(); mBannerVideoManager.onDetachedFromWindow(); } @Override protected void onDestroy() { super.onDestroy(); unbinder.unbind(); } } BaseBannerAdapter

重写一个BannerAdapter

在onBindView(holder, mDatas.get(real), real, getRealCount(), position);中将真实存在的position传出

banner源码中不重写无法在适配器中获取到当前真实的position

import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import com.saqino.picvideobanner.banner.holder.IBaseViewHolder; import com.youth.banner.listener.OnBannerListener; import com.youth.banner.util.BannerUtils; import java.util.ArrayList; import java.util.List; public abstract class BaseBannerAdapter extends RecyclerView.Adapter implements IBaseViewHolder { protected List mDatas = new ArrayList(); private OnBannerListener mOnBannerListener; private VH mViewHolder; private int increaseCount = 2; public BaseBannerAdapter(List datas) { setDatas(datas); } public void setDatas(List datas) { if (datas == null) { datas = new ArrayList(); } mDatas = datas; } public T getData(int position) { return mDatas.get(position); } @Override public final void onBindViewHolder(@NonNull VH holder, int position) { mViewHolder = holder; int real = getRealPosition(position); onBindView(holder, mDatas.get(real), real, getRealCount(), position); if (mOnBannerListener != null) holder.itemView.setOnClickListener(view -> mOnBannerListener.OnBannerClick(mDatas.get(real), real)); } @NonNull @Override public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { return onCreateHolder(parent, viewType); } @Override public int getItemCount() { return getRealCount() > 1 ? getRealCount() + increaseCount : getRealCount(); } public int getRealCount() { return mDatas == null ? 0 : mDatas.size(); } public int getRealPosition(int position) { return BannerUtils.getRealPosition(increaseCount == 2, position, getRealCount()); } public void setOnBannerListener(OnBannerListener listener) { this.mOnBannerListener = listener; } public VH getViewHolder() { return mViewHolder; } public void setIncreaseCount(int increaseCount) { this.increaseCount = increaseCount; } } MediaVideoBannerAdapter

继承BaseBannerAdapter并实现图片视频viewholder绑定逻辑

使用HashMap保存每个position对应的ViewHolder,方便取用播放视频

ResourceBean是demo使用的数据类型,根据实际情况修改

import android.content.Context; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; import com.saqino.picvideobanner.R; import com.saqino.picvideobanner.banner.holder.ImageHolder; import com.saqino.picvideobanner.banner.holder.VideoHolder; import com.saqino.picvideobanner.bean.ResourceBean; import com.youth.banner.util.BannerUtils; import java.util.HashMap; import java.util.List; import java.util.Map; public class MediaVideoBannerAdapter extends BaseBannerAdapter { private Context context; private Map videoHolderMap; public interface OnBannerVideoPlayListener{ void onVideoPlayStart(); void onVideoPlayComplete(); } public MediaVideoBannerAdapter(Context context, List mDatas) { super(mDatas); this.context = context; videoHolderMap = new HashMap(); } @Override public RecyclerView.ViewHolder onCreateHolder(ViewGroup parent, int viewType) { switch (viewType) { case 1: return new ImageHolder(BannerUtils.getView(parent, R.layout.banner_image)); case 2: return new VideoHolder(BannerUtils.getView(parent, R.layout.banner_video)); /*case 3: return new TitleHolder(BannerUtils.getView(parent, R.layout.banner_title));*/ } return new ImageHolder(BannerUtils.getView(parent, R.layout.banner_image)); } @Override public int getItemViewType(int position) { return getData(getRealPosition(position)).getType(); } @Override public void onBindView(RecyclerView.ViewHolder holder, ResourceBean data, int position, int size, int adapterPosition) { int viewType = holder.getItemViewType(); switch (viewType) { case 1: ImageHolder imageHolder = (ImageHolder) holder; Glide.with(imageHolder.itemView) .load(data.getUrl()) .into(imageHolder.imageView); break; case 2: VideoHolder videoHolder = (VideoHolder) holder; videoHolder.player.setUp(data.getUrl(), true, null); videoHolder.player.getBackButton().setVisibility(View.GONE); //增加封面 ImageView imageView = new ImageView(context); imageView.setScaleType(ImageView.ScaleType.CENTER_CROP); //imageView.setImageResource(R.drawable.image4); videoHolder.player.setThumbImageView(imageView); videoHolderMap.put(adapterPosition, videoHolder); break; } } public VideoHolder getVideoHolder(Integer position){ return videoHolderMap.get(position); } public void stopVideo(){ for (Integer key : videoHolderMap.keySet()){ try { if (getVideoHolder(key) != null) { getVideoHolder(key).player.release(); getVideoHolder(key).player.onVideoReset(); } }catch (Throwable e){ Log.e("VideoBannerError", "停止视频播放出错 "+e.getLocalizedMessage()); } } } } ChangeBanner

修改后的Banner控件,主要是修改BannerAdapter的类型

import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.RectF; import android.os.Build; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.widget.FrameLayout; import androidx.annotation.ColorInt; import androidx.annotation.ColorRes; import androidx.annotation.IntDef; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.core.content.ContextCompat; import androidx.lifecycle.LifecycleOwner; import androidx.recyclerview.widget.RecyclerView; import androidx.viewpager.widget.ViewPager; import androidx.viewpager2.widget.CompositePageTransformer; import androidx.viewpager2.widget.MarginPageTransformer; import androidx.viewpager2.widget.ViewPager2; import com.saqino.picvideobanner.R; import com.saqino.picvideobanner.banner.adapter.BaseBannerAdapter; import com.saqino.picvideobanner.banner.manager.ScrollSpeedManger; import com.youth.banner.config.BannerConfig; import com.youth.banner.config.IndicatorConfig; import com.youth.banner.indicator.Indicator; import com.youth.banner.listener.OnBannerListener; import com.youth.banner.listener.OnPageChangeListener; import com.youth.banner.transformer.MZScaleInTransformer; import com.youth.banner.transformer.ScaleInTransformer; import com.youth.banner.util.BannerLifecycleObserver; import com.youth.banner.util.BannerLifecycleObserverAdapter; import com.youth.banner.util.BannerUtils; import com.youth.banner.util.LogUtils; import java.lang.annotation.Retention; import java.lang.ref.WeakReference; import java.util.List; import static java.lang.annotation.RetentionPolicy.SOURCE; public class ChangeBanner extends FrameLayout implements BannerLifecycleObserver { public static final int INVALID_VALUE = -1; private ViewPager2 mViewPager2; private AutoLoopTask mLoopTask; private OnPageChangeListener mOnPageChangeListener; private BA mAdapter; private Indicator mIndicator; private CompositePageTransformer mCompositePageTransformer; private BannerOnPageChangeCallback mPageChangeCallback; // 是否允许无限轮播(即首尾直接切换) private boolean mIsInfiniteLoop = BannerConfig.IS_INFINITE_LOOP; // 是否自动轮播 private boolean mIsAutoLoop = BannerConfig.IS_AUTO_LOOP; // 轮播切换间隔时间 private long mLoopTime = BannerConfig.LOOP_TIME; // 轮播切换时间 private int mScrollTime = BannerConfig.SCROLL_TIME; // 轮播开始位置 private int mStartPosition = 1; // banner圆角半径 private float mBannerRadius = 0; // 指示器相关配置 private int normalWidth = BannerConfig.INDICATOR_NORMAL_WIDTH; private int selectedWidth = BannerConfig.INDICATOR_SELECTED_WIDTH; private int normalColor = BannerConfig.INDICATOR_NORMAL_COLOR; private int selectedColor = BannerConfig.INDICATOR_SELECTED_COLOR; private int indicatorGravity = IndicatorConfig.Direction.CENTER; private int indicatorSpace; private int indicatorMargin; private int indicatorMarginLeft; private int indicatorMarginTop; private int indicatorMarginRight; private int indicatorMarginBottom; private int indicatorHeight = BannerConfig.INDICATOR_HEIGHT; private int indicatorRadius = BannerConfig.INDICATOR_RADIUS; public static final int HORIZONTAL = 0; public static final int VERTICAL = 1; // 滑动距离范围 private int mTouchSlop; // 记录触摸的位置(主要用于解决事件冲突问题) private float mStartX, mStartY; // 记录viewpager2是否被拖动 private boolean mIsViewPager2Drag; // 是否要拦截事件 private boolean isIntercept = true; //绘制圆角视图 private Paint mRoundPaint; private Paint mImagePaint; @Retention(SOURCE) @IntDef( {HORIZONTAL, VERTICAL}) public @interface Orientation { } public ChangeBanner(Context context) { this(context, null); } public ChangeBanner(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ChangeBanner(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); initTypedArray(context, attrs); } private void init(Context context) { mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop() / 2; mCompositePageTransformer = new CompositePageTransformer(); mPageChangeCallback = new BannerOnPageChangeCallback(); mLoopTask = new AutoLoopTask(this); mViewPager2 = new ViewPager2(context); mViewPager2.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); mViewPager2.setOffscreenPageLimit(1); mViewPager2.registerOnPageChangeCallback(mPageChangeCallback); mViewPager2.setPageTransformer(mCompositePageTransformer); ScrollSpeedManger.reflectLayoutManager(this); addView(mViewPager2); mRoundPaint = new Paint(); mRoundPaint.setColor(Color.WHITE); mRoundPaint.setAntiAlias(true); mRoundPaint.setStyle(Paint.Style.FILL); mRoundPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT)); mImagePaint = new Paint(); mImagePaint.setXfermode(null); } private void initTypedArray(Context context, AttributeSet attrs) { if (attrs == null) { return; } TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Banner); mBannerRadius = a.getDimensionPixelSize(R.styleable.Banner_banner_radius, 0); mLoopTime = a.getInt(R.styleable.Banner_banner_loop_time, BannerConfig.LOOP_TIME); mIsAutoLoop = a.getBoolean(R.styleable.Banner_banner_auto_loop, BannerConfig.IS_AUTO_LOOP); mIsInfiniteLoop = a.getBoolean(R.styleable.Banner_banner_infinite_loop, BannerConfig.IS_INFINITE_LOOP); normalWidth = a.getDimensionPixelSize(R.styleable.Banner_banner_indicator_normal_width, BannerConfig.INDICATOR_NORMAL_WIDTH); selectedWidth = a.getDimensionPixelSize(R.styleable.Banner_banner_indicator_selected_width, BannerConfig.INDICATOR_SELECTED_WIDTH); normalColor = a.getColor(R.styleable.Banner_banner_indicator_normal_color, BannerConfig.INDICATOR_NORMAL_COLOR); selectedColor = a.getColor(R.styleable.Banner_banner_indicator_selected_color, BannerConfig.INDICATOR_SELECTED_COLOR); indicatorGravity = a.getInt(R.styleable.Banner_banner_indicator_gravity, IndicatorConfig.Direction.CENTER); indicatorSpace = a.getDimensionPixelSize(R.styleable.Banner_banner_indicator_space, 0); indicatorMargin = a.getDimensionPixelSize(R.styleable.Banner_banner_indicator_margin, 0); indicatorMarginLeft = a.getDimensionPixelSize(R.styleable.Banner_banner_indicator_marginLeft, 0); indicatorMarginTop = a.getDimensionPixelSize(R.styleable.Banner_banner_indicator_marginTop, 0); indicatorMarginRight = a.getDimensionPixelSize(R.styleable.Banner_banner_indicator_marginRight, 0); indicatorMarginBottom = a.getDimensionPixelSize(R.styleable.Banner_banner_indicator_marginBottom, 0); indicatorHeight = a.getDimensionPixelSize(R.styleable.Banner_banner_indicator_height, BannerConfig.INDICATOR_HEIGHT); indicatorRadius = a.getDimensionPixelSize(R.styleable.Banner_banner_indicator_radius, BannerConfig.INDICATOR_RADIUS); int orientation = a.getInt(R.styleable.Banner_banner_orientation, HORIZONTAL); setOrientation(orientation); setInfiniteLoop(); a.recycle(); } private void initIndicatorAttr() { if (indicatorMargin != 0) { setIndicatorMargins(new IndicatorConfig.Margins(indicatorMargin)); } else if (indicatorMarginLeft != 0 || indicatorMarginTop != 0 || indicatorMarginRight != 0 || indicatorMarginBottom != 0) { setIndicatorMargins(new IndicatorConfig.Margins( indicatorMarginLeft, indicatorMarginTop, indicatorMarginRight, indicatorMarginBottom)); } if (indicatorSpace > 0) { setIndicatorSpace(indicatorSpace); } if (indicatorGravity != IndicatorConfig.Direction.CENTER) { setIndicatorGravity(indicatorGravity); } if (normalWidth > 0) { setIndicatorNormalWidth(normalWidth); } if (selectedWidth > 0) { setIndicatorSelectedWidth(selectedWidth); } if (indicatorHeight > 0) { setIndicatorHeight(indicatorHeight); } if (indicatorRadius > 0) { setIndicatorRadius(indicatorRadius); } setIndicatorNormalColor(normalColor); setIndicatorSelectedColor(selectedColor); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { if (!getViewPager2().isUserInputEnabled()) { return super.dispatchTouchEvent(ev); } int action = ev.getActionMasked(); if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_OUTSIDE) { start(); } else if (action == MotionEvent.ACTION_DOWN) { stop(); } return super.dispatchTouchEvent(ev); } @Override public boolean onInterceptTouchEvent(MotionEvent event) { if (!getViewPager2().isUserInputEnabled() || !isIntercept) { return super.onInterceptTouchEvent(event); } switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mStartX = event.getX(); mStartY = event.getY(); getParent().requestDisallowInterceptTouchEvent(true); break; case MotionEvent.ACTION_MOVE: float endX = event.getX(); float endY = event.getY(); float distanceX = Math.abs(endX - mStartX); float distanceY = Math.abs(endY - mStartY); if (getViewPager2().getOrientation() == HORIZONTAL) { mIsViewPager2Drag = distanceX > mTouchSlop && distanceX > distanceY; } else { mIsViewPager2Drag = distanceY > mTouchSlop && distanceY > distanceX; } getParent().requestDisallowInterceptTouchEvent(mIsViewPager2Drag); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: getParent().requestDisallowInterceptTouchEvent(false); break; } return super.onInterceptTouchEvent(event); } @Override protected void dispatchDraw(Canvas canvas) { if (mBannerRadius > 0) { canvas.saveLayer(new RectF(0, 0, canvas.getWidth(), canvas.getHeight()), mImagePaint, Canvas.ALL_SAVE_FLAG); super.dispatchDraw(canvas); //绘制外圆环边框圆环 drawTopLeft(canvas); drawTopRight(canvas); drawBottomLeft(canvas); drawBottomRight(canvas); canvas.restore(); } else { super.dispatchDraw(canvas); } } private void drawTopLeft(Canvas canvas) { Path path = new Path(); path.moveTo(0, mBannerRadius); path.lineTo(0, 0); path.lineTo(mBannerRadius, 0); path.arcTo(new RectF(0, 0, mBannerRadius * 2, mBannerRadius * 2), -90, -90); path.close(); canvas.drawPath(path, mRoundPaint); } private void drawTopRight(Canvas canvas) { int width = getWidth(); Path path = new Path(); path.moveTo(width - mBannerRadius, 0); path.lineTo(width, 0); path.lineTo(width, mBannerRadius); path.arcTo(new RectF(width - 2 * mBannerRadius, 0, width, mBannerRadius * 2), 0, -90); path.close(); canvas.drawPath(path, mRoundPaint); } private void drawBottomLeft(Canvas canvas) { int height = getHeight(); Path path = new Path(); path.moveTo(0, height - mBannerRadius); path.lineTo(0, height); path.lineTo(mBannerRadius, height); path.arcTo(new RectF(0, height - 2 * mBannerRadius, mBannerRadius * 2, height), 90, 90); path.close(); canvas.drawPath(path, mRoundPaint); } private void drawBottomRight(Canvas canvas) { int height = getHeight(); int width = getWidth(); Path path = new Path(); path.moveTo(width - mBannerRadius, height); path.lineTo(width, height); path.lineTo(width, height - mBannerRadius); path.arcTo(new RectF(width - 2 * mBannerRadius, height - 2 * mBannerRadius, width, height), 0, 90); path.close(); canvas.drawPath(path, mRoundPaint); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); start(); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); stop(); } class BannerOnPageChangeCallback extends ViewPager2.OnPageChangeCallback { private int mTempPosition = INVALID_VALUE; private boolean isScrolled; @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { int realPosition = BannerUtils.getRealPosition(isInfiniteLoop(), position, getRealCount()); if (mOnPageChangeListener != null) { mOnPageChangeListener.onPageScrolled(realPosition, positionOffset, positionOffsetPixels); } if (mIndicator != null) { mIndicator.onPageScrolled(realPosition, positionOffset, positionOffsetPixels); } } @Override public void onPageSelected(int position) { if (isScrolled) { mTempPosition = position; int realPosition = BannerUtils.getRealPosition(isInfiniteLoop(), position, getRealCount()); if (mOnPageChangeListener != null) { mOnPageChangeListener.onPageSelected(realPosition); } if (mIndicator != null) { mIndicator.onPageSelected(realPosition); } } } @Override public void onPageScrollStateChanged(int state) { //手势滑动中,代码执行滑动中 if (state == ViewPager2.SCROLL_STATE_DRAGGING || state == ViewPager2.SCROLL_STATE_SETTLING) { isScrolled = true; } else if (state == ViewPager2.SCROLL_STATE_IDLE) { //滑动闲置或滑动结束 isScrolled = false; if (mTempPosition != INVALID_VALUE && mIsInfiniteLoop) { if (mTempPosition == 0) { setCurrentItem(getRealCount(), false); } else if (mTempPosition == getItemCount() - 1) { setCurrentItem(1, false); } } } if (mOnPageChangeListener != null) { mOnPageChangeListener.onPageScrollStateChanged(state); } if (mIndicator != null) { mIndicator.onPageScrollStateChanged(state); } } } static class AutoLoopTask implements Runnable { private final WeakReference reference; AutoLoopTask(ChangeBanner banner) { this.reference = new WeakReference(banner); } @Override public void run() { ChangeBanner banner = reference.get(); if (banner != null && banner.mIsAutoLoop) { int count = banner.getItemCount(); if (count == 0) { return; } int next = (banner.getCurrentItem() + 1) % count; banner.setCurrentItem(next); banner.postDelayed(banner.mLoopTask, banner.mLoopTime); } } } private RecyclerView.AdapterDataObserver mAdapterDataObserver = new RecyclerView.AdapterDataObserver() { @Override public void onChanged() { if (getItemCount() 0) { addPageTransformer(new MarginPageTransformer((int) BannerUtils.dp2px(pageMargin))); } if (scale < 1 && scale > 0) { addPageTransformer(new ScaleInTransformer(scale)); } setRecyclerViewPadding(leftItemWidth > 0 ? (int) BannerUtils.dp2px(leftItemWidth + pageMargin) : 0, rightItemWidth > 0 ? (int) BannerUtils.dp2px(rightItemWidth + pageMargin) : 0); return this; } /** * 为banner添加魅族效果 * * @param itemWidth item左右展示的宽度,单位dp */ public ChangeBanner setBannerGalleryMZ(int itemWidth) { return setBannerGalleryMZ(itemWidth, .88f); } /** * 为banner添加魅族效果 * * @param itemWidth item左右展示的宽度,单位dp * @param scale 缩放[0-1],1代表不缩放 */ public ChangeBanner setBannerGalleryMZ(int itemWidth, float scale) { if (scale < 1 && scale > 0) { addPageTransformer(new MZScaleInTransformer(scale)); } setRecyclerViewPadding((int) BannerUtils.dp2px(itemWidth)); return this; } /** * ********************************************************************** * ------------------------ 指示器相关设置 --------------------------------* * ********************************************************************** */ /** * 设置轮播指示器(显示在banner上) */ public ChangeBanner setIndicator(Indicator indicator) { return setIndicator(indicator, true); } /** * 设置轮播指示器(如果你的指示器写在布局文件中,attachToBanner传false) * * @param attachToBanner 是否将指示器添加到banner中,false 代表你可以将指示器通过布局放在任何位置 * 注意:设置为false后,内置的 setIndicatorGravity()和setIndicatorMargins() 方法将失效。 * 想改变可以自己调用系统提供的属性在布局文件中进行设置。具体可以参照demo */ public ChangeBanner setIndicator(Indicator indicator, boolean attachToBanner) { removeIndicator(); indicator.getIndicatorConfig().setAttachToBanner(attachToBanner); this.mIndicator = indicator; initIndicator(); return this; } public ChangeBanner setIndicatorSelectedColor(@ColorInt int color) { if (mIndicator != null) { mIndicator.getIndicatorConfig().setSelectedColor(color); } return this; } public ChangeBanner setIndicatorSelectedColorRes(@ColorRes int color) { setIndicatorSelectedColor(ContextCompat.getColor(getContext(), color)); return this; } public ChangeBanner setIndicatorNormalColor(@ColorInt int color) { if (mIndicator != null) { mIndicator.getIndicatorConfig().setNormalColor(color); } return this; } public ChangeBanner setIndicatorNormalColorRes(@ColorRes int color) { setIndicatorNormalColor(ContextCompat.getColor(getContext(), color)); return this; } public ChangeBanner setIndicatorGravity(@IndicatorConfig.Direction int gravity) { if (mIndicator != null && mIndicator.getIndicatorConfig().isAttachToBanner()) { mIndicator.getIndicatorConfig().setGravity(gravity); mIndicator.getIndicatorView().postInvalidate(); } return this; } public ChangeBanner setIndicatorSpace(int indicatorSpace) { if (mIndicator != null) { mIndicator.getIndicatorConfig().setIndicatorSpace(indicatorSpace); } return this; } public ChangeBanner setIndicatorMargins(IndicatorConfig.Margins margins) { if (mIndicator != null && mIndicator.getIndicatorConfig().isAttachToBanner()) { mIndicator.getIndicatorConfig().setMargins(margins); mIndicator.getIndicatorView().requestLayout(); } return this; } public ChangeBanner setIndicatorWidth(int normalWidth, int selectedWidth) { if (mIndicator != null) { mIndicator.getIndicatorConfig().setNormalWidth(normalWidth); mIndicator.getIndicatorConfig().setSelectedWidth(selectedWidth); } return this; } public ChangeBanner setIndicatorNormalWidth(int normalWidth) { if (mIndicator != null) { mIndicator.getIndicatorConfig().setNormalWidth(normalWidth); } return this; } public ChangeBanner setIndicatorSelectedWidth(int selectedWidth) { if (mIndicator != null) { mIndicator.getIndicatorConfig().setSelectedWidth(selectedWidth); } return this; } public ChangeBanner setIndicatorRadius(int indicatorRadius) { if (mIndicator != null) { mIndicator.getIndicatorConfig().setRadius(indicatorRadius); } return this; } public ChangeBanner setIndicatorHeight(int indicatorHeight) { if (mIndicator != null) { mIndicator.getIndicatorConfig().setHeight(indicatorHeight); } return this; } /** * ********************************************************************** * ------------------------ 生命周期控制 --------------------------------* * ********************************************************************** */ public ChangeBanner addBannerLifecycleObserver(LifecycleOwner owner) { if (owner != null) { owner.getLifecycle().addObserver(new BannerLifecycleObserverAdapter(owner, this)); } return this; } @Override public void onStart(LifecycleOwner owner) { start(); } @Override public void onStop(LifecycleOwner owner) { stop(); } @Override public void onDestroy(LifecycleOwner owner) { destroy(); } } manager相关类

用于处理轮播及Activity生命周期相关的事件

BannerVideoManager import android.content.Context; import android.os.Handler; import android.widget.Toast; import com.saqino.picvideobanner.banner.ChangeBanner; import com.saqino.picvideobanner.banner.adapter.MediaVideoBannerAdapter; import com.saqino.picvideobanner.banner.holder.VideoHolder; import com.saqino.picvideobanner.bean.ResourceBean; import com.shuyu.gsyvideoplayer.listener.GSYSampleCallBack; import com.youth.banner.listener.OnPageChangeListener; import java.util.List; public class BannerVideoManager { private Context context; private ChangeBanner banner; private MediaVideoBannerAdapter adapter; //数据源,请自行替换 private List list; private long mPageChangeMillis = 5000; private long mVideoPlayLoadWait = 500; public BannerVideoManager(Context context, ChangeBanner banner, MediaVideoBannerAdapter adapter, List list){ this.context = context; this.banner = banner; this.adapter = adapter; this.list = list; banner.addOnPageChangeListener(new BannerPageChange()); } //设置切换间隔时间,单位毫秒 public void setPageChangeMillis(long mills){ this.mPageChangeMillis = mills; } /** * 设置视频播放前置等待时间,单位毫秒 * * 设置为无限轮播时,适配器中会多出两个ViewHolder * 需要给banner自动切换ViewHolder一点时间 * 保证获取到的ViewHolder是当前展示的那一个 * * @param mills */ public void setVideoPlayLoadWait(long mills){ this.mVideoPlayLoadWait = mills; } /** * 视频+图片轮播处理代码 */ private VideoHolder currentVideoHolder = null; private class BannerPageChange implements OnPageChangeListener { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { mPosition = position; if (adapter != null){ currentVideoHolder = null; //当前页不是视频类型 if (list.get(position).getType() != 2) { adapter.stopVideo(); if (videoPlayRunnable != null) mHandler.removeCallbacks(videoPlayRunnable); startScroll(mPageChangeMillis); }else { //视频类型,且仅有一个视频,自动重播 if (list.size() == 1) playVideo(0, position); else { playVideo(mVideoPlayLoadWait, position+1); } stopScroll(); } } } @Override public void onPageScrollStateChanged(int state) { } } //当前position(显示出来的position,非真实position private int mPosition = 0; private Handler mHandler = new Handler(); //轮播切换的runnable private Runnable runnable = new Runnable() { @Override public void run() { mHandler.removeCallbacks(runnable); banner.setCurrentItem(banner.getCurrentItem() + 1, true); } }; //控制视频播放 private Runnable videoPlayRunnable; private void playVideo(long millis, int position){ if (videoPlayRunnable != null) mHandler.removeCallbacks(videoPlayRunnable); videoPlayRunnable = new Runnable(){ @Override public void run() { if (position == 1 && list.size() > 1 && banner.getCurrentItem() != 1){ banner.setCurrentItem(1, false); return; } VideoHolder videoHolder = adapter.getVideoHolder(position); if (videoHolder == null) { showToast("获取视频播放控件出错"); return; } videoHolder.player.onVideoReset(); videoHolder.player.startPlayLogic(); videoHolder.player.setVideoAllCallBack(new GSYSampleCallBack(){ @Override public void onAutoComplete(String url, Object... objects) { super.onAutoComplete(url, objects); if (position == 0) videoHolder.player.startPlayLogic(); else startScroll(0); } }); currentVideoHolder = videoHolder; } }; mHandler.postDelayed(videoPlayRunnable, millis); } //开始切换 private void startScroll(long millis){ mHandler.postDelayed(runnable, millis); } //停止切换 private void stopScroll(){ mHandler.removeCallbacks(runnable); } private void showToast(String str){ Toast.makeText(context, str, Toast.LENGTH_SHORT).show(); } //Activity生命周期控制 public void onPause(){ stopScroll(); if (currentVideoHolder != null) currentVideoHolder.player.onVideoPause(); mHandler.removeCallbacks(videoPlayRunnable); } //Activity生命周期控制 public void onResume(){ if (list == null) return; if (list.size() == 0) return; if (list.get(mPosition).getType() == 2) { if (currentVideoHolder != null) currentVideoHolder.player.onVideoResume(); else { if (list.size() == 1) playVideo(mVideoPlayLoadWait, mPosition); else playVideo(mVideoPlayLoadWait, mPosition+1); } }else startScroll(mPageChangeMillis); } //Activity生命周期控制 public void onDetachedFromWindow(){ stopScroll(); } } ScrollSpeedManger

原项目中的一个管理类,修改了adapter的类型

import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearSmoothScroller; import androidx.recyclerview.widget.RecyclerView; import androidx.viewpager2.widget.ViewPager2; import com.saqino.picvideobanner.banner.ChangeBanner; import java.lang.reflect.Field; /** * 改变LinearLayoutManager的切换速度 */ public class ScrollSpeedManger extends LinearLayoutManager { private ChangeBanner banner; public ScrollSpeedManger(ChangeBanner banner, LinearLayoutManager linearLayoutManager) { super(banner.getContext(), linearLayoutManager.getOrientation(), false); this.banner = banner; } @Override public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) { @Override protected int calculateTimeForDeceleration(int dx) { return banner.getScrollTime(); } }; linearSmoothScroller.setTargetPosition(position); startSmoothScroll(linearSmoothScroller); } public static void reflectLayoutManager(ChangeBanner banner) { if (banner.getScrollTime() < 100) return; try { ViewPager2 viewPager2 = banner.getViewPager2(); RecyclerView recyclerView = (RecyclerView) viewPager2.getChildAt(0); recyclerView.setOverScrollMode(RecyclerView.OVER_SCROLL_NEVER); ScrollSpeedManger speedManger = new ScrollSpeedManger(banner, (LinearLayoutManager) recyclerView.getLayoutManager()); recyclerView.setLayoutManager(speedManger); Field LayoutMangerField = ViewPager2.class.getDeclaredField("mLayoutManager"); LayoutMangerField.setAccessible(true); LayoutMangerField.set(viewPager2, speedManger); Field pageTransformerAdapterField = ViewPager2.class.getDeclaredField("mPageTransformerAdapter"); pageTransformerAdapterField.setAccessible(true); Object mPageTransformerAdapter = pageTransformerAdapterField.get(viewPager2); if (mPageTransformerAdapter != null) { Class aClass = mPageTransformerAdapter.getClass(); Field layoutManager = aClass.getDeclaredField("mLayoutManager"); layoutManager.setAccessible(true); layoutManager.set(mPageTransformerAdapter, speedManger); } Field scrollEventAdapterField = ViewPager2.class.getDeclaredField("mScrollEventAdapter"); scrollEventAdapterField.setAccessible(true); Object mScrollEventAdapter = scrollEventAdapterField.get(viewPager2); if (mScrollEventAdapter != null) { Class aClass = mScrollEventAdapter.getClass(); Field layoutManager = aClass.getDeclaredField("mLayoutManager"); layoutManager.setAccessible(true); layoutManager.set(mScrollEventAdapter, speedManger); } } catch (Exception e) { e.printStackTrace(); } } }

Holder类 import android.view.View; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import com.saqino.picvideobanner.R; import com.shuyu.gsyvideoplayer.video.StandardGSYVideoPlayer; public class VideoHolder extends RecyclerView.ViewHolder { public StandardGSYVideoPlayer player; public VideoHolder(@NonNull View view) { super(view); player = view.findViewById(R.id.player); } } import android.view.ViewGroup; public interface IBaseViewHolder { /** * 创建ViewHolder * * @return XViewHolder */ VH onCreateHolder(ViewGroup parent, int viewType); /** * 绑定布局数据 * * @param holder XViewHolder * @param data 数据实体 * @param position 当前位置 * @param size 总数 */ void onBindView(VH holder, T data, int position, int size, int adapterPosition); } import android.view.View; import android.widget.ImageView; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; public class ImageHolder extends RecyclerView.ViewHolder { public ImageView imageView; public ImageHolder(@NonNull View view) { super(view); this.imageView = (ImageView) view; } }



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有