来一波效果图
qq_nav_gif3.gif有没有一种蠢蠢欲动的想法? 反正我已经动了.
分析一波
1:选中状态, 和未选中状态显示的图片不一样. 这个简单:一个Boolean成员变量控制.
2:当手指360°滑动的时候,图片会跟随移动.这个就是核心了, 需要计算手指距离图片中心的角度, 然后计算出偏移的dx,dy值.
3:细心的你, 可能已经发现了, 笑脸其实并不是相对滚动的, 是有滚动差的. 这个可以在步骤2计算的dx,dy中做一些放大操作就行.
4:当第一次,未选中状态点击的时候, 有一个缩放效果. 这个简单,就用一个动画可以的;
注意:以下代码使用kotlin编写,如果你还不会, 点击传送门去学习吧!
只针对上述步骤2做详解, 其他的太简单了:
override fun onTouchEvent(event: MotionEvent): Boolean {
super.onTouchEvent(event) //这里调用super的目的是,为了支持一些默认效果. 比如:onClickListener, 如果你没有调用super,那么onClickListener是不会回调的哦. 还有就是:如果你使用了background属性,那么background属性的selector也是不会有效果的哦.
val eventX = event.x
val eventY = event.y
when (MotionEventCompat.getActionMasked(event)) {
ACTION_DOWN -> {
scaleAnimation.cancel()
if (!mSelected) {
scaleAnimation.start()//当第一次未选中的时候点击, 播放缩放动画. 为了极致的模仿QQ效果而存在.
}
}
ACTION_MOVE -> {
downX = eventX
downY = eventY
//计算出, 当前手指距离图片中心的距离.
val dx = downX - imageCenterX
val dy = downY - imageCenterY
var atan = Math.atan((dy / dx).toDouble()) //拿到角度, 此函数返回的角度是弧度制的.
val degrees = Math.toDegrees(atan) //这个方法可以把弧度制的角度, 转换成角度制.如果30°之类的.
if (lastDegrees != null && Math.abs(lastDegrees!! - degrees) < 5) {
//如果手指移动时的夹角小于5°,不处理...防止图片抖动.
} else {
lastDegrees = degrees
//这是一个很关键的点, 因为理想状态下, 我们想要的角度范围应该是0-360°
//而你手指转一圈, 函数返回结果却是2个-90°-90°的取值范围.
//所以...数学当中的四象限你还记得么?
if (dx < 0) {
atan -= Math.PI //注意 atan是弧度制的角度哦, 因为cos函数,sin函数,都要求是弧度制的参数.
}
//有了角度之后, 就可以计算出三角形的邻边和对边了. 这2个值, 就是图片需要偏移中心点的距离.
mDrawOffsetX = (mMaxMoveOffset * Math.cos(atan)).toFloat()
mDrawOffsetY = (mMaxMoveOffset * Math.sin(atan)).toFloat()
//为了产生视差效果, 笑脸的偏移大小更大一点就行了.
mSubDrawOffsetX = (mSubMaxMoveOffset * Math.cos(atan)).toFloat()
mSubDrawOffsetY = (mSubMaxMoveOffset * Math.sin(atan)).toFloat()
//重绘....这个方法你不懂,就可以离职了.
postInvalidate()
}
}
ACTION_UP -> {
//恢复默认值
onTouchUp()
}
ACTION_CANCEL -> {
onTouchUp()
}
}
return true
}
private fun onTouchUp() {
downX = 0f
downY = 0f
mDrawOffsetX = 0f
mDrawOffsetY = 0f
mSubDrawOffsetX = 0f
mSubDrawOffsetY = 0f
lastDegrees = null
postInvalidate()
}
override fun onDraw(canvas: Canvas) {
canvas.save()
//绘制图片
if (drawDrawable != null) {
//下面2行代码, 是为了缩放做准备的, 首先移动到图片的中心, 然后再进行缩放处理.
canvas.translate((measuredWidth / 2).toFloat(), measuredHeight / 2 - subHeight / 2 + imageHeight / 2)
canvas.scale(animScale, animScale)
canvas.save()
canvas.translate(-imageWidth / 2 + mDrawOffsetX,
-imageHeight / 2 + mDrawOffsetY)
drawDrawable!!.draw(canvas)
canvas.restore()
//笑脸的绘制.
if (subDrawDrawable != null) {
canvas.save()
canvas.translate(-imageWidth / 2 + mSubDrawOffsetX,
-imageHeight / 2 + mSubDrawOffsetY)
subDrawDrawable!!.draw(canvas)
canvas.restore()
}
}
canvas.restore()
}
联系作者
请使用QQ扫码加群, 小伙伴们在等着你哦!
关注我的公众号, 每天都能一起玩耍哦!
网友评论