Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
191 views
in Technique[技术] by (71.8m points)

android - Rounded Background text like Instagram, ReplacementSpan not working as required

I was trying to do something similar to Instagram below -

This is what i have done

But i want this curves like Instagram - This is what i want

Now i am stuck in one more problem - When i types,. text does not goes automatically to next line, I have to press return , like normally editText works in fixed width. (In short multiline is not working fine with ReplacementSpan)

Below is sample code for what i have done -

public class EditextActivity extends AppCompatActivity {

    EditText edittext;
    RoundedBackgroundSpan roundedBackgroundSpan;


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.editext_screen);
        edittext=(EditText)findViewById(R.id.edittext);
       // edittext.setText("Hello My name is Karandeep Atwal.

 Hii this is test");
        roundedBackgroundSpan= new RoundedBackgroundSpan(Color.RED,Color.WHITE);
        edittext.getText().setSpan(roundedBackgroundSpan, 0, edittext.getText().length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE);
    }


    public class RoundedBackgroundSpan extends ReplacementSpan implements LineHeightSpan {

        private static final int CORNER_RADIUS = 15;
        private static final int PADDING_X = 10;

        private int   mBackgroundColor;
        private int   mTextColor;

        /**
         * @param backgroundColor background color
         * @param textColor text color
         */
        public RoundedBackgroundSpan(int backgroundColor, int textColor) {
            mBackgroundColor = backgroundColor;
            mTextColor = textColor;
        }

        @Override
        public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
            return (int) (PADDING_X + paint.measureText(text,start, end) + PADDING_X);
        }

        @Override
        public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
            float width = paint.measureText(text,start, end);
            RectF rect = new RectF(x, top, x + width + 2 * PADDING_X, bottom);
            paint.setColor(mBackgroundColor);
            canvas.drawRoundRect(rect, CORNER_RADIUS, CORNER_RADIUS, paint);
            paint.setColor(mTextColor);
            canvas.drawText(text, start, end, x + PADDING_X, y, paint);
        }

        @Override
        public void chooseHeight(CharSequence text, int start, int end, int spanstartv, int v, Paint.FontMetricsInt fontMetricsInt) {

        }
    }

}

Below is my xml -

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    android:layout_gravity="center"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <EditText
        android:padding="5dp"
        android:background="@drawable/border"
        android:id="@+id/edittext"
        android:layout_centerInParent="true"
        android:textColor="@android:color/black"
        android:gravity="center"
        android:hint="hi"
        android:singleLine="false"
        android:inputType="textMultiLine"
        android:textSize="30sp"
        android:maxWidth="100dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>

Below is what i am getting when i type using setSpan -

enter image description here

This is normal behaviour for fixed width, that i want -

enter image description here

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

enter image description here activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/holo_purple"
    tools:context="com.tttzof.demotext.MainActivity">

    <EditText
        android:id="@+id/editText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:hint="Enter text"
        android:textSize="30sp"
        android:gravity="center"
        android:textColor="@android:color/black"
        android:background="@android:color/transparent"
        android:layout_gravity="center"/>

</FrameLayout>

MainActivity.java

import android.graphics.Color;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.Spannable;
import android.text.TextWatcher;
import android.widget.EditText;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final EditText editText = (EditText) findViewById(R.id.editText);

        int padding = dp(8);
        int radius = dp(5);

        final Object span = new BackgroundColorSpan(
                        Color.WHITE,
                        (float)padding,
                        (float) radius
        );

        editText.setShadowLayer(padding, 0f, 0f, 0);
        editText.setPadding(padding, padding, padding, padding);

        editText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                s.setSpan(span, 0, s.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        });
    }

    private int dp(int value) {
        return (int) (getResources().getDisplayMetrics().density * value + 0.5f);
    }
}

BackgroundColorSpan.java

import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.text.style.LineBackgroundSpan;

public class BackgroundColorSpan implements LineBackgroundSpan {
    private float padding;
    private float radius;

    private RectF rect = new RectF();
    private Paint paint = new Paint();
    private Paint paintStroke = new Paint();
    private Path path = new Path();

    private float prevWidth = -1f;
    private float prevLeft = -1f;
    private float prevRight = -1f;
    private float prevBottom = -1f;
    private float prevTop = -1f;


    public BackgroundColorSpan(int backgroundColor,
                               float padding,
                               float radius) {
        this.padding = padding;
        this.radius = radius;

        paint.setColor(backgroundColor);
        //paintStroke.setStyle(Paint.Style.STROKE);
        //paintStroke.setStrokeWidth(5f);
        paintStroke.setColor(backgroundColor);
    }

    @Override
    public void drawBackground(
                    final Canvas c,
                    final Paint p,
                    final int left,
                    final int right,
                    final int top,
                    final int baseline,
                    final int bottom,
                    final CharSequence text,
                    final int start,
                    final int end,
                    final int lnum) {

        float width = p.measureText(text, start, end) + 2f * padding;
        float shift = (right - width) / 2f;

        rect.set(shift, top, right - shift, bottom);

        if (lnum == 0) {
            c.drawRoundRect(rect, radius, radius, paint);
        } else {
            path.reset();
            float dr = width - prevWidth;
            float diff = -Math.signum(dr) * Math.min(2f * radius, Math.abs(dr/2f))/2f;
            path.moveTo(
                            prevLeft, prevBottom - radius
            );

            path.cubicTo(
                            prevLeft, prevBottom - radius,
                            prevLeft, rect.top,
                            prevLeft + diff, rect.top
            );
            path.lineTo(
                            rect.left - diff, rect.top
            );
            path.cubicTo(
                            rect.left - diff, rect.top,
                            rect.left, rect.top,
                            rect.left, rect.top + radius
            );
            path.lineTo(
                            rect.left, rect.bottom - radius
            );
            path.cubicTo(
                            rect.left, rect.bottom - radius,
                            rect.left, rect.bottom,
                            rect.left + radius, rect.bottom
            );
            path.lineTo(
                            rect.right - radius, rect.bottom
            );
            path.cubicTo(
                            rect.right - radius, rect.bottom,
                            rect.right, rect.bottom,
                            rect.right, rect.bottom - radius
            );
            path.lineTo(
                            rect.right, rect.top + radius
            );
            path.cubicTo(
                            rect.right, rect.top + radius,
                            rect.right, rect.top,
                            rect.right + diff, rect.top
            );
            path.lineTo(
                            prevRight - diff, rect.top
            );
            path.cubicTo(
                            prevRight - diff, rect.top,
                            prevRight, rect.top,
                            prevRight, prevBottom - radius
            );
            path.cubicTo(
                            prevRight, prevBottom - radius,
                            prevRight, prevBottom,
                            prevRight - radius, prevBottom

            );
            path.lineTo(
                            prevLeft + radius, prevBottom
            );
            path.cubicTo(
                            prevLeft + radius, prevBottom,
                            prevLeft, prevBottom,
                            prevLeft, rect.top - radius
            );
            c.drawPath(path, paintStroke);
        }

        prevWidth = width;
        prevLeft = rect.left;
        prevRight = rect.right;
        prevBottom = rect.bottom;
        prevTop = rect.top;
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...