使用customview android在文本和下划线之间留出空格

时间:2017-08-22 22:08:15

标签: android android-canvas textview android-custom-view android-custom-attributes

I want an underline below OPTING

我想在OPTING下面有一个下划线,如下所示,但是当我创建这个将自定义视图的帮助时,下划线显示在选择下方但我想在文本和线之间留出一些空间,如图像

我创建了一个自定义视图,如果找到一个单词将在字符串中搜索,然后相应的文本将加下划线但我唯一想要的是在下划线和文本之间留出一些空格,

我的课程如下,

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.v7.widget.AppCompatTextView;
import android.text.Layout;
import android.util.AttributeSet;
import android.view.Display;
import android.view.WindowManager;
import android.widget.TextView;


public class UnderLine  extends AppCompatTextView {

private Rect mRect;
private Paint mPaint;
private int mColor;
private float density;
private float mStrokeWidth;
private String stringSeach;

public UnderLine(Context context) {
    this(context, null, 0);
}

public UnderLine(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

public UnderLine(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(context, attrs, defStyleAttr);
}

private void init(Context context, AttributeSet attributeSet, int defStyle) {

    density = context.getResources().getDisplayMetrics().density;

    TypedArray typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.UnderLine, defStyle, 0);
    mColor = typedArray.getColor(R.styleable.UnderLine_underlineColorr, 0xFFFF0000);
    stringSeach = typedArray.getString(R.styleable.UnderLine_underlineTextt);
    mStrokeWidth = typedArray.getDimension(R.styleable.UnderLine_underlineWidthh, density * 2);
    typedArray.recycle();

    mRect = new Rect();
    mPaint = new Paint();
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setColor(mColor); //line mColor
    mPaint.setStrokeWidth(mStrokeWidth);
}

public int getUnderLineColor() {
    return mColor;
}

public void setUnderLineColor(int mColor) {
    this.mColor = mColor;
    invalidate();
}

public float getUnderlineWidth() {
    return mStrokeWidth;
}

public void setUnderlineWidth(float mStrokeWidth) {
    this.mStrokeWidth = mStrokeWidth;
    invalidate();
}

@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    setMeasuredDimension( getMeasuredWidth(), getMeasuredHeight()+110);
}

@Override
protected void onDraw(Canvas canvas) {
    TextView parentTextView = this;
    Rect parentTextViewRect = new Rect();

    String targetWord = stringSeach.toLowerCase();
    int startOffsetOfClickedText = this.getText().toString().toLowerCase().indexOf(targetWord);
    int endOffsetOfClickedText = startOffsetOfClickedText + targetWord.length();

    // Initialize values for the computing of clickedText position
    Layout textViewLayout = parentTextView.getLayout();

    double startXCoordinatesOfClickedText = textViewLayout.getPrimaryHorizontal((int)startOffsetOfClickedText);
    double endXCoordinatesOfClickedText = textViewLayout.getPrimaryHorizontal((int)endOffsetOfClickedText);

    // Get the rectangle of the clicked text
    int currentLineStartOffset = textViewLayout.getLineForOffset((int)startOffsetOfClickedText);
    int currentLineEndOffset = textViewLayout.getLineForOffset((int)endOffsetOfClickedText);
    boolean keywordIsInMultiLine = currentLineStartOffset != currentLineEndOffset;
    textViewLayout.getLineBounds(currentLineStartOffset, parentTextViewRect);

    // Update the rectangle position to his real position on screen
    int[] parentTextViewLocation = {0,0};
    parentTextView.getLocationOnScreen(parentTextViewLocation);

    double parentTextViewTopAndBottomOffset = (
            //parentTextViewLocation[1] -
            parentTextView.getScrollY() +
                    parentTextView.getCompoundPaddingTop()
    );

    parentTextViewRect.top += parentTextViewTopAndBottomOffset;
    parentTextViewRect.bottom += parentTextViewTopAndBottomOffset;

    // In the case of multi line text, we have to choose what rectangle take
    if (keywordIsInMultiLine){

        WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();

        int screenHeight = display.getHeight();
        int dyTop = parentTextViewRect.top;
        int dyBottom = screenHeight - parentTextViewRect.bottom;
        boolean onTop = dyTop > dyBottom;

        if (onTop){
            endXCoordinatesOfClickedText = textViewLayout.getLineRight(currentLineStartOffset);
        }
        else{
            parentTextViewRect = new Rect();
            textViewLayout.getLineBounds(currentLineEndOffset, parentTextViewRect);
            parentTextViewRect.top += parentTextViewTopAndBottomOffset;
            parentTextViewRect.bottom += parentTextViewTopAndBottomOffset;
            startXCoordinatesOfClickedText = textViewLayout.getLineLeft(currentLineEndOffset);
        }

    }

    parentTextViewRect.left += (
            parentTextViewLocation[0] +
                    startXCoordinatesOfClickedText +
                    parentTextView.getCompoundPaddingLeft() -
                    parentTextView.getScrollX()
    );
    parentTextViewRect.right = (int) (
            parentTextViewRect.left +
                    endXCoordinatesOfClickedText -
                    startXCoordinatesOfClickedText
    );


   canvas.drawLine(parentTextViewRect.left,parentTextViewRect.bottom+mStrokeWidth, parentTextViewRect.right,
            parentTextViewRect.bottom+mStrokeWidth, mPaint);
    super.onDraw(canvas);
}

}

attrs.xml如下,

  <declare-styleable name="UnderLine" >
    <attr name="underlineWidthh" format="dimension" />
    <attr name="underlineColorr" format="color" />
    <attr name="underlineTextt" format="string" />
</declare-styleable>

示例布局如下,

    <UnderLine
    style="@style/textView"
    android:gravity="top|center"
    app:underlineColorr="@color/signup_bottom_darkWhite"
    app:underlineWidthh="2dp"
    app:underlineTextt="OPTING"
    android:text="ON FREE PARKING + DISCOUNTED RATES \n BY OPTING IN"/>

我是customview的初学者,我在stackoverflow上的一些答案的帮助下创建了这个。请不要以任何其他方式建议。

Anyhelp将不胜感激。

1 个答案:

答案 0 :(得分:2)

我已经开发了自己的观点,如下所示,

package com.example.reprator.underlinetextview;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.v7.widget.AppCompatTextView;
import android.text.Layout;
import android.util.AttributeSet;

public class UnderlinedTextView extends AppCompatTextView {

private Rect mRect;
private Paint mPaint;
private int mColor;
private float mStrokeWidth;
private float mMarginTop;
private boolean isAllSelected;
private int lineNumber;
private int selectTextEachLine;

public UnderlinedTextView(Context context) {
    this(context, null, 0);
}

public UnderlinedTextView(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

public UnderlinedTextView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init(context, attrs, defStyleAttr);
}

private void init(Context context, AttributeSet attributeSet, int defStyle) {

    float density = context.getResources().getDisplayMetrics().density;

    TypedArray typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.UnderlinedTextView, defStyle, 0);
    mColor = typedArray.getColor(R.styleable.UnderlinedTextView_underlineColor, 0xFFFF0000);
    mStrokeWidth = typedArray.getDimension(R.styleable.UnderlinedTextView_underlineWidth, density * 2);
    mMarginTop = typedArray.getDimension(R.styleable.UnderlinedTextView_underlineMarginTop, density * 2);
    isAllSelected = typedArray.getBoolean(R.styleable.UnderlinedTextView_underlineIsAll, false);
    lineNumber = typedArray.getInteger(R.styleable.UnderlinedTextView_underlineNoLine, 1);
    selectTextEachLine = typedArray.getInteger(R.styleable.UnderlinedTextView_underlineTextEachLine, 3);
    typedArray.recycle();

    mRect = new Rect();
    mPaint = new Paint();
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setColor(mColor); //line mColor
    mPaint.setStrokeWidth(mStrokeWidth);
}

public int getUnderLineColor() {
    return mColor;
}

public void setUnderLineColor(int mColor) {
    this.mColor = mColor;
    invalidate();
}

public float getUnderlineWidth() {
    return mStrokeWidth;
}

public void setUnderlineWidth(float mStrokeWidth) {
    this.mStrokeWidth = mStrokeWidth;
    invalidate();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    int h = (int) (getMeasuredHeight() + mMarginTop);
    setMeasuredDimension(widthMeasureSpec, h);
}

@Override
protected void onDraw(Canvas canvas) {

    final Layout layout = getLayout();
    float x_start, x_stop;
    int firstCharInLine, lastCharInLine;

    int limit = isAllSelected ? getLineCount() : lineNumber;
    for (int i = 0; i < limit; i++) {
        int baseline = getLineBounds(i, mRect);
        firstCharInLine = layout.getLineStart(i);
        lastCharInLine = layout.getLineEnd(i);

        int textHighlight = isAllSelected ? lastCharInLine - 1 : (firstCharInLine + selectTextEachLine);
        x_start = layout.getPrimaryHorizontal(firstCharInLine);
        x_stop = layout.getPrimaryHorizontal(textHighlight);

        float y = baseline + mStrokeWidth + mMarginTop;
        canvas.drawLine(x_start, y, x_stop, y, mPaint);
    }

    super.onDraw(canvas);
}

}

和我的attars.xml如下,

 <declare-styleable name="UnderlinedTextView">
    <attr name="underlineWidth" format="dimension" />
    <attr name="underlineMarginTop" format="dimension" />
    <attr name="underlineColor" format="color" />
    <attr name="underlineText" format="string" />
    <attr name="underlineIsAll" format="boolean" />
    <attr name="underlineNoLine" format="integer" />
    <attr name="underlineTextEachLine" format="integer" />
</declare-styleable>