Пробую это с утра, но не могу заставить работать.

Я пытаюсь создать что-то вроде длинной тени для TextView, которая похожа на следующее:

http://www.iceflowstudios.com/v3/wp-content/uploads/2013/07/long_shadow_banner.jpg http://web3canvas.com/wp-content/uploads/2013/07/lsd-ps-action-720x400.png

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

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

Поэтому мне было интересно, можно ли использовать: (я должен упомянуть, что текстовые представления создаются динамически)

TV.setShadowLayer(1f, 5f, 5f, Color.GREY);

Чтобы создать несколько из них в линию (как каскадный слой), чтобы тень казалась гладкой? Или вы, ребята, предлагаете какие-нибудь другие решения?

Заранее спасибо.

9
Johnaudi 12 Окт 2014 в 18:20

3 ответа

Лучший ответ

Попробуйте поиграть с растровыми изображениями:

  1. Определите границы текста с помощью Paint.getTextBounds() метод
  2. Создайте прозрачный Bitmap с такими показателями (W + H) x H (вы можете использовать Bitmap.Config.ALPHA_8 для оптимизации использования памяти)
  3. Нарисуйте текст на этом Bitmap в позиции 0x0
  4. Скопируйте первую строку Bitmap в новую с исходной шириной, но с высотой 1px
  5. Обходите Y-axis из Bitmap (сверху вниз) и нарисуйте однострочный Bitmap с соответствующим смещением на X-axis (некоторые прозрачные пиксели будут перекрыты)
  6. Теперь у вас есть верхняя часть вашей тени
  7. Нарисуйте нижнюю часть, используя ту же технику, но выбрав последний ряд этого Bitmap

Этот алгоритм можно оптимизировать, если вы обнаружите, что все пиксели в последней строке имеют одинаковый цвет (полная тень).

ОБНОВЛЕНИЕ 1

Такого результата я добился с помощью этого быстрого решения:

enter image description here

MainActivity.java

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle state) {
        super.onCreate(state);

        LongShadowTextView longShadow = new LongShadowTextView(this);
        longShadow.setText("Hello World");
        setContentView(longShadow);
    }
}

LongShadowTextView.java

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.view.View;

public class LongShadowTextView extends View {
    private Bitmap mBitmap;
    private String mText;

    public LongShadowTextView(Context context) {
        super(context);
    }

    public void setText(String text) {
        Paint paint = new Paint();
        // TODO provide setters for these values
        paint.setColor(Color.BLACK);
        paint.setTextSize(142);

        Rect rect = new Rect();
        paint.getTextBounds(text, 0, text.length(), rect);

        Bitmap bitmap = Bitmap.createBitmap(rect.width() + rect.height(), rect.height(), Bitmap.Config.ALPHA_8);
        Canvas canvas = new Canvas(bitmap);

        canvas.drawText(text, 0, rect.height(), paint);

        Rect src = new Rect();
        RectF dst = new RectF();

        int w = bitmap.getWidth();
        int h = bitmap.getHeight();

        src.left = 0;
        src.right = w;

        for (int i = 0; i < h; ++i) {
            src.top = i;
            src.bottom = i + 1;

            dst.left = 1;
            dst.top = i + 1;
            dst.right = 1 + w;
            dst.bottom = i + 2;

            canvas.drawBitmap(bitmap, src, dst, null);
        }

        mText = text;
        mBitmap = bitmap;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawBitmap(mBitmap, 0, 0, null);
    }
}

ОБНОВЛЕНИЕ 2

Вот окончательный результат, которого я добился. Скопируйте эту демонстрацию из github.

enter image description here

12
Oleksii K. 16 Окт 2014 в 21:39

Боюсь, что предложенный вами подход к использованию setShadowLayer() не сработает, поскольку этот подход эффективно рисует второй TextPaint с размытием.

Наложение нескольких TextPaints друг на друга будет означать, что вам нужно смещать их на 1 пиксель для каждого шага, что очень графически интенсивно и будет иметь очень низкую производительность.

Это отличный вопрос и настоящий вызов!

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

Предлагаемое чтение:

0
Community 23 Май 2017 в 12:17

Небольшой комментарий, если кто-то попытается запустить метод setText (). сейчас он не работает. Вы должны вызвать invalidate (); в setText (); метод

 public void setText(String value) {
    boolean changed = 
       mText == null && value != null || mText != null && !mText.equals(value);

    mText = value;

    if (changed) {
        refresh();
    }
    invalidate();
}
0
rurik 3 Янв 2015 в 19:37