android开发教程之使用线程实现视图平滑滚动示例 改
2023-09-27 14:27:19 时间
package com.melonsapp.messenger.ui.popupuser; import android.os.Handler; import android.view.View; import android.view.WindowManager; import android.view.animation.DecelerateInterpolator; import java.util.Timer; /** * Created by lidaqiang on 17/5/3. */ public class SmoothScroll { private Handler mHandler = new Handler(); SmoothScrollThread smoothScrollThread; public static int noData = 0; /** * @param v 需要操控的视图 * @param fromX 起始Y坐标 * @param toX 终止Y坐标 * @param fps 帧率 * @param durtion 动画完成时间(毫秒) * @desc 平滑滚动 */ public SmoothScroll(View v, WindowManager windowManager, WindowManager.LayoutParams windowParams, int fromX, int toX, int fps, long durtion) { this(v, windowManager, windowParams, fromX, toX, noData, noData, 60, durtion); } public SmoothScroll(View v, WindowManager windowManager, WindowManager.LayoutParams windowParams, int fromX, int toX, int fromY, int toY, long durtion) { this(v, windowManager, windowParams, fromX, toX, fromY, toY, 60, durtion); } public SmoothScroll(View v, WindowManager windowManager, WindowManager.LayoutParams windowParams, int fromX, int toX, int fromY, int toY, int fps, long durtion) { smoothScrollThread = new SmoothScrollThread(v, windowManager, windowParams, fromX, toX, fromY, toY, durtion, fps); } public void start() { if (smoothScrollThread == null) { return; } smoothScrollThread.run(); } public void stop() { if (smoothScrollThread == null) { return; } smoothScrollThread.stop(); } /** * @desc 平滑滚动线程,用于递归调用自己来实现某个视图的平滑滚动 */ class SmoothScrollThread implements Runnable { WindowManager mWindowManager; WindowManager.LayoutParams mWindowParams; //需要操控的视图 private View v = null; //原X坐标 private int fromX = noData; //目标X坐标 private int toX = noData; //原Y坐标 private int fromY = noData; //目标Y坐标 private int toY = noData; //动画执行时间(毫秒) private long durtion = 0; //帧率 private int fps = 60; //间隔时间(毫秒),间隔时间 = 1000 / 帧率 private int interval = 0; //启动时间,-1 表示尚未启动 private long startTime = -1; // /减速插值器 private DecelerateInterpolator decelerateInterpolator = null; private int mChangeState = 0; // 0 x,y都不变 1 x变 2 y变 3 x,y都变 /** * @desc 构造方法,做好第一次配置 */ public SmoothScrollThread(View v, WindowManager windowManager, WindowManager.LayoutParams windowParams, int fromX, int toX, int fromY, int toY, long durtion, int fps) { mWindowManager = windowManager; mWindowParams = windowParams; this.v = v; this.fromX = fromX; this.toX = toX; this.fromY = fromY; this.toY = toY; this.durtion = durtion; this.fps = fps; this.interval = 1000 / this.fps; decelerateInterpolator = new DecelerateInterpolator(); mChangeState = 0; if (fromX != toX && fromY == toY) { mChangeState = 1; } else if (fromX == toX && fromY != toY) { mChangeState = 2; } else if (fromX != toX && fromY != toY) { mChangeState = 3; } } @Override public void run() { if (mChangeState == 0) { return; } //先判断是否是第一次启动,是第一次启动就记录下启动的时间戳,该值仅此一次赋值 if (startTime == -1) { startTime = System.currentTimeMillis(); } //得到当前这个瞬间的时间戳 long currentTime = System.currentTimeMillis(); //放大倍数,为了扩大除法计算的浮点精度 int enlargement = 1000; //算出当前这个瞬间运行到整个动画时间的百分之多少 float rate = (currentTime - startTime) * enlargement / durtion; //这个比率不可能在 0 - 1 之间,放大了之后即是 0 - 1000 之间 rate = Math.min(rate, 1000); //将动画的进度通过插值器得出响应的比率,乘以起始与目标坐标得出当前这个瞬间,视图应该滚动的距离。 int currentX = fromX; if (mChangeState == 1 || mChangeState == 3) { int changeDistanceX = (int) ((fromX - toX) * decelerateInterpolator.getInterpolation(rate / enlargement)); currentX = fromX - changeDistanceX; } int currentY = fromY; if (mChangeState == 2 || mChangeState == 3) { int changeDistanceY = (int) ((fromY - toY) * decelerateInterpolator.getInterpolation(rate / enlargement)); currentY = fromY - changeDistanceY; } notifyViewLayout(currentX, currentY); if (currentX != toX || currentY != toY) { mHandler.postDelayed(this, this.interval); } else { return; } } private void notifyViewLayout(int currentX, int currentY) { // v.scrollTo(0, currentY); if (mWindowParams == null || mWindowParams == null || v == null) { return; } if (mChangeState == 1 || mChangeState == 3) { mWindowParams.x = currentX; } if (mChangeState == 2 || mChangeState == 3) { mWindowParams.y = currentY; } if (v.getParent() != null) { mWindowManager.updateViewLayout(v, mWindowParams); } } public void stop() { mHandler.removeCallbacks(this); } } }
相关文章
- JS判断客户端是否是iOS或者Android
- 2021年Android开发者跳槽指南,大牛最佳总结
- android开发教程!4面字节跳动拿到Offer,工作感悟
- 曝iPhone15或换用USB-C接口;Google将下架第三方Android通话录音APP|极客头条
- Android 进程回收之LowMemoryKiller原理篇
- Android之Error: 'L' is not a valid file-based resource name character解决办法
- Android Studio 打包签名教程
- Android APP开发实战——从规划到上线全程详解
- android x86 9.0rc2 安装教程
- Android:控件AutoCompleteTextView 客户端保存搜索历史自动提示
- android 该项目的优化toast优化技巧
- Android:What is ART?
- Android ROM 制作教程
- Android性能调优篇之探索垃圾回收机制
- android:ToolBar详解(手把手教程)
- Android Studio系列教程二--基本设置与运行
- Android Studio系列教程一--下载和安装
- Android 迁移到androidX教程 Kotlin支持androidX
- Android 测试查看日志输出 logcat
- Android Stuido 进行Debug调试
- Android安卓开发 数据库第三方mysql库使用教程
- Android Studio快捷键switch case 轻松转换为if else
- Android onActivityResult优雅的回调
- Android NIO 系列教程(八) --NIO简易聊天室
- Android NIO 系列教程(四) -- Selector
- Android:这是一份Handler消息传递机制 的使用教程
- Android最新源码4.3下载-教程 2013-11
- [Unity3D]Unity+Android交互教程——让手机"动"起来
- 我的Android进阶之旅------>Android MediaPlayer播放网络音频的实例--网络mp3播放器