【问题标题】:Android: Handling text size for different dip devicesAndroid:处理不同dip设备的文本大小
【发布时间】:2019-07-30 08:12:35
【问题描述】:

对于相同的屏幕尺寸、不同的 dpi 设备,我得到了不同的文本尺寸。我希望文本在所有设备(如 Inshorts 应用)上的大小完全相同。

从这些屏幕截图中可以看出,xxhdpi 的文本大小略大于 560 dpi 设备。

我的 xml 布局:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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"
    tools:context=".MainActivity"
    android:layout_margin="30dp">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
        android:textSize="14sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

我也尝试使用 dp 代替 sp 没有任何成功。 请帮忙。

【问题讨论】:

  • 转换多个部分的值,如..small、medium、normal、large 和 extra large..以及这些文件中的值。
  • 使用 dp 代替 sp 文本大小
  • @ParthLotia 我也试过了,但问题是我的两个设备都属于大类,所以没有变化。
  • @underoid 如前所述,我尝试过 dp 也没有任何成功。
  • 问题是你的 textView 宽度不是恒定的 (wrap_content),如果你让你的 textView 的宽度在 dp 中保持恒定,那么 dp 中的文本大小应该可以工作。

标签: android android-layout text-size pixel-density


【解决方案1】:

如果您希望文本大小与密度无关,则应使用 dp 而不是 sp。

通过这种方式,您的文本大小也不会受到手机设置中用户文本大小偏好的影响。

【讨论】:

  • 正如我的问题中提到的,我已经尝试过 dp 但没有效果。在屏幕截图中使用 dp 后,文本大小有所不同。
【解决方案2】:

将跟随类(AutoResizeTextView)添加到您的项目中,然后将跟随代码添加到您的xml中 在值 android:maxLines="1" 放任何你想要的,所以自动计算会改变字体大小

<com.example.youpackage.AutoResizeTextView
                android:id="@+id/textViewTitle"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="0.40"
                android:text="@string/title"
                android:textColor="#FFFFFF"
                android:maxLines="1"
                android:paddingBottom="5dp"
                android:layout_marginBottom="5dp"
                android:gravity="center_vertical|center_horizontal"
                android:textSize="50sp" />

这里是 AutoResizeTextView 类

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.RectF;
import android.os.Build;
import android.text.Layout.Alignment;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.method.TransformationMethod;
import android.util.AttributeSet;
import android.util.SparseIntArray;
import android.util.TypedValue;
import android.widget.TextView;

/**
 * http://stackoverflow.com/questions/16017165/auto-fit-textview-for-android/21851239
 */
public class AutoResizeTextView extends TextView {

    public AutoResizeTextView(Context context) {
        super(context);
        initialize();
    }

    public AutoResizeTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initialize();
    }

    public AutoResizeTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initialize();
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public AutoResizeTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initialize();
    }

    private interface SizeTester {
        /**
         *
         * @param suggestedSize
         *            Size of text to be tested
         * @param availableSpace
         *            available space in which text must fit
         * @return an integer < 0 if after applying {@code suggestedSize} to
         *         text, it takes less space than {@code availableSpace}, > 0
         *         otherwise
         */
        public int onTestSize(int suggestedSize, RectF availableSpace);
    }

    private RectF mTextRect = new RectF();

    private RectF mAvailableSpaceRect;

    private SparseIntArray mTextCachedSizes;

    private TextPaint mPaint;

    private float mMaxTextSize;

    private float mSpacingMult = 1.0f;

    private float mSpacingAdd = 0.0f;

    private float mMinTextSize = 10;

    private int mWidthLimit;

    private static final int NO_LINE_LIMIT = -1;
    private int mMaxLines;

    private boolean mEnableSizeCache = true;
    private boolean mInitializedDimens;

    private void initialize() {
        mPaint = new TextPaint(getPaint());
        mMaxTextSize = getTextSize();
        mAvailableSpaceRect = new RectF();
        mTextCachedSizes = new SparseIntArray();
        if (mMaxLines == 0) {
            // no value was assigned during construction
            mMaxLines = NO_LINE_LIMIT;
        }
    }

    @Override
    public void setTextSize(float size) {
        mMaxTextSize = size;
        mTextCachedSizes.clear();
        adjustTextSize();
    }

    @Override
    public void setMaxLines(int maxlines) {
        super.setMaxLines(maxlines);
        mMaxLines = maxlines;
        adjustTextSize();
    }

    public int getMaxLines() {
        return mMaxLines;
    }

    @Override
    public void setSingleLine() {
        super.setSingleLine();
        mMaxLines = 1;
        adjustTextSize();
    }

    @Override
    public void setSingleLine(boolean singleLine) {
        super.setSingleLine(singleLine);
        if (singleLine) {
            mMaxLines = 1;
        } else {
            mMaxLines = NO_LINE_LIMIT;
        }
        adjustTextSize();
    }

    @Override
    public void setLines(int lines) {
        super.setLines(lines);
        mMaxLines = lines;
        adjustTextSize();
    }

    @Override
    public void setTextSize(int unit, float size) {
        Context c = getContext();
        Resources r;

        if (c == null)
            r = Resources.getSystem();
        else
            r = c.getResources();
        mMaxTextSize = TypedValue.applyDimension(unit, size,
                r.getDisplayMetrics());
        mTextCachedSizes.clear();
        adjustTextSize();
    }

    @Override
    public void setLineSpacing(float add, float mult) {
        super.setLineSpacing(add, mult);
        mSpacingMult = mult;
        mSpacingAdd = add;
    }

    /**
     * Set the lower text size limit and invalidate the view
     *
     * @param minTextSize
     */
    public void setMinTextSize(float minTextSize) {
        mMinTextSize = minTextSize;
        adjustTextSize();
    }

    private void adjustTextSize() {
        if (!mInitializedDimens) {
            return;
        }
        int startSize = (int) mMinTextSize;
        int heightLimit = getMeasuredHeight() - getCompoundPaddingBottom()
                - getCompoundPaddingTop();
        mWidthLimit = getMeasuredWidth() - getCompoundPaddingLeft()
                - getCompoundPaddingRight();
        mAvailableSpaceRect.right = mWidthLimit;
        mAvailableSpaceRect.bottom = heightLimit;
        super.setTextSize(
                TypedValue.COMPLEX_UNIT_PX,
                efficientTextSizeSearch(startSize, (int) mMaxTextSize,
                        mSizeTester, mAvailableSpaceRect));
    }

    private final SizeTester mSizeTester = new SizeTester() {
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
        @Override
        public int onTestSize(int suggestedSize, RectF availableSPace) {
            mPaint.setTextSize(suggestedSize);
            String text = getTransformedText();
            boolean singleline = getMaxLines() == 1;
            if (singleline) {
                mTextRect.bottom = mPaint.getFontSpacing();
                mTextRect.right = mPaint.measureText(text);
            } else {
                StaticLayout layout = new StaticLayout(text, mPaint,
                        mWidthLimit, Alignment.ALIGN_NORMAL, mSpacingMult,
                        mSpacingAdd, true);
                // return early if we have more lines
                if (getMaxLines() != NO_LINE_LIMIT
                        && layout.getLineCount() > getMaxLines()) {
                    return 1;
                }
                mTextRect.bottom = layout.getHeight();
                int maxWidth = -1;
                for (int i = 0; i < layout.getLineCount(); i++) {
                    if (maxWidth < layout.getLineWidth(i)) {
                        maxWidth = (int) layout.getLineWidth(i);
                    }
                }
                mTextRect.right = maxWidth;
            }

            mTextRect.offsetTo(0, 0);
            if (availableSPace.contains(mTextRect)) {
                // may be too small, don't worry we will find the best match
                return -1;
            } else {
                // too big
                return 1;
            }
        }
    };

    /**
     * Enables or disables size caching, enabling it will improve performance
     * where you are animating a value inside TextView. This stores the font
     * size against getText().length() Be careful though while enabling it as 0
     * takes more space than 1 on some fonts and so on.
     *
     * @param enable
     *            enable font size caching
     */
    public void enableSizeCache(boolean enable) {
        mEnableSizeCache = enable;
        mTextCachedSizes.clear();
        adjustTextSize();
    }

    private int efficientTextSizeSearch(int start, int end,
                                        SizeTester sizeTester, RectF availableSpace) {
        if (!mEnableSizeCache) {
            return binarySearch(start, end, sizeTester, availableSpace);
        }
        int key = getText().toString().length();
        int size = mTextCachedSizes.get(key);
        if (size != 0) {
            return size;
        }
        size = binarySearch(start, end, sizeTester, availableSpace);
        mTextCachedSizes.put(key, size);
        return size;
    }

    private static int binarySearch(int start, int end, SizeTester sizeTester,
                                    RectF availableSpace) {
        int lastBest = start;
        int lo = start;
        int hi = end - 1;
        int mid;
        while (lo <= hi) {
            mid = (lo + hi) >>> 1;
            int midValCmp = sizeTester.onTestSize(mid, availableSpace);
            if (midValCmp < 0) {
                lastBest = lo;
                lo = mid + 1;
            } else if (midValCmp > 0) {
                hi = mid - 1;
                lastBest = hi;
            } else {
                return mid;
            }
        }
        // make sure to return last best
        // this is what should always be returned
        return lastBest;

    }

    @Override
    protected void onTextChanged(final CharSequence text, final int start,
                                 final int before, final int after) {
        super.onTextChanged(text, start, before, after);
        adjustTextSize();
    }

    @Override
    protected void onSizeChanged(int width, int height, int oldwidth,
                                 int oldheight) {
        mInitializedDimens = true;
        mTextCachedSizes.clear();
        super.onSizeChanged(width, height, oldwidth, oldheight);
        if (width != oldwidth || height != oldheight) {
            adjustTextSize();
        }
    }

    private String getTransformedText() {
        CharSequence text = getText();
        if (text != null) {
            TransformationMethod transformationMethod = getTransformationMethod();
            if (transformationMethod != null) {
                text = transformationMethod.getTransformation(text, this);
            }
        }
        return text == null ? null : text.toString();
    }
}

【讨论】:

  • developer.android.com/guide/topics/ui/look-and-feel/… 和你的AutoResizeTextView 有什么区别?
  • @NatigBabayev 这个类可以用于任何安卓版本。正如您的链接所说,不仅是 Android 8+
  • Link 还指出:“支持库 26.0 完全支持在运行 Android 8.0(API 级别 26)之前的 Android 版本的设备上自动调整 TextView 功能。该库提供对 Android 4.0(API 级别)的支持14) 及更高版本。android.support.v4.widget 包包含 TextViewCompat 类以向后兼容的方式访问功能。因此,基本上,它也可以在 Android 8 下运行。
  • @ChristosThemelis 但如前所述,我需要在所有设备上使用完全相同大小的文本,而不是根据可用空间自动调整大小。
  • @Sid 我以为你想要相同的比例。我的错。尝试使用“px”而不是“sp”
【解决方案3】:

您需要使用dimens才能理解,请访问以下链接:

欲了解更多详情,请访问 Dimens

还请看以下问题的答案: How to use dimens.xml

【讨论】:

  • 感谢您的链接。但是从这些链接中,我得出结论,使用 dp 应该给我完全相同大小的文本,并且在 sp 的情况下,文本大小可能会根据从 android 设备设置中选择的字体大小而改变。正如我所提到的,我已经使用了 dp 和 sp,并且在不同的设备上获得了不同的文本大小。如果我错了,请纠正我。
【解决方案4】:

尝试不同的维度

创建文件dimens.xml(sw-320dp-xhdpi)

<resources>
    <dimen name="textSize">16sp</dimen>
</resources>

创建文件dimens.xml(sw-320dp-xxhdpi)

 <resources>
         <dimen name="textSize">14sp</dimen>
  </resources>

根据需要调整 textSize

【讨论】:

  • @Sid 你试过这个解决方案吗?
【解决方案5】:

这是我项目的一部分,它根据屏幕大小调整文本大小。 这是你想要的吗?

double height;
double width = parent.getMeasuredWidth();

boolean isLandscape;
if ( getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT ) {
    isLandscape = false;
    height = parent.getMeasuredHeight() / 3;
    width = width + (parent.getPaddingLeft() + parent.getPaddingRight());
} else {
    isLandscape = true;
    height = parent.getMeasuredHeight() / 2;
    width = parent.getMeasuredWidth() / 2;
    width = width + ((parent.getPaddingLeft() + parent.getPaddingRight()) / 2);
}       

height = height + (parent.getPaddingTop() + parent.getPaddingBottom());

view.setMinimumHeight((int) Math.round(height));

double h = height / 100;
double w = width / 100; 

if ( isLandscape ) {
    textViewService.setX((int) Math.round(w * 24));
    textViewService.setTextSize(TypedValue.COMPLEX_UNIT_PX, (int) Math.round(16 * h));
} else {
    textViewService.setX((int) Math.round(w * 23));
    textViewService.setTextSize(TypedValue.COMPLEX_UNIT_PX, (int) Math.round(18 * h));
}

【讨论】:

    猜你喜欢
    • 2014-10-15
    • 2018-06-09
    • 2012-10-28
    • 2016-05-25
    • 2012-03-17
    • 2013-07-23
    • 2019-01-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多