【问题标题】:android canvas drawText set font size from width?android canvas drawText从宽度设置字体大小?
【发布时间】:2012-08-23 09:17:15
【问题描述】:

我想使用.drawtext在一定宽度的canvas上绘制文本

例如,无论输入文本是什么,文本的宽度都应始终为400px

如果输入文本较长,则会减小字体大小,如果输入文本较短,则会相应增加字体大小。

【问题讨论】:

    标签: java android android-canvas


    【解决方案1】:

    Michael Scheper's solution 看起来不错,但它对我不起作用,我需要获得可以在我的视图中绘制的最大文本大小,但这种方法取决于您设置的第一个文本大小,每次设置不同的尺寸你会得到不同的结果,不能说它在每种情况下都是正确的答案。

    所以我尝试了另一种方法:

    private float calculateMaxTextSize(String text, Paint paint, int maxWidth, int maxHeight) {
        if (text == null || paint == null) return 0;
        Rect bound = new Rect();
        float size = 1.0f;
        float step= 1.0f;    
        while (true) {
            paint.getTextBounds(text, 0, text.length(), bound);
            if (bound.width() < maxWidth && bound.height() < maxHeight) {
                size += step;
                paint.setTextSize(size);
            } else {
                return size - step;
            }
        }
    }
    

    这很简单,我增加文本大小,直到文本矩形绑定尺寸足够接近 maxWidthmaxHeight,要减少循环重复,只需将 step 更改为更大的值(准确性与速度),也许这不是实现这一目标的最佳方式,但它确实有效。

    【讨论】:

    • 这与@slybloty 的回答有同样的效率问题。我也不明白您在我的解决方案中遇到的问题;关键是你会得到不同宽度的不同文本大小。您能否发表评论并举例说明它没有返回正确大小的参数?
    • 老实说,您的解决方案有效,但不是我预期的方式,如果我没记错float desiredTextSize = testTextSize * desiredWidth / bounds.width(); 返回一个可接受的值,但不一定是最大尺寸,毫无疑问,您的解决方案更有效,但我认为结果非常依赖desiredWidth,并不完全符合我的需要,问候
    • 所以你想适应最大高度和最大宽度?试试float desiredTextSize = testTextSize * Math.min(desiredWidth / bounds.width(), desiredHeight / bounds.height())。无论如何,请注意解决方案中的整数;它们会导致你的浮点数只保存整数值,这可能不像你需要的那么精确。
    【解决方案2】:

    这里有一个更有效的方法:

    /**
     * Sets the text size for a Paint object so a given string of text will be a
     * given width.
     * 
     * @param paint
     *            the Paint to set the text size for
     * @param desiredWidth
     *            the desired width
     * @param text
     *            the text that should be that width
     */
    private static void setTextSizeForWidth(Paint paint, float desiredWidth,
            String text) {
    
        // Pick a reasonably large value for the test. Larger values produce
        // more accurate results, but may cause problems with hardware
        // acceleration. But there are workarounds for that, too; refer to
        // http://stackoverflow.com/questions/6253528/font-size-too-large-to-fit-in-cache
        final float testTextSize = 48f;
    
        // Get the bounds of the text, using our testTextSize.
        paint.setTextSize(testTextSize);
        Rect bounds = new Rect();
        paint.getTextBounds(text, 0, text.length(), bounds);
    
        // Calculate the desired size as a proportion of our testTextSize.
        float desiredTextSize = testTextSize * desiredWidth / bounds.width();
    
        // Set the paint for that size.
        paint.setTextSize(desiredTextSize);
    }
    

    然后,您需要做的就是setTextSizeForWidth(paint, 400, str);(400 是问题中的示例宽度)。

    为了提高效率,您可以将Rect 设为静态类成员,从而避免每次都对其进行实例化。但是,这可能会引入并发问题,并且可能会妨碍代码清晰。

    【讨论】:

    • 啊,糟了! :-) 很高兴它有所帮助。
    • 我能知道你是从哪里选择 400 的吗?因为我尝试了你的方法,但我的一些文字超出了画布,就像一两个字母。
    • 我尝试了bitmap.getwidth(),它更好,但仍然没有效率。
    • @Chisko:当然,而且自从我从 1997 年开始编写 Java 代码以来,我想这是合适的。 ☺ 当一个方法是static 时,无论有多少类实例,每个JVM 都只会有一个副本。但是对于非静态方法,类的每个实例都有一个副本,因此您可以拥有多个局部变量副本,并且我相信字节码本身也是如此。我承认这在你的 Android 应用程序中可能是相当学术的,如果你只是创建一个你放置这个代码的类的实例,但这是一个好习惯。我强烈推荐 Bloch 的书以获取更多信息。
    • 更直接地回答您的问题:还有谁会使用这种方法?类的其他实例。假设您编写了一个小部件并将setTextSizeForWidth 放入其中,您的应用程序具有三个这样的小部件。如果您的小部件的类使此方法成为静态,则将有一个副本。如果没有,那就是三个。三个副本一次只能使用一个,但是每次都会为两个floats分配新的内存,直到垃圾回收才会释放。同样,在这种情况下是次要的,但对于较大对象的较大集合,它很快就会导致问题。
    【解决方案3】:

    试试这个:

    /**
     * Retrieve the maximum text size to fit in a given width.
     * @param str (String): Text to check for size.
     * @param maxWidth (float): Maximum allowed width.
     * @return (int): The desired text size.
     */
    private int determineMaxTextSize(String str, float maxWidth)
    {
        int size = 0;       
        Paint paint = new Paint();
    
        do {
            paint.setTextSize(++ size);
        } while(paint.measureText(str) < maxWidth);
    
        return size;
    } //End getMaxTextSize()
    

    【讨论】:

    • 只是出于好奇,你为什么返回size / 2?猜猜我现在想不出一个很好的理由,但size - 1 对我来说更有意义:/
    • 说实话我记不太清了。我知道我尝试使用 -1 并认为我没有得到我想要的。
    • 这不起作用..我正在做的是将 maxwidth 设置为我手机的屏幕宽度为 560 像素,但是当我设置它时它不适合屏幕,它比这大得多。并且字体大小没有相应改变。
    • 哦,这工作现在我正在传递不同的字符串值并绘制不同的值。我的错。它适用于size 而不是size/2 请编辑您的答案。
    • 这里有一个错误。您不处理 str 没有字符或只有空格的情况。因为它,你永远迭代。将此添加为第一行...if (str == null || str.trim().length() == 0) return 0;
    猜你喜欢
    • 1970-01-01
    • 2013-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-09
    • 1970-01-01
    • 2013-03-05
    相关资源
    最近更新 更多