编辑文本缩放与选择

2022-09-01 11:04:50

我有一个我想缩放它,并用/滚动,它工作正常 - 文本正在正确的位置进行编辑。EditTextsetScaleXsetScaleY

但是当我尝试选择文本时 - 它会将选择手柄绘制到位置,例如文本未缩放时。这是已知的错误

这是预期的结果,因为在与视图大小相关的弹出窗口上绘制句柄。

上的所有操作都针对其字段 。如果我们通过反射设置自己的编辑器,我不知道该如何处理私有方法,这些方法不可重写。android.widget.Editorprivate TextView mTextView;

此外,选择手柄是在布局中计算的弹出窗口坐标上绘制的,我只需要,但对于我们的目的来说,它没有区别。android.widget.Editor.HandleView#HandleViewDynamicLayout

方法是公共的,其值可以按比例乘以,但为此我们需要扩展和覆盖私有方法,但这是一个问题。android.text.Layout#getPrimaryHorizontal(int, boolean)android.widget.TextView#makeSingleLayout

此外,我们可以使用所有必需的重写方法实现自己的布局,但是我们可以重写的所有方法都标有注释,并且没有可以通过反射访问的字段。@hide

显示下一个屏幕截图,用于在 2x 上缩放

enter image description here

PS:任务的上下文是一个 编辑器 与捏合缩放编辑文本。通过计算大小来中继文本不是解决方案。因为我需要每个屏幕尺寸上的便携式文档。


答案 1

您可以使用MetricAffectingSpan来做到这一点。下面是一个类来说明它:

package android.text.style;

import android.os.Parcel;
import android.text.ParcelableSpan;
import android.text.TextPaint;
import android.text.TextUtils;

public class AbsoluteSizeSpan extends MetricAffectingSpan implements ParcelableSpan {

    private final int mSize;
    private boolean mDip;

    /**
     * Set the text size to <code>size physical pixels.
     */
    public AbsoluteSizeSpan(int size) {
        mSize = size;
    }

    /**
     * Set the text size to <code>size physical pixels,
     * or to <code>size device-independent pixels if
     * <code>dip is true.
     */
    public AbsoluteSizeSpan(int size, boolean dip) {
        mSize = size;
        mDip = dip;
    }

    public AbsoluteSizeSpan(Parcel src) {
        mSize = src.readInt();
        mDip = src.readInt() != 0;
    }

    public int getSpanTypeId() {
        return TextUtils.ABSOLUTE_SIZE_SPAN;
    }

    public int describeContents() {
        return 0;
    }

    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(mSize);
        dest.writeInt(mDip ? 1 : 0);
    }

    public int getSize() {
        return mSize;
    }

    public boolean getDip() {
        return mDip;
    }

    @Override
    public void updateDrawState(TextPaint ds) {
        if (mDip) {
            ds.setTextSize(mSize * ds.density);
        } else {
            ds.setTextSize(mSize);
        }
    }

    @Override
    public void updateMeasureState(TextPaint ds) {
        if (mDip) {
            ds.setTextSize(mSize * ds.density);
        } else {
            ds.setTextSize(mSize);
        }
    }
}

参考:Java 源代码仓库项目

你需要玩 MetricAffectingSpanwrap(CharacterStyle cs) - 这允许 CharacterStyle 应用于给定 Spanned 的单个区域。

在子类中,覆盖 onTouch 并将其值传递给 ScaleGestureDetector。将检测到的刻度存储为成员变量。

覆盖 onDraw,并在调用 super.onDraw 之前使用您的比例值调用 canvas.scale()。正如您在 AbsoluteSizeSpan 中注意到的那样,使用 AbsoluteSizeSpan(Parcel src) 将获得您想要调整大小的文本,然后应用 updateDrawState


答案 2

您是否尝试过对这些元素应用不同的样式?我认为它应该有一些条件反射。

<item name="android:textSelectHandle">@drawable/text_select_handle_middle</item>
<item name="android:textSelectHandleLeft">@drawable/text_select_handle_left</item>
<item name="android:textSelectHandleRight">@drawable/text_select_handle_right</item>

推荐