Android: коснитесь, чтобы стереть части изображения на переднем плане, чтобы открыть фоновое изображение.

Так что я боролся с этим большую часть дня. Предположим, у меня есть собственный ImageView, который я хочу наложить на фоновый вид (оба в RelativeLayout), который при прикосновении стирает части исходного растрового изображения представления, как инструмент стирания в MS Paint, открывая вид под ним. Я проверил практически все потоки (например, этот), и они предлагают использовать режим PorterDuff SRC в объекте Paint, а также создать Canvas из теневой копии ARGB_8888 исходного растрового изображения для применения маскирования.

Кроме того, я не могу заранее установить источник наложения, так как мне нужно загрузить его по сети, чтобы тип масштабирования ImageView позаботился о масштабировании за меня.

Каждый раз, когда я переопределяю onDraw, когда я применяю стирание к растровому изображению IV, он открывает черный фон вместо представления под ним, даже если я устанавливаю фон прозрачным. Итак, я нахожусь на последнем этапе, что нужно сделать, чтобы открыть фоновый вид.

Вот что у меня есть до сих пор:

конструктор представления:

    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));  
    paint.setColor(Color.TRANSPARENT);
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeJoin(Paint.Join.ROUND);
    paint.setStrokeWidth(STROKE_WIDTH);
    paint.setAntiAlias(true);

переопределил setImageBitmap, чтобы установить мой холст из моего перенастроенного исходного растрового изображения:

public void setImageBitmap(Bitmap bitmap){
    super.setImageBitmap(bitmap);
    Drawable bd = getDrawable();
    if(bd == null){
        return;
    }

    Bitmap fullSizeBitmap = ((BitmapDrawable) bd).getBitmap();
    overlay = fullSizeBitmap.copy(Config.ARGB_8888, true);
    c2 = new Canvas(overlay);
}

Метод onDraw:

protected void onDraw(Canvas canvas) {
    /*
     * Override paint call by re-drawing the view's Bitmap first, then overlaying our path on top of it
     */
    Drawable bd = getDrawable();
    if(bd == null){
        return;
    }
    Bitmap fullSizeBitmap = ((BitmapDrawable) bd).getBitmap();
    if(fullSizeBitmap != null && c2 != null){
        canvas.drawColor(Color.TRANSPARENT);
        c2.drawBitmap(fullSizeBitmap, 0, 0, null);
        c2.drawPath(path, paint);
        canvas.drawBitmap(overlay, 0, 0, null);
    }
}

person Diego Tori    schedule 22.11.2011    source источник
comment
Это, вероятно, не лучший способ сделать это, но это идея. В ImageView, который вы хотите сделать прозрачным, вы можете просто установить прозрачное изображение .png на фон вместо рисования холста. Это означает, что вы должны сделать крошечное изображение .png и упаковать его в свое приложение.   -  person Reed    schedule 22.11.2011
comment
Что ж, у меня уже есть такое изображение в моих ресурсах, но я не знаю, в чем его преимущество перед а) установкой фона IV на ноль или б) установкой его цвета и холста на прозрачность? Я попробую.   -  person Diego Tori    schedule 22.11.2011
comment
Нет, даже установка прозрачного PNG в качестве фона не имела значения :-(   -  person Diego Tori    schedule 22.11.2011
comment
Вы можете использовать addView, чтобы добавить изображение, которое позже будет удалено, а затем вызвать removeView при касании. Я предполагаю, что это может работать или не работать в зависимости от того, что вы на самом деле хотите, чтобы ваше приложение делало. И я не вижу никаких ошибок в вашем коде, но я предполагаю, что есть какая-то глупость, которая разрушает всю операцию. Обычно мои необъяснимые ошибки происходят из-за моей невнимательности. Я могу ошибаться, но это может быть что-то очень простое.   -  person Reed    schedule 22.11.2011
comment
Что, если вы полностью подделаете эффект? Создайте представление, содержащее как верхнее изображение (установленное как видимое), так и компоненты нижнего представления (установленное как невидимое). Когда щелкнут верхнее изображение, сделайте его невидимым и сделайте видимыми другие компоненты представления.   -  person Adil B    schedule 22.11.2011
comment
Это не то, что я ищу. Мне нужно иметь возможность делать прозрачные части ImageView в зависимости от того, куда пользователь перетаскивает палец.   -  person Diego Tori    schedule 22.11.2011


Ответы (2)


Я знаю, что это действительно старый вопрос, но вот что я сделал, чтобы решить аналогичную проблему, которая у меня была. Может быть, это поможет кому-то в будущем.

Начиная с уровня API 11 и выше, вы должны указать этот фрагмент кода для своего ImageView, чтобы открыть изображение сзади, а не черную область.

if (Build.VERSION.SDK_INT >= 11) {
    imageview.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

Это помогло мне успешно отобразить заднее изображение.

person the-ginger-geek    schedule 26.02.2013
comment
а как же апи ‹ 11 - person Kapil Vats; 04.03.2013
comment
Это не понадобится для более старых уровней API. - person the-ginger-geek; 04.03.2013
comment
но тогда почему я получаю черную линию для более старых API, но мой код хорошо работает на Android 4.1, вот мой вопрос stackoverflow.com/questions/15200187/ - person Kapil Vats; 04.03.2013
comment
Этот фрагмент кода отключает аппаратное ускорение для определенного представления (Android API 11+). Посмотрите на это (stackoverflow.com/questions/ 6792115/) и посмотрите, поможет ли это. Если нет, вам, вероятно, придется отключить аппаратное ускорение в манифесте, еще не совсем разобравшись с этим. - person the-ginger-geek; 04.03.2013
comment
Вы также можете ознакомиться с документацией для разработчиков для получения дополнительной информации developer.android .com/guide/topics/graphics/hardware-accel.html - person the-ginger-geek; 04.03.2013
comment
спасибо, Нил, но я отключаю аппаратное ускорение только в mainfest, даже если оно не работает - person Kapil Vats; 04.03.2013

Можете ли вы попробовать это решение, оно поможет вам стереть изображения в Android при касании. Или загрузите демонстрационный пример

public class MainActivity extends Activity {

    Bitmap bp;
    Canvas bitmapCanvas;
    DrawView drawImg;
    LinearLayout ln1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        ln1 = (LinearLayout) findViewById(R.id.ln1);
        drawImg = new DrawView(this);
        ln1.addView(drawImg);

    }



    public class DrawView extends View implements View.OnTouchListener {

        private int x = 0;
        private int y = 0;

        Bitmap bitmap;
        Path circlePath;
        Paint circlePaint;

        private final Paint paint = new Paint();
        private final Paint eraserPaint = new Paint();


        public DrawView(Context context){
            super(context);
            setFocusable(true);
            setFocusableInTouchMode(true);
            this.setOnTouchListener(this);

            // Set background
            this.setBackgroundColor(Color.CYAN);
            bp = BitmapFactory.decodeResource(getResources(), R.drawable.bg);

            // Set bitmap
            bitmap = Bitmap.createBitmap(320, 480, Bitmap.Config.ARGB_8888);
            bitmapCanvas = new Canvas();
            bitmapCanvas.setBitmap(bitmap);
            bitmapCanvas.drawColor(Color.TRANSPARENT);
            bitmapCanvas.drawBitmap(bp, 0, 0, null);

            circlePath = new Path();
            circlePaint = new Paint();
            circlePaint.setAntiAlias(true);
            circlePaint.setColor(Color.BLUE);
            circlePaint.setStyle(Paint.Style.STROKE);
            circlePaint.setStrokeJoin(Paint.Join.MITER);
            circlePaint.setStrokeWidth(4f);

            // Set eraser paint properties
            eraserPaint.setAlpha(0);
            eraserPaint.setStrokeJoin(Paint.Join.ROUND);
            eraserPaint.setStrokeCap(Paint.Cap.ROUND);
            eraserPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
            eraserPaint.setAntiAlias(true);

        }

        @Override
        public void onDraw(Canvas canvas) {

            canvas.drawBitmap(bitmap, 0, 0, paint);
            bitmapCanvas.drawCircle(x, y, 30, eraserPaint);

            canvas.drawPath(circlePath, circlePaint);
        }

        public boolean onTouch(View view, MotionEvent event) {
            x = (int) event.getX();
            y = (int) event.getY();

            bitmapCanvas.drawCircle(x, y, 30, eraserPaint);

            circlePath.reset();
            circlePath.addCircle(x, y, 30, Path.Direction.CW);

            int ac=event.getAction();
            switch(ac){
                case MotionEvent.ACTION_UP:
                    Toast.makeText(MainActivity.this, String.valueOf(x), Toast.LENGTH_SHORT).show();
                    circlePath.reset();
                    break;
            }
            invalidate();
            return true;
        }
    }
}
person Daniel Nyamasyo    schedule 21.03.2017