一部のアプリケーション、特にアカウント システムを備えたアプリケーションでは、アルバムから写真を選択してカメラで写真を撮り、取得したアバターを取得し、最終的に選択ボックス内のコンテンツをアバターとして取得します。
では、そのような効果を作成するにはどうすればよいでしょうか?
実際には、これを行う方法がたくさんあります。
1) ImageView を直接継承して、ImageView の OnDraw 関数で円形または正方形のハイライト円を直接描画できます
2) View を直接継承することもできます。それを渡して、まずonDraw関数で絵を描き、次にPathを使って円形または正方形の選択範囲を描き、Region.OP.DIFFERENCEを使って逆にマスクレイヤーを取得します。
ただし、clipPath を使用してこのマスク レイヤーを描画すると、描画された円のエッジがギザギザになります。ギザギザのエッジを削除するより良い方法がまだ見つかりません。友人がいくつか提案を提供してくれるでしょうか。
キーコードは次のとおりです:
@Override protected void onDraw(Canvas canvas) { if(!mIsInit){ initCropRect(getWidth(), getHeight()); mOptBitmap = getProperBitmap(mBitmap, mCropRect.width()); ... mIsInit = true; } canvas.save(); canvas.concat(mDrawMatrix); canvas.drawBitmap(mOptBitmap, 0, 0, null); canvas.restore(); if(mToDrawHighlight){ canvas.save(); mPath.reset(); if (mIsCircle) { float radius = mCropRect.width() / 2 ; mPath.addCircle(mCropRect.left + radius, mCropRect.top + radius, radius, Path.Direction.CW); } else { mPath.addRect(mCropRect, Path.Direction.CW); } canvas.clipPath(mPath, Region.Op.DIFFERENCE); canvas.drawPaint(mDimPaint); canvas.restore(); } }
まず、最初の Ondraw 中に、現在の View とビットマップのサイズを取得できます。このとき、まず CropRect、つまり選択ボックスのサイズと範囲を決定する必要があります。円形または正方形、実際にはそれらはすべて正方形の領域であるため、最初にこの領域を決定する必要があります。これはコード initCropRect で実装されます。
以降の操作は、実際には画像を中央に配置したり、小さな画像を選択した領域のサイズに拡大したりするための操作です。今のところは無視してかまいません。
次に、canvas.drawBitmap を使用して、対応するビットマップを描画します。
2 番目のステップでは、まず円を描画するか四角形を描画するかに応じてパスを定義し、そのパスにグラフィックを追加してから、clipPath と Regional.OP.DIFFERENCE を使用してマスク領域を逆に取得する必要があります。次に、キャンバス上で mDimPaint を使用してマスクをペイントします (mDimPaint は、下にペイントされたビットマップを隠さないようにするための半透明色のブラシです)。
マスクと選択円を描画した後、WeChat や Alipay と同様に、画像の移動とズームも必要になることが多くなります。その場合、次のように、GestureDetector と ScaleGestureDetector を使用して動きとズームを制御できます。
mScaleGestureDetector = new ScaleGestureDetector(context, this);mGestureDetector = new GestureDetector(context, new MyGestureListener());
その中で、MyGestureListener は私たちがカスタマイズした GestureDetector です。それほど多くの Gesture は必要ないので、次のように SimpleOnGestureListener を使用して処理を実装できます:
class MyGestureListener extends SimpleOnGestureListener { @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY){ mDrawMatrix.postTranslate(-distanceX, -distanceY); checkBorderWhenTranslate(); return true; } }
これはモバイル専用であり、ズームする必要があります。次のように、OnScaleGestureListener を実装し、現在のビューにこのインターフェイスを実装させる必要があります:
float scaleFactor = detector.getScaleFactor(); float[] values = new float[9]; mDrawMatrix.getValues(values); float curScale = values[Matrix.MSCALE_X]; if ((curScale < SCALE_MAX && scaleFactor > 1.0f) || (curScale > mInitScale && scaleFactor < 1.0f)) { if (scaleFactor * curScale < mInitScale) { scaleFactor = mInitScale / curScale; } if (scaleFactor * curScale > SCALE_MAX) { scaleFactor = SCALE_MAX / curScale; } mDrawMatrix.postScale(scaleFactor, scaleFactor, detector.getFocusX(), detector.getFocusY()); checkBorderAndCenterWhenScale(); } return true;
@Override public boolean onTouch(View v, MotionEvent event) { ... mScaleGestureDetector.onTouchEvent(event); mGestureDetector.onTouchEvent(event); invalidate(); return true; }