android-misc-widgets多方抽屉bug修复版 解决“闪烁”问题

http://blog.csdn.net/lovehong0306


前几天项目需要用到左侧拉出抽屉,想到了http://blog.csdn.net/hellogv/article/details/6264706中提到的多方抽屉,拿来试用了下,发现bug还真不少,最不能忍受的是最后那一下“闪烁”,于是乎,改!

下面将修改过程中遇到的问题及其解决方法分享给大家。

首先是出现了如图的情况:

当以光的速度点击handle(就是那个带箭头的Button)并拉出到很远很远的地方 就出先上边那个神奇的现象了

寻找原因,发现是这里的问题

			if (tmpX != mTrackX || tmpY != mTrackY)
			{
				mTrackX = tmpX;
				mTrackY = tmpY;
				// invalidate(); //放在此导致极快速滑动至touch区域外界面不刷新(mTrackX、mTrackY均为0)
			}
			invalidate();

就拿上边那种情况来讲

当瞬间将handle拉至最大位置,即 tmpX=0 的位置,由于mTrackX默认为0,if条件不成立,执行不到invalidate()方法,页面没有刷新

将invalidate()方法移到if'条件语句之外即可解决问题


下一问题:onFling方法在将抽屉快速抽出时基本不能用

抽出来~滑进去~抽出来~滑进去~     (这个抽屉带弹簧的@_@?!)

究其原因,在这里

public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
		mState = State.FLYING;
		mVelocity = mOrientation == VERTICAL? velocityY : velocityX;
		post(startAnimation);
		return true;
	}

mVelocity 使用的是onFling方法传进来的参数velocityX,经多次打印log发现velocityX为负数大致看了下源码,这个速度是基于getX()方法算出来的是
大家都知道,getX()方法是获取以widget左上角为坐标原点计算的X轴坐标值(不知道的看这里:http://blog.csdn.net/lovehong0306/article/details/7451507
由此推想而知
1.点击handle(此时content为GONE),这时的getX()得到的是以handle左上角为原点的坐标

2.快速滑动以发动onFling方法(快到只有两个event事件发生),这时getX()得到的依然是以handle的左上角为原点的坐标,但是由于content已经可见,handle的位置发生了变化,为抽屉完全抽出时的位置,而action_up事件发生时的getX()得到是在handle原点的左边,即为负值,用此时的X坐标值减去之前得到的那个正的坐标值,结果当然是负的了

3.有负的偏移量和时间,计算出来的速度也就是负的了

这就是为什么拉出抽屉后会滑进去的原因了


修改为如下即可解决:

@Override
		public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
				float velocityY)
		{
			mState = State.FLYING;

			float velocityX2, velocityY2;
			if (lastRawX == -1 && lastRawY == -1)	//见onScroll方法
			{
				velocityX2 = (curRawX - e1.getRawX())
						/ (curEventTime - e1.getEventTime()) * 1000; //  px/s
				velocityY2 = (curRawY - e1.getRawY())
						/ (curEventTime - e1.getEventTime()) * 1000;
			}
			else
			{
				velocityX2 = (curRawX - lastRawX)
						/ (curEventTime - lastEventTime) * 1000;
				velocityY2 = (curRawY - lastRawY)
						/ (curEventTime - lastEventTime) * 1000;
			}

			mVelocity = mOrientation == VERTICAL ? velocityY2 : velocityX2;

			if (Math.abs(mVelocity) > 50)
			{
				if (mVelocity > 0)
				{
					mAnimatedAcceleration = mMaximumAcceleration;
				}
				else
				{
					mAnimatedAcceleration = -mMaximumAcceleration;
				}

				long now = SystemClock.uptimeMillis();
				mAnimationLastTime = now;
				mCurrentAnimationTime = now + ANIMATION_FRAME_DURATION;
				mAnimating = true;
				mHandler.removeMessages(MSG_ANIMATE);
				mHandler.removeMessages(MSG_PREPARE_ANIMATE);
				mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_ANIMATE),
						mCurrentAnimationTime);
				return true;
			}
			return false;
		}

代码就不多做解释了,命名还算规范,应该能看懂,最后那几行是为解决“闪烁”问题的

下面就来说下最棘手的问题——“闪烁”


那么为什么会闪烁呢?

经多次尝试,发现是动画与setVisibility(GONG)冲突,当把动画设置为setFillAfter(true)后即可发现,动画结束后设置控件setVisibility(GONG),消失的不仅仅是content,handle也一同消失了。

由此可知handle在动画结束后先消失再出现,于是就出现了闪烁的效果


那么好办,只要把content和handle分别同时设置动画不就行了,content在动画结束后setVisibility(GONG),handle不setVisibility(GONG)。

But,这么尝试了一下发现,虽然“几乎”同时start动画,毕竟还是有时间间隔的,机子性能越差越明显,content和handle分开了!!!

此法行不通,另想他法


源码真是个好东西,看看SlidingDrawer是怎么实现的

原来如此,没用系统动画,利用handler重复改变控件位置

好,就按照这个思路,结合当前代码,改!

(完整代码稍后贴出)

把所有post(startAnimation)替换成:

long now = SystemClock.uptimeMillis();
				mAnimationLastTime = now;
				mCurrentAnimationTime = now + ANIMATION_FRAME_DURATION;
				mAnimating = true;
				mHandler.removeMessages(MSG_ANIMATE);
				mHandler.removeMessages(MSG_PREPARE_ANIMATE);
				mHandler.sendMessageAtTime(
						mHandler.obtainMessage(MSG_PREPARE_ANIMATE),
						mCurrentAnimationTime);

这段代码基本上是从SlidingDrawer源码copy过来的,MSG_PREPARE_ANIMATE是自己加的

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 36
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 36
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值