AndroidBanner - ViewPager

解决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)  
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/18232.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Kafka系列之:安装Know Streaming详细步骤

Kafka系列之:安装Know Streaming详细步骤 一、相关技术博客二、安装elasticsearch1.下载elasticsearch2.创建数据目录3.创建es用户4.修改最大文件数5.解压elasticsearch6.赋予es用户目录权限7.修改es配置8.切换es用户启动elasticsearch三、安装KnowStreaming1.下载KnowStreami…

电影推荐系统】系统初步搭建及离线个性化推荐

上篇博文我们已经写完统计推荐部分&#xff0c;现在我们将使用VueElement-uiSpringBoot来快速搭建系统&#xff0c;展示出电影&#xff0c;并介绍个性化推荐部分。 1 系统页面设计 初步是想设计一个类似豆瓣电影推荐系统 用户登陆后&#xff0c;可以查看高分电影可以查看推荐…

P2404 自然数的拆分问题

题目 思路 最简单的dfs题之一 只需要一点点小优化 代码 #include<bits/stdc.h> using namespace std; const int maxn55; int n; int ans[maxn],s; void print(int tot) { for(int i1;i<tot-1;i) cout<<ans[i]<<""; cout<<ans[tot-1]&…

微信小程序,商城底部工具栏的实现

效果演示&#xff1a; 前提条件&#xff1a; 去阿里云矢量图标&#xff0c;下载8个图标&#xff0c;四个黑&#xff0c;四个红&#xff0c;如图&#xff1a; 新建文件夹icons&#xff0c;把图标放到该文件夹&#xff0c;然后把该文件夹移动到该项目的文件夹里面。如图所示 app…

【Redis深度专题】「核心技术提升」探究Redis服务启动的过程机制的技术原理和流程分析的指南(集群指令分析—实战篇)

探究Redis服务启动的过程机制的技术原理和流程分析的指南&#xff08;集群指令分析—下篇&#xff09; Cluster XX的集群指令&#xff08;扩展&#xff09;写入记录主节点和备节点切换-CLUSTER FAILOVER新加入master节点新加入slave节点为slave节点重新分配master分配哈希槽删除…

jmeter之接口测试(http接口测试)

基础知识储备 一、了解jmeter接口测试请求接口的原理 客户端--发送一个请求动作--服务器响应--返回客户端 客户端--发送一个请求动作--jmeter代理服务器---服务器--jmeter代理服务器--服务器 二、了解基础接口知识&#xff1a; 1、什么是接口&#xff1a;前端与后台之间的…

动手学深度学习(一)预备知识

目录 一、数据操作 1. N维数组样例 2. 访问元素 3. 基础函数 &#xff08;1&#xff09; 创建一个行向量 &#xff08;2&#xff09;通过张量的shape属性来访问张量的形状和元素总数 &#xff08;3&#xff09;reshape()函数 &#xff08;4&#xff09;创建全0、全1、…

在springboot项目中使用策略工厂模式

在springboot项目中使用策略工厂模式 策略接口类 package cn.test.ext;public interface ITestStrategy {void execTestMethod(); }策略实现类 package cn.test.ext.beanlife;import cn.test.ext.ITestStrategy; import cn.test.ext.MyStrategyFactory; import lombok.exter…

【Spring】Spring之推断构造方法源码解析

Spring的Bean生命周期中&#xff0c;需要通过构造方法来实例化对象&#xff0c;如果构造方法由多个或者手动指定构造方法&#xff0c;该如何选择用来实例化Bean的构造方法呢。 构造方法选择 一个构造方法时&#xff1a;如果只有一个无参的构造方法&#xff0c;那么实例化就只…

CorelDraw怎么做立体字效果?CorelDraw制作漂亮的3d立体字教程

1、打开软件CorelDRAW 2019&#xff0c;用文本工具写上我们所需要的大标题。建议字体选用比较粗的适合做标题的字体。 2、给字填充颜色&#xff0c;此时填充的颜色就是以后立体字正面的颜色。我填充了红色&#xff0c;并加上了灰色的描边。 3、选中文本&#xff0c;单击界面左侧…

java 企业工程管理系统软件源码+Spring Cloud + Spring Boot +二次开发+ MybatisPlus + Redis

&#xfeff; Java版工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离 功能清单如下&#xff1a; 首页 工作台&#xff1a;待办工作、消息通知、预警信息&#xff0c;点击可进入相应的列表 项目进度图表&#xff1a;选择&#xff08;总体或单个&am…

Metric3D:Towards Zero-shot Metric 3D Prediction from A Single Image

参考代码&#xff1a;Metric3D 介绍 在如MiDas、LeReS这些文章中对于来源不同的深度数据集使用归一化深度作为学习目标&#xff0c;则在网络学习的过程中就天然失去了对真实深度和物体尺寸的度量能力。而这篇文章比较明确地指出了影响深度估计尺度变化大的因素就是焦距 f f f…

驱动开发-按键中断

编写LED灯的驱动&#xff0c;使用GPIO子系统&#xff0c;里面添加按键的中断处理 1.应用程序发送指令控制LED亮灭 2.按键1 按下&#xff0c;led1电位反转 按键2按下&#xff0c;led2电位反转 按键3 按下&#xff0c;led3电位反转 功能函数 #include<stdlib.h> #inclu…

本地shell无法连接ubuntu,解决办法?

1.启动ssh服务&#xff1b; sudo /etc/init.d/ssh start若重启ssh服务后&#xff0c;还是连接不上&#xff0c;继续第2步&#xff1b; 2.修改SSH配置文件 /etc/ssh/sshd_config 默认是不允许root远程登录的&#xff0c;可以再配置文件开启。 sudo vi /etc/ssh/sshd_config找…

TypeC拓展设计方案|TypeC转HDMI设计方案|CS5261/CS5265芯片设计参数对比

集睿智远CS5261/CS5265都可以用于设计TypeC转HDMI方案&#xff0c;低成本TypeC扩展坞设计方案&#xff0c;而两者也有些差异&#xff1a;1.CS5261支持DP1.4输入&#xff0c;一个HDMI1.4输出&#xff0c;即HDMI输出为4K30HZ ;CS5265DP1.4到HDMI2.0转换芯片&#xff0c;即HDMI输出…

ansible安装lnmp(集中式)

文章目录 一、安装nginx二、安装mysql三、安装php测试&#xff1a; 一、安装nginx - name: the nginx playhosts: webserversremote_user: roottasks:- name: stop firewalld #关闭防火墙service: namefirewalld statestopped enabledno- name: selinux stopc…

pytorch+GPU跑模型时 nvrtc: error: failed to open nvrtc-builtins64_117.dll

1.先检查自己cuda版本&#xff1a; print(torch.version.cuda) #查看cuda版本 print(torch.cuda.is_available()) # 查看cuda是否可用 print(torch.cuda.device_count()) # 查看可行的cuda数目如果版本高于11建议先降版本&#xff0c;然后再试下。 2.重新安装nvrtc-builtin…

CGAL-2D和3D线性几何内核-点和向量-内核扩展

文章目录 1.介绍1.1.鲁棒性 2.内核表示2.1.通过参数化实现泛型2.2.笛卡尔核2.3.同质核2.4.命名约定2.5.内核作为trait类2.6.选择内核和预定义内核 3.几何内核3.1.点与向量3.2.内核对象3.3.方位和相对位置 4.谓语和结构4.1.谓词4.2.结构4.3.交集和变量返回类型4.4.例子4.5.建构性…

“深入探究Spring Boot的核心特性与原理“

标题&#xff1a;深入探究Spring Boot的核心特性与原理 摘要&#xff1a;本文将深入探究Spring Boot的核心特性与原理&#xff0c;包括自动配置、起步依赖和嵌入式容器等方面。通过详细解释每个特性的原理和工作方式&#xff0c;并提供示例代码&#xff0c;帮助读者更好地理解…

Python元编程-装饰器介绍、使用

目录 一、Python元编程装饰器介绍 二、装饰器使用 1. 实现认证和授权功能 2.实现缓存功能 3.实现日志输出功能 三、附录 1. logging.basicConfig介绍 2. 精确到毫秒&#xff0c;打印时间 方法一&#xff1a;使用datetime 方法二&#xff1a;使用time 一、Python元编程…