2

これが私のシナリオです:

onDraw()メソッドでキャンバスを計算して取得できるビューを持つレイアウトが1つあります。ここで、onTouchEvent()などのイベントで、キャンバスの一部をクリップして、この部分を別のレイアウトの別のビューに表示したいと思います。

私はコードスニペットが同様のことをしているのを見つけましたが、それらはAndroid API、特にjava.awt.Graphics2Dのようなコアコンポーネントでサポートされていないjava.awtパッケージに基づいています

AndroidのGraphics2Dの代わりにcanvasを使用して同様のアルゴリズムに従い、コンテンツを別のキャンバスに描画したいと思います。これをどのように達成しますか?

基本的に、java.awtの次のコードで実行したのと同じ結果を達成したいと思います。

protected void paint(Graphics2D g2) {
Ellipse2D ellipse = //create ellipse which is to be displayed in another surface
g2.fill(ellipse);  //how to achieve the same result in Android?
g2.draw(ellipse);  //how to achieve the same result in Android?
g2.clip(ellipse);  //how to achieve the same result in Android?
....
... 
//note: Afaik, in Android, the code like Drawable.draw(canvas, ....),
//will achieve result in the opposite way where the Drawable would be drawn into
//the Canvas whereas G2.fill(ellipse) would fill the ellipse with the G2's content
}
4

1 に答える 1

0

必要なものを正しく理解していれば、次のようにコードを試すことができます。

アクティビティのxmlレイアウトファイルは次のようになります。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.example.test.SourceImageView
        android:id="@+id/srcImage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:src="@drawable/landscape" /> <!-- landscape.png is the picture on resources -->

    <ImageView
        android:id="@+id/dstImage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/srcImage"
        android:layout_centerHorizontal="true" />

</RelativeLayout>

アクティビティのソースコード:

public class MainActivity extends Activity implements SourceImageView.OnCropListener {

    private SourceImageView srcImageView;
    private ImageView       dstImageView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        srcImageView = (SourceImageView) findViewById(R.id.srcImage);
        dstImageView = (ImageView) findViewById(R.id.dstImage);

        srcImageView.setOnCropListener(this);
    }

    @Override
    public void onCrop(Bitmap bitmap) {
        dstImageView.setImageBitmap(Bitmap.createScaledBitmap(bitmap, 50, 50, true));
    }
}

SourceImageViewと呼ばれるカスタムビュー:

public class SourceImageView extends ImageView implements OnTouchListener {

    private float           x;
    private float           y;
    private Paint           paint;
    private Bitmap          bitmap;
    private OnCropListener  cropListener;

    public SourceImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setOnTouchListener(this);
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
        bitmap = ((BitmapDrawable) getDrawable()).getBitmap();
    }

    @Override
    protected void onDetachedFromWindow() {
        bitmap.recycle();
        super.onDetachedFromWindow();
    }

    @Override
    public boolean onTouch(View v, MotionEvent event) {

        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            x = event.getX();
            y = event.getY();

            if (cropListener != null) {
                if (x + 20 > bitmap.getWidth() || y + 20 > bitmap.getHeight() || (y - 20) < 0 || (x - 20) < 0) {
                    return true;
                }
                Bitmap b = Bitmap.createBitmap(bitmap, (int) x - 20, (int) y - 20, 40, 40);
                Bitmap overlay = Bitmap.createBitmap(40, 40, Bitmap.Config.ARGB_8888);
                Canvas c = new Canvas(overlay);

                c.clipRect(0, 0, b.getWidth(), b.getHeight());

                Path path = new Path();
                path.addCircle(20, 20, 20, Path.Direction.CW);
                c.clipPath(path, Op.INTERSECT);
                c.drawBitmap(b, 0, 0, null);

                cropListener.onCrop(overlay);

                Bitmap overlay2 = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
                Canvas canvas = new Canvas(overlay2);
                canvas.drawBitmap(bitmap, 0, 0, null);
                canvas.drawCircle(x, y, 20, paint);
                bitmap = overlay2;
                setImageBitmap(bitmap);
            }
        }
        return true;
    }

    public void setOnCropListener(OnCropListener cropListener) {
        this.cropListener = cropListener;
    }

    static interface OnCropListener {
        public void onCrop(Bitmap bitmap);
    }

}

ビットマップを扱うときは注意してください。特に古いバージョンのAndroidを使用している場合は、メモリリークの原因となる可能性があります。このコードのリークはチェックしていません。おそらくこれは改善できるでしょう(リファクタリング、最適化)。

これがあなたの望むものでない場合、私はあなたにアイデアを与え、あなたを正しい方向に向けるのに役立つことを願っています。

==編集==

はっきりしないかもしれないので、例として、画像のトリミングされた部分が半径20ピクセルの円の領域であると仮定したと言わなければなりません。

于 2012-11-01T19:43:07.580 に答える