本文实例为大家分享了android实现可拖动的浮动view,供大家参考,具体内容如下
业务来源
页面最小化后,需要出现一个浮动 view 告知用户,防止遮挡视线,需要对 view 做可滑动处理
已知会遇到的问题
1.view 的依赖的布局类型未知【为了后续方便扩展】
外界传递 viewgroup 自己本身继承 linearlayout【或者其他 viewgroup 】
class floatchannelview(var mcontext: context?, var viewgroup: viewgroup) : linearlayout(mcontext){ private var micon: imageview = imageview(context) private var mname: textview = textview(context) private var mclose: imageview = imageview(context) private var iconwh = dip2px(38) private var grouppadding = dip2px(3) private var mviewgrouph = dip2px(44) private var mviewgroupw = dip2px(152) private var mboundaryleft: float private var mboundarytop: float private var mboundaryright: float private var mboundarybottom: float private var mscreenwidth = getscreenwidth() // 获取屏幕宽高 private var mscreenheight = getscreenheight() private var mdowneventx: float = 0f // 相对控件的x private var mdowneventy: float = 0f private var mdownx: float = 0f // 相对屏幕所在的 x private var mdowny: float = 0f private var mlistener: onclicklistener? = null private var misstartanimation: boolean = false private val mdefaultmargin = dip2px(12) private var mmarginleft = mdefaultmargin private var mmargintop = mdefaultmargin private var mmarginright = mdefaultmargin private var mmarginbottom = mdefaultmargin init { layoutparams = layoutparams(mviewgroupw, mviewgrouph) setpadding(grouppadding, grouppadding, grouppadding, grouppadding) setbackgroundresource(r.drawable.backage) // 建议加一些透明 orientation = horizontal gravity = gravity.center_vertical mboundaryleft = mmarginleft.tofloat() mboundarytop = mmargintop.tofloat() mboundaryright = mscreenwidth - mmarginright.tofloat() mboundarybottom = (mscreenheight - mmarginbottom - dip2px(85)).tofloat() setview() } }
2.拖动事件影响点击,事件分发处理。
override fun ontouchevent(event: motionevent?): boolean { if (misstartanimation) { // 动画正在进行无需处理 ontouch return true } if (event == null) { return super.ontouchevent(event) } misontouch = true //悬浮区域左上角坐标 val x = x val y = y //悬浮区域宽高 val width = mviewgroupw val height = mviewgrouph when (event.actionmasked) { action_down -> { //点击位置坐标 mdowneventx = event.x mdowneventy = event.y mdownx = x mdowny = y } action_up -> { muptime = system.currenttimemillis() if (mismove && abs(mdownx - x) <= 8f && abs(mdowny - y) <= 8f) { mlistener?.onclick(this) } mismove = false // 抬起后处理边界溢出问题 resilienceanimation(x, y, x + mviewgroupw, y + mviewgrouph) } action_move -> { val changex = event.x.toint() - mdowneventx val changey = event.y.toint() - mdowneventy mismove = true if (changex == 0f && changey == 0f) { return super.ontouchevent(event) } val left = (x + changex).toint() val top = (y + changey).toint() val right = left + mviewgroupw val bottom = top + mviewgrouph layout(left, top, right, bottom) } } return true }
3.拖到边界问题。
拖出边界后做了回弹处理
/** * 超出边界回弹 * @param left 当前 x 方向位置 * @param right 当前 y 方向位置 */ private fun resilienceanimation(left: float, top: float, right: float, bottom: float) { var startx = 0f var resiliencex = 0f if (mboundaryleft <= left && right <= mboundaryright) { // x 方向在范围内 // 不处理 } else if (mboundaryleft > left) { // left 溢出 startx = 0f resiliencex = mboundaryleft - left } else { // right 方向底部溢出 startx = 0f resiliencex = mboundaryright - right } var starty = 0f var resiliencey = 0f if (mboundarytop <= top && bottom <= mboundarybottom) { // y 方向在范围内 // 不处理 } else if (mboundarytop > top) { // top 溢出 starty = 0f resiliencey = mboundarytop - top } else { // bottom 溢出 starty = 0f resiliencey = mboundarybottom - bottom } if (resiliencex == 0f && resiliencey == 0f) { // 在范围内无需回弹 return } // 超出边界回弹 val phasefirstduration: long = 400 var oanimphasefirsttupx: objectanimator? = null if (resiliencex != 0f) { oanimphasefirsttupx = objectanimator.offloat(this, "translationx", startx, resiliencex) .setduration(phasefirstduration) } var oanimphasefirsttupy: objectanimator? = null if (resiliencey != 0f) { oanimphasefirsttupy = objectanimator.offloat(this, "translationy", starty, resiliencey) .setduration(phasefirstduration) } val animatorset = animatorset() if (oanimphasefirsttupx != null && oanimphasefirsttupy != null) { animatorset.play(oanimphasefirsttupx).with(oanimphasefirsttupy) } else if (oanimphasefirsttupx != null) { animatorset.play(oanimphasefirsttupx) } else { animatorset.play(oanimphasefirsttupy) } animatorset.childanimations[animatorset.childanimations.size - 1].addlistener(object : animator.animatorlistener { override fun onanimationstart(animation: animator?) { misstartanimation = true } override fun onanimationend(animation: animator?) { var l = left var t = top var r = right var b = bottom when { mboundaryleft > left -> { // x左边溢出 l = mboundaryleft r = mboundaryleft + mviewgroupw } mboundaryright < right -> { // x右边溢出 l = mboundaryright - mviewgroupw r = mboundaryright } else -> { // x方向未溢出 } } when { mboundarytop > top -> { // y 顶部溢出 t = mboundarytop b = mboundarytop + mviewgrouph } mboundarybottom < bottom -> { // y 底部溢出 t = mboundarybottom - mviewgrouph b = mboundarybottom } else -> { // y方向未溢出 } } // 只进行偏移,实际位置未变化,需要重置偏移量,并重绘 this@floatchannelview.translationx = 0f this@floatchannelview.translationy = 0f layout(l.toint(), t.toint(), r.toint(), b.toint()) mmarginleft = l.toint() mmargintop = t.toint() misstartanimation = false } override fun onanimationcancel(animation: animator?) {} override fun onanimationrepeat(animation: animator?) {} }) animatorset.start()
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
声明:如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。