Эквивалент RadialGradientPaint в Android - PullRequest
0 голосов
/ 07 июня 2018

Я рисую круг радиального градиента на изображении, подобном этому

enter image description here

У меня есть Java-код для этого

private void drawRadialGradientCircleJava(String imagePath, double posX, double posY, float radius, String outputPath) throws IOException{
    BufferedImage city = ImageIO.read(new File(imagePath));

    BufferedImage mask = new BufferedImage(city.getWidth(), city.getHeight(), BufferedImage.TYPE_INT_ARGB);

    Graphics2D g2d = mask.createGraphics();
    Color transparent = new Color(255, 0, 0, 0);
    Color fill = Color.RED;
    RadialGradientPaint rgp = new RadialGradientPaint(
            new Point2D.Double(posX, posY),
            radius,
            new float[]{0f, 0.75f, 1f},
            new Color[]{transparent, transparent, fill});
    g2d.setPaint(rgp);
    g2d.fill(new Rectangle(0, 0, mask.getWidth(), mask.getHeight()));
    g2d.dispose();

    BufferedImage masked = new BufferedImage(city.getWidth(), city.getHeight(), BufferedImage.TYPE_INT_ARGB);
    g2d = masked.createGraphics();
    g2d.setColor(Color.RED);
    g2d.fillRect(0, 0, masked.getWidth(), masked.getHeight());
    g2d.drawImage(city, 0, 0, null);
    g2d.setComposite(AlphaComposite.DstAtop);
    g2d.drawImage(mask, 0, 0, null);
    g2d.dispose();

    ImageIO.write(masked,"png", new File(outputPath));
}

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

У меня следующий код Androidтакже, но id ничего не рисует на изображении

  private void drawRadialGradientCircleAndroid(ImageView imageView, float posX,
                                                 float posY, float radius) throws IOException {

        RadialGradient gradient = new RadialGradient(posX, posY, radius, Color.TRANSPARENT,
                Color.TRANSPARENT, android.graphics.Shader.TileMode.CLAMP);
        Paint p = new Paint();
        p.setDither(true);
        p.setShader(gradient);

        Bitmap bm = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
        Bitmap bmOverlay = Bitmap.createBitmap(bm.getWidth(), bm.getHeight(), bm.getConfig());
        Canvas canvas = new Canvas(bmOverlay);
        canvas.drawBitmap(bm, new Matrix(), null);
        canvas.drawCircle(posY, posX, radius, p);
        imageView.setImageBitmap(bmOverlay);

    }

Пожалуйста, помогите, как мне добиться этого в Android.

1 Ответ

0 голосов
/ 07 июня 2018

Мы должны перенести это в поля для ответов.

ОП в основном получил его здесь - и на самом деле пересмотренный ОП gist великолепен.

Некоторые общие советы относительно первой попытки в вопросе:

1) В protected void onSizeChanged(int w, int h, int oldw, int oldh):

  • width = w; нет причин, по которым вы можете 'Звоните getWidth(), когда вам это нужно.Это целесообразно потому, что внутренняя ширина View установлена ​​довольно поздно после onMeasure.Следовательно, onDraw может быть в следующий раз, когда вам нужна самая свежая версия, поэтому используйте получатель там.
  • mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);.Создание растрового изображения является дорогостоящей и требующей большого объема памяти операцией.Если вы не хотите записать растровое изображение в файл или отправить его в BitmapDrawable для ImageView или чего-то еще, вам не нужно это делать.Особенно с эффектами, нарисованными на пользовательском интерфейсе с библиотекой graphics для Android.
  • mCanvas = new Canvas(mBitmap); с последующей операцией рисования на новом холсте.Это никогда не нужно.И все же я видел это (не работает) во многих кодах и попытках.Я думаю это ошибка старого поста переполнения стека, который заставил людей делать это так, чтобы они могли преобразовать холст в пользовательском представлении, не влияя на рисунок на остальной части холста.Кстати, если вам это нужно, используйте .restore() и .save().Если вы видите new Canvas, с подозрением .

2) onDraw(...):

  • Да , вам нужноизбегать таких вещей в onDraw, как создание объектов или любая тяжелая обработка. Но вам все равно нужно делать то, что в onDraw, что нужно делать в onDraw!
  • Так что здесь вам просто нужно вызвать : canvas.drawCircle(float cx, float cy, float radius, Paint paint) с аргументами согласно документам .
  • Это действительно не так уж грехonDraw. Если вы беспокоитесь о том, чтобы назвать это слишком много , как это может быть в случае анимирования всей кнопки на экране, вам нужно использовать аппаратное ускорение , доступное в более поздних версиях API,как будет подробно описано в статье под названием Оптимизация представления ;очень полезное чтение, если вы используете много пользовательских нарисованных видов.

3) Этот надоедливый радиальный градиент .Следующая проблема, с которой вы столкнулись, заключается в том, что вы совершенно правильно создали свою краску методом init, чтобы создание объекта было не в порядке.Но тогда совершенно справедливо, что на вас будет IllegalArgumentException ed (я думаю), потому что на этом этапе getHeight() представления было 0. Вы пытались передать небольшие значения в пикселях - это не сработает, если вы не знаете магию оразмеры экрана.

Это не ваша проблема, а раздражающий цикл просмотра в основе шаблонов дизайна Android.Исправить это достаточно просто: просто используйте более позднюю часть процесса рисования вида после вызова onMeasure, чтобы установить фильтр рисования.

Но Есть некоторые проблемы с получением этого праваа именно, что иногда, к сожалению, onDraw вызывается до того момента, когда вы ожидаете этого.В результате ваша краска будет иметь нулевое значение, и вы не получите желаемого поведения.

Я нашел более надежное решение - просто выполнить дерзкую и непослушную пустую проверку в onDraw, а затем только один раз построить объект рисования там.Строго говоря, это не оптимально, но учитывая сложный способ, которым объекты Paint соединяются с собственным графическим слоем Android, лучше, чем пытаться совмещать конфигурацию и конструкцию рисования во многих часто называемых местах.И это делает чертовски более понятный код.

Это будет выглядеть (исправляя вашу суть):

        @Override
        protected void onDraw(final Canvas canvas) {
            super.onDraw(canvas);
            if (mPaint == null) {
                mPaint = new Paint();
                mPaint.setColor(Color.BLACK);
                mPaint.setStrokeWidth(1);
                mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
                mPaint.setShader(new RadialGradient(getWidth() / 2, getHeight() / 2,
                        getHeight() / 3, Color.TRANSPARENT, Color.BLACK, TileMode.MIRROR));
            }
            width = getWidth();
            height = getHeight();
            canvas.drawCircle(width / 2, height / 2, height / 3, mPaint);
        }

Так что обратите внимание на несколько изменений - я думаю, из вашего описания вы хотите поменять два цветаокруглите аргументы, также не забывайте центрировать центр вашего градиента по вашему мнению: width/2 и height/2 аргументы.

Удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...