AndroidBanner - ViewPager 03

这篇具有很好参考价值的文章主要介绍了AndroidBanner - ViewPager 03。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

AndroidBanner - ViewPager 03

上一篇文章,描述了如何实现自动轮播的,以及手指触摸的时候停止轮播,抬起继续轮播,其实还遗留了一些问题:

  1. 当banner不可见的时候,也需要停止轮播
  2. 给banner设置点击事件,长时间的触摸也会被默认是一个点击事件

这篇文章就来解决这些问题,并处理一下banner的曝光打点问题。

解决banner 不可见依旧轮播的问题

思考一下:什么时候可以轮播,什么时候不可以轮播

当Banner添加到屏幕上,且对用户可见的时候,可以开始轮播
当Banner从屏幕上移除,或者Banner不可见的时候,可以停止轮播
当手指触摸到Banner时,停止轮播
当手指移开时,开始轮播

所以,我们需要知道什么时候View可见,不可见,添加到屏幕上和从屏幕上移除,幸运的是,这些,android都提供了对应的接口来获取。

OnAttachStateChangeListenner

该接口可以通知我们view添加到屏幕上或者从屏幕上被移除,或者可以直接重写view的onAttachedToWindow和onDetachedFromWindow方法

// view提供的接口,可以通过 addOnAttachStateChangeListener 添加舰艇
public interface OnAttachStateChangeListener {  
	public void onViewAttachedToWindow(@NonNull View v);  
	public void onViewDetachedFromWindow(@NonNull View v);  
}

// 复写view的方法
override fun onAttachedToWindow() {  
    super.onAttachedToWindow()  
}  
  
override fun onDetachedFromWindow() {  
    super.onDetachedFromWindow()  
}

这里我们通过复写方法的方式处理

onVisibilityChanged

view 提供了方法,可以复写该方法,获取到view 的可见性变化

protected void onVisibilityChanged(@NonNull View changedView, @Visibility int visibility) {  
}

onWindowVisibilityChanged

view 提供了方法,可以复习该方法,当前widow的可见性发生变化的时候,会调用通知给我们

protected void onWindowVisibilityChanged(@Visibility int visibility) {  
    if (visibility == VISIBLE) {  
        initialAwakenScrollBars();  
    }  
}

我们根据上面的api,可以封装一个接口,来监听View的可见性

VisibleChangeListener

interface VisibleChangeListener {  
    /**  
     * view 可见  
     */  
    fun onShown()  
  
    /**  
     * view 不可见  
     */  
    fun onDismiss()  
}

Banner重写方法,进行调用

override fun onVisibilityChanged(changedView: View, visibility: Int) {  
    Log.e(TAG, "onVisibilityChanged ${changedView == this}, vis: $visibility")  
    dispatchVisible(visibility)  
}  
  
override fun onWindowVisibilityChanged(visibility: Int) {  
    super.onWindowVisibilityChanged(visibility)  
    Log.e(TAG, "onWindowVisibilityChanged $visibility")  
    dispatchVisible(visibility)  
}  
  
override fun onAttachedToWindow() {  
    super.onAttachedToWindow()  
    Log.e(TAG, "onAttachedToWindow ")  
    this.mAttached = true  
}  
  
override fun onDetachedFromWindow() {  
    Log.e(TAG, "onDetachedFromWindow ")  
    super.onDetachedFromWindow()  
    this.mAttached = false  
}

private fun dispatchVisible(visibility: Int) {  
    val visible = mAttached && visibility == VISIBLE  
    if (visible) {  
        prepareLoop()  
    } else {  
        stopLoop()  
    }  
    mVisibleChangeListener?.let {  
        when (visible) {  
            true -> it.onShown()  
            else -> it.onDismiss()  
        }  
    }  
}

页面滚动时处理banner轮播

滚动监听,如果是scrollview,就监听滚动事件处理即可。如果是listview,recyclerview可以选择监听onscrollstatechanged,更高效。
下面是scrollview的监听处理

mBinding.scrollView.setOnScrollChangeListener(object :OnScrollChangeListener{  
    override fun onScrollChange(  
        v: View?,  
        scrollX: Int,  
        scrollY: Int,  
        oldScrollX: Int,  
        oldScrollY: Int  
    ) {  
        val visible = mBinding.vpBanner.getGlobalVisibleRect(Rect())  
        Log.e(TAG,"banner visible : $visible")  
        if(visible){  
            mBinding.vpBanner.startLoop()  
        }else{  
            mBinding.vpBanner.stopLoop()  
        }  
    }  
})

点击事件的处理

首先要声明一个点击事件回调接口

interface PageClickListener {  
    fun onPageClicked(position: Int)  
}

重写banner的onTouch事件,将移动距离小于100,且按压时间小于500ms的事件认为是点击事件

private var mMoved = false  
private var mDownX = 0F  
private var mDownY = 0F  
  
/**  
 * 当前事件流结束时,恢复touch处理的相关变量  
 */  
private fun initTouch() {  
    this.mMoved = false  
    this.mDownX = 0F  
    this.mDownY = 0F  
}  
  
private fun calculateMoved(x: Float, y: Float, ev: MotionEvent) {  
    mClickListener?.let {  
        // 超过500ms(系统默认的时间) 我们认为不是点击事件  
        if (ev.eventTime - ev.downTime >= 500) {  
            return  
        }  
        // 移动小于阈值我们认为是点击  
        if (sqrt(((x - mDownX).pow(2) + (y - mDownY).pow(2))) >= MOVE_FLAG) {  
            return  
        }  
        val count = adapter?.count ?: 0  
        if (count == 0) {  
            return  
        }  
        // 由于我们实现无限轮播的方式是重新设置当前选中的item,这里要将currentItem重新映射回去  
        val index = when (currentItem) {  
            in 1..count - 2 -> currentItem - 1  
            0 -> count - 1  
            else -> 0  
        }  
        it.onPageClicked(index)  
    }  
}  
  
override fun onTouchEvent(ev: MotionEvent?): Boolean {  
    when (ev?.action) {  
        MotionEvent.ACTION_DOWN -> {  
            this.mDownY = ev.y  
            this.mDownX = ev.x  
            stopLoop()  
        }  
        MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {  
            val y = ev.y  
            val x = ev.x  
            calculateMoved(x, y, ev)  
            initTouch()  
            prepareLoop()  
        }  
    }  
    return super.onTouchEvent(ev)  
}

曝光打点的处理

监听page切换,当page变化的时候,从实际展示的数据队列中取出数据进行曝光。

class ExposureHelper(private val list: List<*>, private var last: Int = -1) :  
    ViewPager.OnPageChangeListener {  
  
    private var mStart: AtomicBoolean = AtomicBoolean(false);  
  
    override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) =  
        Unit  
  
    override fun onPageSelected(position: Int) {  
        Log.e(TAG, "$position $last")  
        if (last >= 0) {  
            exposure()  
        }  
        last = position  
    }  
  
    override fun onPageScrollStateChanged(state: Int) = Unit  
  
    /**  
     * 开始曝光  
     * @param current Int  
     */    fun startExposure(current: Int) {  
        mStart.set(true)  
        last = current  
    }  
  
    /**  
     * 停止曝光  
     */  
    fun endExposure() {  
        if (mStart.get()) {  
            mStart.set(false)  
            exposure()  
        }  
    }  
  
    /**  
     * 实际执行数据上报的处理  
     */  
    private fun exposure() {  
        val data = list[last]  
        Log.e(TAG, "data:$data")  
    }  
  
    companion object {  
        private const val TAG = "ExposureHelper"  
    }  
}

VPAdapter 对外提供实际展示的数据集

private val mData = mutableListOf<T>()  
  
fun setData(data: List<T>) {  
    mData.clear()  
    if (this.loop && data.size > 1) {  
        // 数组组织一下,用来实现无限轮播  
        mData.add(data[data.size - 1])  
        mData.addAll(data)  
        mData.add(data[0])  
    } else {  
        mData.addAll(data)  
    }  
}

fun getShowDataList():List<T>{  
    return mData  
}

在Banner中的配置使用

private var mExposureHelper: ExposureHelper? = null

/**  
 * 自动轮播  
 */  
fun startLoop() {  
    if (mLoopHandler == null) {  
        mLoopHandler = Handler(Looper.getMainLooper()) { message ->  
            return@Handler when (message.what) {  
                LOOP_NEXT -> {  
                    loopNext()  
                    true  
                }  
                else -> false  
            }  
        }  
    }  
    if (mLoopHandler?.hasMessages(LOOP_NEXT) != true) {  
        Log.e(TAG, "startLoop")  
        mLoopHandler?.sendEmptyMessageDelayed(LOOP_NEXT, mLoopDuration)  
    }  
    // 开始轮播时开始曝光(可见时会触发轮播)  
    mExposureHelper?.startExposure(currentItem)  
}  
  
fun stopLoop() {  
    // 停止轮播时结束曝光(不可见时会停止轮播)  
    mExposureHelper?.endExposure()  
    mLoopHandler?.removeMessages(LOOP_NEXT)  
}

fun bindExposureHelper(exposureHelper: ExposureHelper?) {  
    mExposureHelper = exposureHelper  
    mExposureHelper?.let {  
        addOnPageChangeListener(it)  
    }  
    mExposureHelper?.startExposure(currentItem)  
}

代码:huyuqiwolf/Banner (github.com)文章来源地址https://www.toymoban.com/news/detail-404553.html

到了这里,关于AndroidBanner - ViewPager 03的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • android viewpager 禁止滑动

    本文介绍了本人有一个相关的需求需要实现这一功能,在过程中发现自己之前没做过,然后记录下实现这一功能的过程及相关的小知识点。 viewpager 禁止滑动,就是在特殊的条件,比如说编辑的状态下,是不允许用户滑动的,但是看了下viewpager 的源码,也百度了一下,并没有

    2024年01月19日
    浏览(47)
  • ViewPager2+TabLayout

    ViewPager2最显著的特点是基于RecyclerView实现,RecyclerView是目前Android端最成熟的AdapterView解决方案,这带来诸多好处: 1、抛弃传统的PagerAdapter,统一了Adapter的API/ 2、通过LinearLayoutManager可以实现类似抖音的纵向滑动 3、支持DiffUitl,可以通过diff实现局部刷新 4、支持RTL(right-to-

    2023年04月19日
    浏览(41)
  • Android:ViewPager2

    ViewPager2内部使用RecyclerView实现,并提供了增强功能 支持水平、垂直方向布局 android:orientation = “vertical” 支持从右到左 android:layoutDirection = “rtl” 禁止滑动 setUserInputEnabled() 可修改Fragment集合 对可修改的Fragment集合进行分页浏览,底层集合更改时调用notifyDatasetChanged来更新页

    2024年02月09日
    浏览(40)
  • 关于Android ViewPager禁止滑动

    ViewPager经常被用来实现轮播图,页面切换的效果。 关于页面切换,可以搭配Fragment+TabLayout,感兴趣的可以去看一下我之前的文章: TabLayout 加 ViewPager实现类似选项卡可切换的功能_水很清的博客-CSDN博客  关于实现轮播图的,我之前也有封装过,使用起来很简单,也好用,链接

    2024年02月16日
    浏览(63)
  • 关于安卓viewpager实现堆叠卡片交互

    长江后浪推前浪,无聊的需求一浪接一浪。 最近做到一个关于卡片堆叠的需求,觉得挺有意思,所以特此记录一下。 文末将附上源码链接 首先看设计图: 可以看到,是一个卡片堆叠的效果,关于这种UI的实现,方法有很多,例如用recyclerview,viewpager,甚至说自定义view都可以

    2024年02月11日
    浏览(38)
  • 统计viewpager中页面进入的次数

    利用OnPageChangeListener的onPageScrolled方法,在该方法中判断positionOffsetPixels == 0,即可判断选中的页面。

    2024年02月06日
    浏览(42)
  • Android 之 ViewPager 的简单使用

    本节带来的是Android 3.0后引入的一个UI控件——ViewPager(视图滑动切换工具),实在想不到 如何来称呼这个控件,他的大概功能:通过手势滑动可以完成View的切换,一般是用来做APP 的引导页或者实现图片轮播,因为是3.0后引入的,如果想在低版本下使用,就需要引入v4 兼容包哦

    2024年02月06日
    浏览(49)
  • Android ViewPager2 + Fragment 联动

    本篇主要介绍一下 ViewPager2 + Fragment , 上篇中简单使用了ViewPager2 实现了一个图片的滑动效果, 那图片视图可以滑动, ViewPager2也可以滑动 Fragment 概述 ViewPager2 官方对它的描述就是 以可滑动的格式显示视图或 Fragment 也就说明提供了滑动Fragment的实现 并且还很简单, 下面来看看吧

    2023年04月08日
    浏览(44)
  • ViewPager+ Fragment结合的setUserVisibleHint()调用时机

    最近的项目使用到了 ViewPager + Fragment 的模式,要求在每次 Fragment 获取显示的时候来刷新数据,该项目下 ViewPager 有5个子fragment,在onCreateView及fragment的**setUserVisibleHint(bool isVisibleToUser)**中的isVisibleToUser为true的时候刷新数据的时候出现数据多次刷新的情况,因此对ViewPage + Fr

    2024年02月11日
    浏览(38)
  • Android——禁止ViewPager的左右滑动功能实现

    Android——禁止ViewPager的左右滑动功能实现 在Android开发中,ViewPager是一种常用的滑动控件,用于实现页面的左右切换效果。然而,在某些场景中,我们可能需要禁止ViewPager的左右滑动功能,只允许通过其他方式进行页面切换。本文将介绍如何在Android中实现禁止ViewPager左右滑动

    2024年02月06日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包