インスタントアンドロイドアプリを模したDragToFinishPhotoView実装
5387 ワード
効果のプレビュー
拡大ドラッグ
ドラッグして戻る
拡大してドラッグして戻る
実現構想.
このコントロールは主にPhotoViewに基づいて実現され、拡大、ドラッグ、およびViewPagerとの衝突処理はPhotoViewの処理方法を参考にし、その上でドラッグして戻る機能を追加します.
全体的な実装は主に2つの部分に分けられる:拡大ドラッグ、ドラッグ戻り.どちらの部分も変換行列によって実現され,ImageViewのsetImageMatrix(matrix)である.
もともとPhotoVIewは、拡大縮小および拡大後のドラッグ操作を記録し、適切な変換を行い、updataMatrix()の場合、画像の境界が正常範囲内に表示されないことを保証し、画像の高さがスクリーン高さより小さい場合に下にドラッグできないと判断した.ここでは、元のピクチャ表示範囲の制御ロジックに影響を及ぼさないように、ドラッグダウン距離を記録するマトリクス
mDragDownMatrix
を追加し、最終的にmScaleAndDragMatrix
とともにピクチャのマトリクス変換を決定する.スケーリングではアンドロイドのScaleGestureDetectorを使用して、現在スケーリング操作を行っているかどうかをリスニングし、スケーリングしている場合はドラッグ操作を禁止します.
タッチ操作全体のプロセスには、主に2つの状態がある:スケール
mScaleGestureDetector.isInProgress()
、ドラッグisDragging
.ドラッグ再細分化は、画面を超えたドラッグおよびドロップダウンを拡大してisDraggingDown
の状態に戻る.ドラッグ状態に入る判断はACTION_MOVE中:
float dX = getActiveX(event) - mLastTouchX;
float dY = getActiveY(event) - mLastTouchY;
if (!isDragging) {
isDragging = Math.sqrt(dX * dX + dY * dY) >= mTouchSlop;
if (isDragging) {
mLastTouchX = getActiveX(event);
mLastTouchY = getActiveY(event);
}
}
特定のドラッグ操作の判断に入るには、ドラッグ中に再スケールされる競合を回避します.
if(isDragging && !mScaleGestureDetector.isInProgress() && event.getPointerCount() == 1)
ドラッグ・アンド・ドロップ中に現在ドラッグ・アンド・ドロップしているかどうかを判断します.
RectF rectF = getDisplayRect(getDrawMatrix());
if (!isDraggingDown && rectF != null) {
boolean isScrollVertical = Math.abs(getActiveX(event) - mActionDownX) +
mTouchSlop * 5 < Math.abs(getActiveY(event) - mActionDownY);
boolean isScrollUp = getActiveY(event) < mActionDownY;
boolean dragVerticalOutOfBounds = (Math.round(rectF.top) >= 0 && !isScrollUp) ||
(Math.round(rectF.bottom) <= getViewHeight() && isScrollUp);
if (isScrollVertical && dragVerticalOutOfBounds) {
mActionDownX = getActiveX(event);
mActionDownY = getActiveY(event);
isDraggingDown = true;
}
}
ドラッグ操作変換の具体的な実装:
if (isDraggingDown) {
mDragDownMatrix.reset();
float deltaY = getActiveY(event) - mActionDownY;
mDragDownMatrix.postTranslate(0, deltaY / 3);
updateMatrix();
if (mOnPhotoViewDragListener != null) {
mOnPhotoViewDragListener.onDragOffset(Math.abs(deltaY / 3), getViewHeight() / 6);
}
requestParentDisallowInterceptTouchEvent(true);
} else {
mScaleAndDragMatrix.postTranslate(getActiveX(event) - mLastTouchX, getActiveY(event) - mLastTouchY);
updateMatrix();
mLastTouchX = getActiveX(event);
mLastTouchY = getActiveY(event);
// ViewPager
boolean isScrollHorizontal = Math.abs(getActiveX(event) - mActionDownX) + mTouchSlop > Math.abs(getActiveY(event) - mActionDownY) * 5;
boolean isScrollRight = getActiveX(event) > mActionDownX;
if (rectF != null) {
if (isScrollHorizontal && (isScrollRight && Math.round(rectF.left) >= 0)
|| (!isScrollRight && Math.round(rectF.right) <= getViewWidth())) {
requestParentDisallowInterceptTouchEvent(false);
} else {
requestParentDisallowInterceptTouchEvent(true);
}
}
}
マトリックス変換を適用:
private void updateMatrix() {
RectF rectF = getDisplayRect(getDrawMatrix());
if (rectF != null) {
float deltaX = 0;
float deltaY = 0;
if (rectF.width() < getViewWidth()) {
deltaX = (getViewWidth() - rectF.width()) / 2 - rectF.left;
} else if (rectF.left > 0) {
deltaX = -rectF.left;
} else if (rectF.right < getViewWidth()) {
deltaX = getViewWidth() - rectF.right;
}
if (rectF.height() <= getViewHeight()) {
deltaY = (getViewHeight() - rectF.height()) / 2 - rectF.top;
} else if (rectF.top > 0) {
deltaY = -rectF.top;
} else if (rectF.bottom < getViewHeight()) {
deltaY = getViewHeight() - rectF.bottom;
}
//
mScaleAndDragMatrix.postTranslate(deltaX, deltaY);
Matrix drawMatrix = getDrawMatrix();
drawMatrix.postConcat(mDragDownMatrix);
setImageMatrix(drawMatrix);
}
}
マルチタッチの場合、いずれかのタッチポイントをActiveとして選択し、指を持ち上げる場合、つまりズーム状態からドラッグ状態に入り、持ち上げた指が現在Activeとして扱われているかどうかを判断し、タッチポイントの位置データを更新しないとブレが発生します.
case MotionEvent.ACTION_POINTER_UP: {
int pointerIndex = (event.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
int pointerId = event.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mActivePointerId = event.getPointerId(newPointerIndex);
mActionDownX = mLastTouchX = event.getX(newPointerIndex);
mActionDownY = mLastTouchY = event.getY(newPointerIndex);
} else {
mActionDownX = mLastTouchX = event.getX(mActivePointerIndex);
mActionDownY = mLastTouchY = event.getY(mActivePointerIndex);
}
break;
}
ソース:https://github.com/okhochan/DragToFinishPhotoView