Android textview text get cut off on the sides with custom font

前端 未结 6 1430
误落风尘
误落风尘 2020-12-30 02:01

This is what happens in the preview and on device:

TextView is nothing special, it just loads the custom font:

public class TestTextView extends App         


        
相关标签:
6条回答
  • 2020-12-30 02:29

    What if you wrap it in another layout and add padding to that? For example something like this:

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="24dp">
            <*custompackage* .TestTextView
            android:gravity="left"
            android:padding="0dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="just some text for testing"
            android:textColor="@color/material_black"
            android:textSize="100dp" />
    </RelativeLayout>
    

    Not having your font and other themes etc I've just tried it with the cursive font for example and on my machine it would look like this. screenshot

    Update: Looks like you're not the only one to have had this issue and the other answers here and here both unfortunately relate to adding extra spaces.

    I've created a bug ticket here since it looks like a bug to me.

    0 讨论(0)
  • 2020-12-30 02:35

    A workaround is to add a space before typing. It will save you a lot of coding but will result in a "padding" to the left.

    android:text=" text after a space"

    0 讨论(0)
  • 2020-12-30 02:40

    This answer has led me to the right path: https://stackoverflow.com/a/28625166/4420543

    So, the solution is to create a custom Textview and override the onDraw method:

        @Override
        protected void onDraw(Canvas canvas) {
            final Paint paint = getPaint();
            final int color = paint.getColor();
            // Draw what you have to in transparent
            // This has to be drawn, otherwise getting values from layout throws exceptions
            setTextColor(Color.TRANSPARENT);
            super.onDraw(canvas);
            // setTextColor invalidates the view and causes an endless cycle
            paint.setColor(color);
    
            System.out.println("Drawing text info:");
    
            Layout layout = getLayout();
            String text = getText().toString();
    
            for (int i = 0; i < layout.getLineCount(); i++) {
                final int start = layout.getLineStart(i);
                final int end = layout.getLineEnd(i);
    
                String line = text.substring(start, end);
    
                System.out.println("Line:\t" + line);
    
                final float left = layout.getLineLeft(i);
                final int baseLine = layout.getLineBaseline(i);
    
                canvas.drawText(line,
                        left + getTotalPaddingLeft(),
                        // The text will not be clipped anymore
                        // You can add a padding here too, faster than string string concatenation
                        baseLine + getTotalPaddingTop(),
                        getPaint());
            }
        }
    
    0 讨论(0)
  • 2020-12-30 02:45

    Reworked @Dmitry Kopytov solution:

    • in Kotlin
    • recycle the old bitmap
    • added documentation
    • fall back on default TextView rendering if the bitmap cannot be created (not enough memory)

    Code:

    /**
     * This TextView is able to draw text on the padding area.
     * It's mainly used to support italic texts in custom fonts that can go out of bounds.
     * In this case, you've to set an horizontal padding (or just end padding).
     *
     * This implementation is doing a render-to-texture procedure, as such it consumes more RAM than a standard TextView,
     * it uses an additional bitmap of the size of the view.
     */
    class TextViewNoClipping(context: Context, attrs: AttributeSet?) : AppCompatTextView(context, attrs) {
        private class NonClippableCanvas(@NonNull val bitmap: Bitmap) : Canvas(bitmap) {
            override fun clipRect(left: Float, top: Float, right: Float, bottom: Float): Boolean {
                return true
            }
        }
    
        private var rttCanvas: NonClippableCanvas? = null
    
        override fun onSizeChanged(width: Int, height: Int,
                                   oldwidth: Int, oldheight: Int) {
            if ((width != oldwidth || height != oldheight) && width > 0 && height > 0) {
                rttCanvas?.bitmap?.recycle()
                try {
                    Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)?.let {
                        rttCanvas = NonClippableCanvas(it)
                    }
                } catch (t: Throwable) {
                    // If for some reasons the bitmap cannot be created, we fall back on default rendering (potentially cropping the text).
                    rttCanvas?.bitmap?.recycle()
                    rttCanvas = null
                }
            }
    
            super.onSizeChanged(width, height, oldwidth, oldheight)
        }
    
        override fun onDraw(canvas: Canvas) {
            rttCanvas?.let {
                // Clear the RTT canvas from the previous font.
                it.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
    
                // Draw on the RTT canvas (-> bitmap) that will use clipping on the NonClippableCanvas, resulting in no-clipping
                super.onDraw(it)
    
                // Finally draw the bitmap that contains the rendered text (no clipping used here, will display on top of padding)
                canvas.drawBitmap(it.bitmap, 0f, 0f, null)
    
            } ?: super.onDraw(canvas) // If rtt is not available, use default rendering process
        }
    }
    
    0 讨论(0)
  • 2020-12-30 02:52

    I have encountered the same problem and i found a one liner solution for thouse who are not using the TextView.shadowLayer.

    this is based on the source code that [Dmitry Kopytov] brought here:

    editTextOrTextView.setShadowLayer(editTextOrTextView.textSize, 0f, 0f, Color.TRANSPARENT)
    

    that's it, now the canvas.clipRect in TextView.onDraw() won't cut off the curly font sides.

    0 讨论(0)
  • 2020-12-30 02:55

    I encountered the same problem when I used some fonts in EditText.

    My first attempt was to use padding. Size of view increased but text is still cropped.

    Then I looked at the source code TextView. In method onDraw method Canvas.clipRect is called to perform this crop.

    My solution to bypass cropping when use padding :

    1) Сreate custom class inherited from Canvas and override method clipRect

    public class NonClippableCanvas extends Canvas {
    
        public NonClippableCanvas(@NonNull Bitmap bitmap) {
            super(bitmap);
        }
    
        @Override
        public boolean clipRect(float left, float top, float right, float bottom) {
            return true;
        }
    }
    

    2) Create custom TextView and override methods onSizeChanged and onDraw.

    In the method onSizeChanged create bitmap and canvas.

    In the method onDraw draw on bitmap by passing our custom Canvas to method super.onDraw. Next, draw this bitmap on the target canvas.

    public class CustomTextView extends AppCompatTextView {
        private Bitmap _bitmap;
        private NonClippableCanvas _canvas;
    
        @Override
        protected void onSizeChanged(final int width, final int height,
                                 final int oldwidth, final int oldheight) {
            if (width != oldwidth || height != oldheight) {
                _bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
                _canvas = new NonClippableCanvas(_bitmap);
            }
    
            super.onSizeChanged(width, height, oldwidth, oldheight);
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            _canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
    
            super.onDraw(_canvas);
    
            canvas.drawBitmap(_bitmap, 0, 0, null);
        }
    }
    

    0 讨论(0)
提交回复
热议问题