Как убрать конец последней строки в TextView?

Как добиться эффекта затухания на последней строке TextView, как в разделе «ЧТО НОВОГО» в приложении Play Store?

Как убрать конец последней строки в TextView?

10
0
1 904
1

Ответы 1

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

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

Создается внеэкранный буфер, и мы позволяем TextView рисовать в нем свое содержимое. Затем мы рисуем градиент затухания поверх него с помощью режима передачи PorterDuff.Mode.DST_OUT, который по существу очищает нижележащий контент до степени относительно непрозрачности градиента в данной точке. Отрисовка этого буфера обратно на экран приводит к желаемому затуханию независимо от того, что находится в фоновом режиме.

public class FadingTextView extends AppCompatTextView {

    private static final float FADE_LENGTH_FACTOR = .4f;

    private final RectF drawRect = new RectF();
    private final Rect realRect = new Rect();
    private final Path selection = new Path();
    private final Matrix matrix = new Matrix();
    private final Paint paint = new Paint();
    private final Shader shader =
            new LinearGradient(0f, 0f, 1f, 0f, 0x00000000, 0xFF000000, Shader.TileMode.CLAMP);

    public FadingTextView(Context context) {
        this(context, null);
    }

    public FadingTextView(Context context, AttributeSet attrs) {
        this(context, attrs, android.R.attr.textViewStyle);
    }

    public FadingTextView(Context context, AttributeSet attrs, int defStyleAttribute) {
        super(context, attrs, defStyleAttribute);

        paint.setShader(shader);
        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // Locals
        final RectF drawBounds = drawRect;
        final Rect realBounds = realRect;
        final Path selectionPath = selection;
        final Layout layout = getLayout();

        // Figure last line index, and text offsets there
        final int lastLineIndex = getLineCount() - 1;
        final int lastLineStart = layout.getLineStart(lastLineIndex);
        final int lastLineEnd = layout.getLineEnd(lastLineIndex);

        // Let the Layout figure a Path that'd cover the last line text
        layout.getSelectionPath(lastLineStart, lastLineEnd, selectionPath);
        // Convert that Path to a RectF, which we can more easily modify
        selectionPath.computeBounds(drawBounds, false);

        // Naive text direction determination; may need refinement
        boolean isRtl =
                layout.getParagraphDirection(lastLineIndex) == Layout.DIR_RIGHT_TO_LEFT;

        // Narrow the bounds to just the fade length
        if (isRtl) {
            drawBounds.right = drawBounds.left + drawBounds.width() * FADE_LENGTH_FACTOR;
        } else {
            drawBounds.left = drawBounds.right - drawBounds.width() * FADE_LENGTH_FACTOR;
        }
        // Adjust for drawables and paddings
        drawBounds.offset(getTotalPaddingLeft(), getTotalPaddingTop());

        // Convert drawing bounds to real bounds to determine
        // if we need to do the fade, or a regular draw
        drawBounds.round(realBounds);
        realBounds.offset(-getScrollX(), -getScrollY());
        boolean needToFade = realBounds.intersects(getTotalPaddingLeft(), getTotalPaddingTop(),
                getWidth() - getTotalPaddingRight(), getHeight() - getTotalPaddingBottom());

        if (needToFade) {
            // Adjust and set the Shader Matrix
            final Matrix shaderMatrix = matrix;
            shaderMatrix.reset();
            shaderMatrix.setScale(drawBounds.width(), 1f);
            if (isRtl) {
                shaderMatrix.postRotate(180f, drawBounds.width() / 2f, 0f);
            }
            shaderMatrix.postTranslate(drawBounds.left, drawBounds.top);
            shader.setLocalMatrix(shaderMatrix);

            // Save, and start drawing to an off-screen buffer
            final int saveCount;
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                saveCount = canvas.saveLayer(null, null);
            } else {
                saveCount = canvas.saveLayer(null, null, Canvas.ALL_SAVE_FLAG);
            }

            // Let TextView draw itself to the buffer
            super.onDraw(canvas);

            // Draw the fade to the buffer, over the TextView content
            canvas.drawRect(drawBounds, paint);

            // Restore, and draw the buffer back to the Canvas
            canvas.restoreToCount(saveCount);
        } else {
            // Regular draw
            super.onDraw(canvas);
        }
    }
}

Это прямая замена TextView, и вы можете использовать ее в своем макете аналогичным образом.

<com.example.app.FadingTextView
    android:layout_width = "match_parent"
    android:layout_height = "wrap_content"
    android:background = "#e2f3eb"
    android:textColor = "#0b8043"
    android:lineSpacingMultiplier = "1.2"
    android:text = "@string/umang" />

screenshot


Заметки:

  • Вычисление длины затухания основано на постоянной части длины текста последней строки, определяемой здесь FADE_LENGTH_FACTOR. Это похоже на ту же базовую методологию компонента Play Store, поскольку абсолютная длина затухания зависит от длины строки. Значение FADE_LENGTH_FACTOR можно изменить по желанию.

  • FadingTextView в настоящее время является расширением AppCompatTextView, но он отлично работает как обычный TextView, если он вам нужен. Я думаю, что он будет работать и как MaterialTextView, хотя я еще не тестировал это полностью.

  • Этот пример ориентирован в основном на относительно простое использование; то есть как простая статическая метка в оболочке. Хотя я попытался учесть и протестировать каждую настройку TextView, о которой я мог подумать, которая может повлиять на это - например, составные чертежи, отступы, выбираемый текст, прокрутка, направление и выравнивание текста и т. д. - я не могу гарантировать, что я ' я думал обо всем.

Другие вопросы по теме