android - 重复调用 LineBackgroundSpan drawBackground()

标签 android android-layout android-edittext

编辑:我已经能够将问题追溯到使用 EditText 而不是 TextView。重复调用仅在字段为 EditText 时发生,并且系统在字段为 TextView 时自行运行。我在文档或网上找不到任何内容表明 LineBackgroundSpan 不适用于 EditText

我已经更新了 MCVE 来展示如何使用 TextView(它可以)和 EditText(它不能 - 至少不是很好)。我更新的问题是如何让 LineBackgroundSpanEditText 一起工作。


我已经实现了一个简单的类,使用 LineBackgroundSpanEditText 中的文本添加圆形背景。 .一切正常,但在调试时我注意到我的类的 drawBackground 方法被重复调用,并且似乎没有结束字符串中的每个跨度,即使没有进行任何更改。它在显示屏上不明显,但如果在 drawBackground 方法中设置断点,则很明显。

在尝试追查问题时,我能够将代码缩减为 MCVE。以下代码将简单地突出显示整行文本。顶行是 EditText,底行是 TextView。 (这不是我真正想要做的,但它达到了目的。)

此 MCVE 在运行 API 17 和 API 24 的模拟器以及运行 API 24 的实际手机上向我展示了问题。将 disableDraw 参数设置为 true RoundedBackgroudSpan() 的构造函数将禁用 drawBackground() 中的背景绘制操作。我在 EditText 上看到了问题,即使禁用了背景绘图也是如此。

这是怎么回事?我误解了如何使用跨度吗?跨度是否不适用于 EditText?任何帮助将不胜感激。

MainActivity.java

    package com.example.bgspanmcve;

import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.SpannableString;
import android.text.style.LineBackgroundSpan;
import android.util.Log;
import android.widget.EditText;
import android.widget.TextView;

import static android.text.Spanned.SPAN_INCLUSIVE_INCLUSIVE;

public class MainActivity extends AppCompatActivity {
    final String dispString = "XAB CD EF";
    private static int count = 0; // times drawBackground is called

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        EditText editText;
        TextView textView;
        RoundedBackgroundSpan bg;

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Set up the EditText field with a span.
        // RoundedBackgroundSpan#drawBackground will be called forever for this EditText.
        editText = ((EditText) findViewById(R.id.editText));
        SpannableString ssEditText = new SpannableString(dispString);
        bg = new RoundedBackgroundSpan(INHIBIT_DRAWING, false);
        ssEditText.setSpan(bg, 0, ssEditText.length(), SPAN_INCLUSIVE_INCLUSIVE);
        editText.setText(ssEditText);

        // Set up the TextView field with a span.
        // RoundedBackgroundSpan#drawBackground will be called once for this TextView.
        textView = ((TextView) findViewById(R.id.textView));
        SpannableString ssTextView = new SpannableString(dispString);
        bg = new RoundedBackgroundSpan(INHIBIT_DRAWING, true);
        ssTextView.setSpan(bg, 0, ssTextView.length(), SPAN_INCLUSIVE_INCLUSIVE);
        textView.setText(ssTextView, TextView.BufferType.EDITABLE);
    }

    private static class RoundedBackgroundSpan implements LineBackgroundSpan {
        private boolean mDisableDraw;
        private boolean mIsTextView;

        RoundedBackgroundSpan(boolean disableDraw, boolean isTextView) {
            super();
            mDisableDraw = disableDraw;
            mIsTextView = isTextView;
        }

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

            count++;
            if (mIsTextView) {
                Log.d(TAG, "<<<<drawBackground (TextView) #" + count);
            } else {
                Log.d(TAG, "<<<<drawBackground (EditText) #" + count);
            }
            if (mDisableDraw) return;

            Paint localPaint = new Paint();
            RectF rect = new RectF(left, top, right, bottom);
            localPaint.setColor(BG_COLOR);
            canvas.drawRoundRect(rect, RADIUS_X, RADIUS_Y, localPaint);
        }

        private final String TAG = RoundedBackgroundSpan.class.getSimpleName();
        private final int BG_COLOR = 0xfF00FF00;
        private final int RADIUS_X = 20;
        private final int RADIUS_Y = 20;
    }

    private final static String TAG = MainActivity.class.getSimpleName();
    private final boolean INHIBIT_DRAWING = true;
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.bgspanmcve.MainActivity">

    <EditText
        android:id="@+id/editText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_marginStart="0dp"
        android:inputType="text"
        android:paddingEnd="0dp"
        android:paddingStart="0dp"
        android:text="EditText"
        android:textSize="20sp" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignStart="@id/editText"
        android:layout_below="@id/editText"
        android:layout_marginStart="0dp"
        android:layout_marginTop="16dp"
        android:paddingEnd="0dp"
        android:paddingStart="0dp"
        android:text="TextView"
        android:textSize="20sp"
        android:textStyle="bold" />

</RelativeLayout>

最佳答案

drawBackground() 的调用是按照@Suragch 建议的闪烁光标的速率计时的,该速率约为 500 毫秒。我现在确信对 drawBackground() 的调用是作为游标实现的一部分进行的。

作为一个快速但非决定性的测试,我已将 EditText 字段设置为不显示光标但仍可编辑 (android:cursorVisible="false" ).当此属性设置为 false 时,对 drawBackground() 的重复调用将停止。

关于android - 重复调用 LineBackgroundSpan drawBackground(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43611613/

相关文章:

java - 如何使用Java检查android中的editText框是否为空

按任意键时android编辑文本隐藏在键盘下方

android - 带有 Libgdx 屏幕的 LinearLayout 中的 Admob 横幅

android - ListView 显示错误和重复图像

android - Scrollview 并不总是显示滚动条 - android?

android - 通过摄像头进行人脸检测

android - 由父级捕获 onTouch 事件,处理并传递给子级

android - 调整 SwipeRefreshLayout 高度以将 View 置于其底部

java - EditText OnClickListener 需要两次点击才能工作

没有overlayColor的Android GIF borderRadius