android ListView 可缩放,支持左右上下手势
public class ZoomListView extends ListView implements SwipeListener { public static enum Action { LeftToRight, RightToLeft, TopToBottom, BottomToTop, None } private List<SwipeListener> actionListeners = new ArrayList<SwipeListener>(); private boolean SwipeFlag = false; private static final int HORIZONTAL_MIN_DISTANCE = 30; // The minimum private static final int VERTICAL_MIN_DISTANCE = 80; // The minimum distance private float downX, downY, upX, upY; // Coordinates private static final int INVALID_POINTER_ID = -1; private int mActivePointerId = INVALID_POINTER_ID; private ScaleGestureDetector mScaleDetector; private float mScaleFactor = 1.f; private float maxWidth = 0.0f; private float maxHeight = 0.0f; private float mLastTouchX; private float mLastTouchY; private float mPosX; private float mPosY; private float width; private float height; public ZoomListView(Context context) { super(context); mScaleDetector = new ScaleGestureDetector(getContext(), new ScaleListener()); } public ZoomListView(Context context, AttributeSet attrs) { super(context, attrs); mScaleDetector = new ScaleGestureDetector(getContext(), new ScaleListener()); } public ZoomListView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mScaleDetector = new ScaleGestureDetector(getContext(), new ScaleListener()); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { width = MeasureSpec.getSize(widthMeasureSpec); height = MeasureSpec.getSize(heightMeasureSpec); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override public boolean onTouchEvent(@NonNull MotionEvent ev) { super.onTouchEvent(ev); final int action = ev.getAction(); mScaleDetector.onTouchEvent(ev); switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_DOWN: { final float x = ev.getX(); final float y = ev.getY(); mLastTouchX = x; mLastTouchY = y; mActivePointerId = ev.getPointerId(0); downX = ev.getX(); downY = ev.getY(); SwipeFlag = true; break; } case MotionEvent.ACTION_MOVE: { final int pointerIndex = ev.findPointerIndex(mActivePointerId); final float x = ev.getX(pointerIndex); final float y = ev.getY(pointerIndex); final float dx = x - mLastTouchX; final float dy = y - mLastTouchY; float leftMargin = Math.abs(mPosX) / mScaleFactor; float rightMargin = this.getMeasuredWidth() - Math.abs(mPosX) / mScaleFactor; rightMargin -= this.getResources().getDisplayMetrics().widthPixels / mScaleFactor ; mPosX += dx; mPosY += dy; if (mPosX > 0.0f) mPosX = 0.0f; else if (mPosX < maxWidth) mPosX = maxWidth; if (mPosY > 0.0f) mPosY = 0.0f; else if (mPosY < maxHeight) mPosY = maxHeight; mLastTouchX = x; mLastTouchY = y; invalidate(); upX = ev.getX(); upY = ev.getY(); float deltaX = downX - upX; float deltaY = downY - upY; // horizontal swipe detection if (Math.abs(deltaX) > HORIZONTAL_MIN_DISTANCE) { // left or right if (deltaX < 0 && SwipeFlag && leftMargin < 10) { SwipeFlag = false; OnAction(Action.LeftToRight); break; } if (deltaX > 0 && SwipeFlag && rightMargin < 10) { SwipeFlag = false; OnAction(Action.RightToLeft); break; } } else { // vertical swipe detection if (Math.abs(deltaY) > VERTICAL_MIN_DISTANCE) { // top or down if (deltaY < 0 && SwipeFlag) { SwipeFlag = false; OnAction(Action.TopToBottom); break; } if (deltaY > 0 && SwipeFlag) { SwipeFlag = false; OnAction(Action.BottomToTop); break; } } } break; } case MotionEvent.ACTION_UP: { mActivePointerId = INVALID_POINTER_ID; break; } case MotionEvent.ACTION_CANCEL: { mActivePointerId = INVALID_POINTER_ID; break; } case MotionEvent.ACTION_POINTER_UP: { final int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; final int pointerId = ev.getPointerId(pointerIndex); if (pointerId == mActivePointerId) { final int newPointerIndex = pointerIndex == 0 ? 1 : 0; mLastTouchX = ev.getX(newPointerIndex); mLastTouchY = ev.getY(newPointerIndex); mActivePointerId = ev.getPointerId(newPointerIndex); } break; } } return true; } @Override public void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.save(Canvas.MATRIX_SAVE_FLAG); canvas.translate(mPosX, mPosY); canvas.scale(mScaleFactor, mScaleFactor); canvas.restore(); } @Override protected void dispatchDraw(@NonNull Canvas canvas) { canvas.save(Canvas.MATRIX_SAVE_FLAG); if (mScaleFactor == 1.0f) { mPosX = 0.0f; mPosY = 0.0f; } canvas.translate(mPosX, mPosY); canvas.scale(mScaleFactor, mScaleFactor); super.dispatchDraw(canvas); canvas.restore(); invalidate(); } private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { @Override public boolean onScale(ScaleGestureDetector detector) { mScaleFactor *= detector.getScaleFactor(); mScaleFactor = Math.max(1.0f, Math.min(mScaleFactor, 3.0f)); maxWidth = width - (width * mScaleFactor); maxHeight = height - (height * mScaleFactor); invalidate(); return true; } } @Override public void OnAction(Action action) { for(SwipeListener listener : actionListeners){ listener.OnAction(action); } } public void addActionListener(SwipeListener listener) { actionListeners.add(listener); } }
public interface SwipeListener extends EventListener { public void OnAction(Action action); }
如果想ListView中显示图片且自适应,需要设置 android:adjustViewBounds="true"
桂棹兮兰桨,击空明兮溯流光。
分类:
Android 开发
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
2017-03-30 asp.net Checkbox 绑定自定义属性