首页 > 解决方案 > 如何从 Android 中的缩放视图中获取位图

问题描述

我有一个名为 MyView 的自定义视图,并正确启用了缩放!用手指缩放视图后,我想得到这个结果视图的位图。为此,我使用下面的 getBitmap () 方法,但它不起作用!它仅在视图未缩放时才有效(scaleFactor = 1.0f)。我用getWidth()/ scaleFactor,getHeight()/ scaleFactor替换了getWidth(),getHeight(),但它也不起作用!

//These two methods are inside the MyView class
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    canvas.save();
    canvas.scale(scaleFactor, scaleFactor);

    canvas.drawPath(path, paint);

    canvas.restore();
}

public Bitmap getBitmap(){
    Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    draw(canvas);

    return bitmap;
}

那么如何从缩放视图中获取位图(scaleFactor!= 1.0f)?

更新:包括完整的项目:

//myview
public class MyView extends View {
    private Path path;
    private Paint paint;
    private ScaleGestureDetector scaleDetector;
    private float scaleFactor = 1.0f;

    public MyView(Context context) {
        super(context);
        init(context);
    }

    public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context){
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(Color.GREEN);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeJoin(Paint.Join.ROUND);
        paint.setStrokeCap(Paint.Cap.ROUND);
        path = new Path();

        //inside window
        path.addRect(300, 300, 600, 600, Path.Direction.CW);

        //outside window
        path.addRect(800, 800, 1000, 1000, Path.Direction.CW);

        //outside window
        path.addRect(1000, 1000, 1200, 1200, Path.Direction.CW);
        scaleDetector = new ScaleGestureDetector(context, new ScaleListener());
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.save();
        canvas.scale(scaleFactor, scaleFactor);
        canvas.drawPath(path, paint);
        canvas.restore();
    }

    public Bitmap getBitmap(){
        Bitmap bitmap =
                Bitmap.createBitmap(
                        Math.round(getWidth()*scaleFactor),
                        Math.round(getHeight()*scaleFactor),
                        Bitmap.Config.ARGB_8888);

        Canvas canvas = new Canvas(bitmap);
        draw(canvas);
        return bitmap;
    }

    private class ScaleListener
            extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            scaleFactor *= detector.getScaleFactor();
            // Don't let the object get too small or too large.
            scaleFactor = Math.max(0.1f, Math.min(scaleFactor, 5f));
            invalidate();
            return true;
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        // Let the ScaleGestureDetector inspect all events.
        scaleDetector.onTouchEvent(ev);
        return true;
    }
}

主要活动

public class MainActivity extends AppCompatActivity {

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

        MyView myView = findViewById(R.id.my_view);
        Button button = findViewById(R.id.button);

        button.setOnClickListener(view -> {
            Bitmap bitmap = myView.getBitmap(); //add breakpoint in this line
            int width = bitmap.getWidth();
            int height = bitmap.getHeight();
        });
    }
}

xml

<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.abdo.scaledviewtobitmapquestion.MyView
        android:id="@+id/my_view"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:text="Hello World!"
        app:layout_constraintBottom_toTopOf="@id/button"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Get Bitmap"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

在这个项目中,我创建了三个矩形,一个在窗口内,两个在窗口外,在运行这个项目之前,我在“Bitmap bitmap = myView.getBitmap ();”这一行中添加了一个断点 (主要活动)当应用程序打开时,我缩小窗口,直到所有 3 个矩形出现在窗口中,然后单击按钮查看调试器输出的位图。

奇怪!位图不包括三个矩形,它只是在缩放之前捕获原始窗口中可见的矩形(scaleFactor = 1)。

标签: androidbitmapscale

解决方案


2部分的答案。

  1. scaleFactor > 1.0f 是放大, scaleFactor < 1.0f 是缩小

所以计算应该是getWidth() * scaleFactor

例如 0.5f 的 scaleFactor 是一半大小

  1. 您需要的大小是 aint并且 scaleFactor 是 a float,因此您无法获得所需位图的确切宽度,但应该可以使用四舍五入Math.round()

推荐阅读