Android自定义双进度条View触摸位置精度问题求助
Hey there! Let's work through this touch precision issue with your dual-progress custom View— I’ve dealt with similar wonky touch recognition problems before, so here’s what I’d check and fix step by step:
Most touch precision bugs stem from incorrect coordinate math. If you’re using MotionEvent.getX()/getY() directly without accounting for padding or the View’s usable area, you’ll get skewed progress calculations.
Adjust your touch coordinates to the View’s internal usable space first:
float touchX = event.getX() - getPaddingLeft(); float usableWidth = getWidth() - getPaddingLeft() - getPaddingRight(); float progressRatio = touchX / usableWidth; // Clamp the ratio to 0-1 to avoid out-of-bounds progress progressRatio = Math.max(0f, Math.min(1f, progressRatio));
This ensures even touches near the View’s edges map to valid progress values.
System touch events can have tiny, unwanted jitters (especially during swipes). Adding a small threshold filters out these noise events and makes your interaction feel smoother:
private float lastTouchX; private int minTouchThreshold; @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); // Convert 2dp to pixels for device-agnostic threshold minTouchThreshold = (int) TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, 2, getResources().getDisplayMetrics() ); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: lastTouchX = event.getX(); return true; // Claim the touch event to receive subsequent updates case MotionEvent.ACTION_MOVE: float deltaX = Math.abs(event.getX() - lastTouchX); if (deltaX >= minTouchThreshold) { updatePlaybackProgress(event.getX()); lastTouchX = event.getX(); } return true; // Handle ACTION_UP/ACTION_CANCEL as needed } return super.onTouchEvent(event); }
Sometimes touches are ignored because they fall outside the View’s intended interactive area (e.g., tapping too far above/below the progress bar). Add a check to ensure the touch is within your progress bar’s bounds:
@Override public boolean onTouchEvent(MotionEvent event) { float touchY = event.getY(); float usableHeight = getHeight() - getPaddingTop() - getPaddingBottom(); // Reject touches outside the vertical bounds of the progress bar if (touchY < getPaddingTop() || touchY > getPaddingTop() + usableHeight) { return super.onTouchEvent(event); } // Proceed with horizontal touch logic... }
If your progress indicator (red dot) isn’t aligning with touch positions, make sure its calculation uses the exact same math as your touch-to-progress conversion:
// Calculate red dot X position float redDotX = getPaddingLeft() + (currentPlaybackProgress / maxProgress) * usableWidth; // Calculate progress from touch (same variables!) float playbackProgress = (touchX / usableWidth) * maxProgress;
Mismatched logic here is the #1 cause of "red dot is in the wrong place" bugs.
In rare cases, hardware acceleration can skew touch coordinate precision for custom-drawn Views. If all else fails, disable it for your View:
<!-- In your layout --> <com.yourpackage.DualProgressView android:id="@+id/dual_progress" android:layout_width="match_parent" android:layout_height="wrap_content" android:hardwareAccelerated="false" />
Or in code:
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
Note: This can hurt drawing performance, so only use it if the above fixes don’t work.
内容的提问来源于stack exchange,提问作者Basti

