android 歌词平滑滚动,Android 使用 Scroller 实现平滑滚动

记录使用Scroller实现平滑滚动,效果图如下:

58204b8f22b2

一、自定义View中实现View的平滑滚动

public class ScrollerView extends View {

private Scroller mScroller;

private Paint mPaint;

/**

* 屏幕拖动最小像素

*/

private int mTouchSlop;

/**

* View宽度

*/

private int width;

/**

* View高度

*/

private int height;

/**

* MotionEvent.getX()

*/

private int mEventX;

/**

* MotionEvent.getY()

*/

private int mEventY;

private Bitmap mBitmap;

/**

* View到屏幕左边距离

*/

private int mStartX;

/**

* View到屏幕顶部距离

*/

private int mStartY;

/**

* View默认大小

*/

private static int DEFAULT_SIZE = 200;

public ScrollerView(Context context) {

this(context, null);

}

public ScrollerView(Context context, @Nullable AttributeSet attrs) {

super(context, attrs);

mPaint = new Paint();

mScroller = new Scroller(context);

ViewConfiguration configuration = ViewConfiguration.get(context);

mTouchSlop = ViewConfigurationCompat.getScaledHoverSlop(configuration);

mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

int widthMode = MeasureSpec.getMode(widthMeasureSpec);

int heightMode = MeasureSpec.getMode(heightMeasureSpec);

if (widthMode == MeasureSpec.EXACTLY) {

width = MeasureSpec.getSize(widthMeasureSpec);

} else {

if (heightMode == MeasureSpec.EXACTLY) {

width = MeasureSpec.getSize(heightMeasureSpec);

} else {

width = DEFAULT_SIZE;

}

}

if (heightMode == MeasureSpec.EXACTLY) {

height = MeasureSpec.getSize(heightMeasureSpec);

} else {

height = width;

}

setMeasuredDimension(width, height);

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

if (null != mBitmap) {

Rect src = new Rect(0, 0, mBitmap.getWidth(), mBitmap.getHeight());

Rect dst = new Rect(0, 0, width, height);

canvas.drawBitmap(mBitmap, src, dst, mPaint);

} else {

Log.e("zzy", "Bitmap is null");

}

}

@Override

public boolean onTouchEvent(MotionEvent event) {

int action = event.getAction();

switch (action) {

case MotionEvent.ACTION_DOWN:

mEventX = (int) event.getX();

mEventY = (int) event.getY();

break;

case MotionEvent.ACTION_MOVE:

mStartX = (int) event.getRawX() - mEventX;

mStartY = (int) event.getRawY() - mEventY;

layout(mStartX,mStartY,mStartX+width,mStartY+height);

break;

case MotionEvent.ACTION_UP:

startScroller();

break;

}

return true;

}

@Override

public void computeScroll() {

if (mScroller.computeScrollOffset()){

int l = mScroller.getCurrX();

layout(l,mStartY,l+width,mStartY+height);

invalidate();

}

}

/**

* 开始Scroller动画

*/

private void startScroller(){

mScroller.forceFinished(true);

mScroller.startScroll(mStartX, mStartY,-mStartX,0);

int screenWidth = getScreenWidth();

// Scroller动画默认250ms,超过屏幕一半时设置为500ms

if (mStartX > screenWidth / 2){

mScroller.extendDuration(500);

}

invalidate();

}

private int getScreenWidth(){

return getResources().getDisplayMetrics().widthPixels;

}

}

Scroller其实是个辅助类,本身并不能完成动画的执行。而是帮我们计算随着时间的流逝,动画应该执行的位置值,我们需要获得当前时间的位置,然后调用View位置移动方法,将View移动到该位置,完成动画。

所以,在自定义View中。我们需要调用invalidate()触发View的重绘,并覆写重绘会执行的方法computeScroll()。

在computeScroll()方法中调用Scroller的computeScrollOffset()计算当前时间动画应该移动的位置,返回值是动画是否在执行。

通过mScroller.getCurrX()和mScroller.getCurrY()获得当前时间的位置。手动调用View位置移动的方法将View的位置移动到当前时间的位置,实现View的滚动。

然后再次调用invalidate()触发刷新。直到computeScrollOffset()返回false,动画执行完成,滚动完成。

二、直接使用Scroller实现View的平滑滚动

我们知道,Scroller会帮我们计算当前时间,插值器返回的值。

而如果直接使用Scroller实现平滑滚动的话,也需要借助带时间的监听器。

这里借助ValueAnimator来实现Scroller平滑滚动

private Scroller mScroller;

private ImageView mImage;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

mImage = findViewById(R.id.image);

mScroller =new Scroller(this);

}

public void btnStart(View view){

start();

}

private void start(){

mScroller.forceFinished(false);

mScroller.extendDuration(500);

mScroller.startScroll(0,0,400,400);

ValueAnimator valueAnimator = ValueAnimator.ofFloat(0,1);

valueAnimator.setDuration(500);

valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

if (mScroller.computeScrollOffset()){

ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mImage.getLayoutParams();

params.leftMargin = mScroller.getCurrX();

params.topMargin = mScroller.getCurrY();

mImage.setLayoutParams(params);

}

}

});

valueAnimator.start();

}

在ValueAnimator的addUpdateListener中刷新Scroller当前值。并移动位置。效果如下:

58204b8f22b2

PS:关于我

58204b8f22b2

本人是一个拥有6年开发经验的帅气Android攻城狮,记得看完点赞,养成习惯,微信搜一搜「 程序猿养成中心 」关注这个喜欢写干货的程序员。

另外耗时两年整理收集的Android一线大厂面试完整考点PDF出炉,资料【完整版】已更新在我的【Github】,有面试需要的朋友们可以去参考参考,如果对你有帮助,可以点个Star哦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值