質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

Q&A

0回答

404閲覧

customViewのスケーリング処理がうまくいかない。

shikasama

総合スコア163

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

0グッド

0クリップ

投稿2017/12/27 01:43

###前提・実現したいこと
表示した画像をピンチで拡大縮小できるようにcustomViewを作成しています。
OnScaleGestureListenerでピンチ操作を取得しようとしています。

以下のデバッグログのようにonScale()の呼び出しが一度のみですぐonScaleEnd()が呼ばれているためか、
スケーリングがうまくいきません。

kotlin

1D/CustomScaleImageView: onScaleBegin() 2D/CustomScaleImageView: onScale() 3D/CustomScaleImageView: updateMatrix() mCurrentScale = 1.6776869 mCurrentX = 103.1402 mCurrentY = 77.35513 4D/CustomScaleImageView: onScaleEnd()

どのようにしたらonScale()が連続で呼ばれ、スケーリング処理が正常に行えるでしょうか?

###該当のソースコード

以下はImageViewを継承した自作クラスCustomScaleImageViewのイベントリスナ部分とanimator部分です。

kotlin

1override fun onTouchEvent(event: MotionEvent?): Boolean { 2 scaleGestureDetector.onTouchEvent(event) 3 if(!scaleGestureDetector.isInProgress) { 4 gestureDetector.onTouchEvent(event) 5 } 6 7 return true 8} 9 10private inner class GestureListener : GestureDetector.SimpleOnGestureListener() { 11 override fun onScroll(e1: MotionEvent?, e2: MotionEvent?, distanceX: Float, distanceY: Float): Boolean { 12 if(scaling) { 13 return false 14 } 15 // 前の座標 16 val previousCurrentX = currentX 17 val previousCurrentY = currentY 18 19 currentX = getAdjustedPos(currentX - distanceX, currentScale, imageWidth, width, horizontalFitType) 20 currentY = getAdjustedPos(currentY - distanceY, currentScale, imageHeight, height, verticalFitType) 21 22 Log.d(TAG, "onScroll() mCurrentX = $currentX mCurrentY = $currentY") 23 24 if(previousCurrentX != currentX || previousCurrentY != currentY) { 25 // 変更あり 26 updateMatrix() 27 } 28 return true 29 } 30 31 override fun onDoubleTap(e: MotionEvent?): Boolean { 32 Log.d(TAG, "onDoubleTap()") 33 34 var targetScale = 0.0F 35 if(currentScale == fitScale) { 36 // オリジナル画像のサイズ 37 targetScale = 1.0F 38 } else { 39 targetScale = fitScale 40 } 41 if(e != null) { 42 animator.startScaleAnimation(targetScale, e.x, e.y) 43 } 44 45 return true 46 } 47 48} 49 50private inner class ScaleGestureListener : OnScaleGestureListener { 51 52 // 前のフォーカスの座標 53 private var previousFocusX = 0.0F 54 private var previousFocusY = 0.0F 55 56 override fun onScaleBegin(p0: ScaleGestureDetector?): Boolean { 57 Log.d(TAG, "onScaleBegin()") 58 59 scaling = true 60 61 // 最初のフォーカス座標を記憶 62 p0?.let { 63 previousFocusX = p0.focusX 64 previousFocusY = p0.focusY 65 } 66 67 return true 68 } 69 70 override fun onScale(p0: ScaleGestureDetector?): Boolean { 71 Log.d(TAG, "onScale()") 72 73 // 前回のイベントでの2点間の距離との比率 74 var scaleFactor : Float 75 p0?.let { 76 scaleFactor = when { 77 (currentScale >= maxScale) -> 1F + (p0.scaleFactor - 1F) * maxScale / currentScale * SCALE_RESTRICT_FACTOR 78 (currentScale <= minScale) -> 1F + (p0.scaleFactor - 1F) * currentScale / minScale * SCALE_RESTRICT_FACTOR 79 else -> p0.scaleFactor 80 } 81 82 currentScale *= scaleFactor 83 84 val focusX = p0.focusX 85 val focusY = p0.focusY 86 87 currentX = focusX + (currentX - this.previousFocusX) * scaleFactor 88 currentY = focusY + (currentY - this.previousFocusY) * scaleFactor 89 updateMatrix() 90 91 previousFocusX = focusX 92 previousFocusY = focusY 93 } 94 95 return true 96 } 97 98 override fun onScaleEnd(p0: ScaleGestureDetector?) { 99 Log.d(TAG, "onScaleEnd()") 100 101 val targetScale = ensureRange(currentScale, minScale, maxScale) 102 animator.startScaleAnimation(targetScale, previousFocusX, previousFocusY) 103 } 104} 105 106private inner class TransformAnimator { 107 // アニメーション開始位置 108 private var startScale = 0.0F 109 private var startX = 0.0F 110 private var startY = 0.0F 111 112 // アニメーション目標位置 113 private var targetScale = 0.0F 114 private var targetX = 0.0F 115 private var targetY = 0.0F 116 117 // 開始と目標の差 118 private var diffScale = 0.0F 119 private var diffX = 0.0F 120 private var diffY = 0.0F 121 122 // アニメーション実行時間 123 private var duration = ANIMATION_DURATION 124 // アニメーション開始時間 125 private var startTime : Long = 0 126 // アニメーション実行状態 127 private var isAnimating = false 128 129 internal fun startAnimation(targetScale: Float, targetX : Float, targetY : Float) { 130 if(isAnimating) { 131 // すでにアニメーションが実行中の場合はなにもしません 132 return 133 } 134 135 if(targetScale == currentScale && targetX == currentX && targetY == currentY) { 136 // 現在の位置とスケーリング後の位置が同じ場合はなにもしません 137 return 138 } 139 140 // アニメーションの開始位置を設定 141 startScale = currentScale 142 startX = currentX 143 startY = currentY 144 145 // アニメーションの目標位置を設定 146 this.targetScale = targetScale 147 this.targetX = targetX 148 this.targetY = targetY 149 150 // 開始位置と目標位置の差分を取得 151 diffScale = targetScale - startScale 152 diffX = targetX - startX 153 diffY = targetY - startY 154 155 // 現在時刻(ミリ秒単位)を開始時刻に設定 156 startTime = System.currentTimeMillis() 157 158 // アニメーション実行状態 159 isAnimating = true 160 161 // 再描画する(onDrawを呼ぶ) 162 invalidate() 163 164 Log.d(TAG, "TransformAnimator.startAnimation() invalidate()") 165 } 166 167 internal fun startScaleAnimation(targetScale : Float, pivotX : Float, pivotY : Float) { 168 // スケーリング後の位置を計算 169 val diffScaleFactor = targetScale / currentScale - 1.0F 170 var targetX = currentX + (currentX - pivotX) * diffScaleFactor 171 var targetY = currentY + (currentY - pivotY) * diffScaleFactor 172 // 調整後の位置を取得 173 targetX = getAdjustedPos(targetX, targetScale, imageWidth, width, horizontalFitType) 174 targetY = getAdjustedPos(targetY, targetScale, imageHeight, height, verticalFitType) 175 176 // アニメーションを開始する 177 startAnimation(targetScale, targetX, targetY) 178 } 179 180 internal fun animate() { 181 if(!isAnimating) { 182 // アニメーション実行状態でない場合 183 return 184 } 185 186 val diffTime = System.currentTimeMillis() - startTime 187 if(diffTime >= duration) { 188 // アニメーション実行時間を過ぎた場合はアニメーションを終了させる 189 190 isAnimating = false 191 currentScale = targetScale 192 currentX = targetX 193 currentY = targetY 194 } else { 195 // アニメーション実行時間内の場合 196 197 // 進捗度 198 val progress = diffTime.toFloat() / duration 199 // 進捗状況に合わせて移動位置を計算します 200 currentScale = startScale + (diffScale * progress) 201 currentX = startX + (diffX * progress) 202 currentY = startY + (diffY * progress) 203 } 204 205 Log.d(TAG, "TransformAnimator.animate() mCurrentScale = $currentScale mCurrentX = $currentX mCurrentY = $currentY") 206 // 移動位置を反映させる 207 updateMatrix() 208 // 再描画する 209 invalidate() 210 } 211} 212 213private fun updateMatrix() { 214 // 初期イメージのcurrentScale倍にする 215 _matrix.setScale(currentScale, currentScale) 216 // 移動する 217 _matrix.postTranslate(currentX, currentY) 218 // imegeViewにmatrixを設定する 219 imageMatrix = _matrix 220 Log.d(TAG, "updateMatrix() mCurrentScale = $currentScale mCurrentX = $currentX mCurrentY = $currentY") 221}

###補足情報(言語/FW/ツール等のバージョンなど)
android studio 3.0.1
kotlin 1.2.10

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問