2

这是我的场景:

我有一个布局,其中我可以在其 onDraw() 方法上校准和获取画布。现在,对于一个事件,比如 onTouchEvent(),我想剪辑画布的一部分并将这部分显示到另一个布局的另一个视图中。

我发现代码片段做类似的事情,但它们基于 Android API 不支持的 java.awt 包,尤其是像 java.awt.Graphics2D 这样的核心组件

我想遵循类似的算法,使用画布而不是 Android 中的 Graphics2D 将其内容绘制到另一个画布中。我们如何实现这一目标?

基本上,我想获得与 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

如果我正确理解了您的需求,您可以尝试如下代码。

这是 Activity 的 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 px 的圆的区域。

于 2012-11-01T19:43:07.580 回答