如何在应用小部件中的TextView中根据小部件大小调整文本大小?

6
我已经编写了一段时间的Android程序,但这真让我困惑。我有一个简单的小部件,其中包含一个文本视图。我希望在用户调整小部件大小时,文本视图内的文本字体大小能够缩放,从而使应用程序更改大小,使文本变大。我尝试了几种解决方案,但都失败了:
1. 只是使用“sp”(比例像素)单位作为字体大小 - 当小部件大小发生变化时,这不会缩放文本(我也没有指望它!)。
2. 使用自己的TextView扩展onSizeChanged方法。但是,在小部件中无法拥有基本UI类的派生类(文档也说明了这一点)。
由于没有甚至可以获取当前小部件大小的方法,所以我现在陷入了困境。是的,我知道一种解决方案是创建不同版本的小部件,如1x4和2x4等,但肯定还有另一种方法吧?欢迎任何想法!

作为对后来的读者的一点提示,我可以说从API 16+开始是可以实现的。您可以在小部件中覆盖一个回调方法:onAppWidgetOptionsChanged,并从该方法中获取最大宽度和高度(如下面所指出的)。但在API 16以下,调整大小并不是很容易实现。 - zaifrun
4个回答

4
无法根据父级大小自动缩放TextView文本。解决方法是覆盖TextView的onDraw方法并手动实现缩放。

关于appwidget:由于其旨在与ListView和GridView容器一起使用,因此无法检索可调整大小的appwidget的当前大小。这些容器将自动管理内容的缩放和间距,并在内容无法适应appwidget的当前大小时使它们可滚动。
如果未使用ListView或GridView,则似乎最好的“缩放”appwidget组件的方法是使用不同的非可调整大小的appwidget。

就像我说的,通过扩展TextView并重写onDraw方法的解决方法对于小部件是不起作用的,文档也有相应说明。也许我可以将TextView放在一个GridView中,这样可行吗? - zaifrun
一个带有一个行和一列的'GridView',其中TextView设置为fill_parent可能会起作用。如果不起作用,您可能需要使用不同大小的不可调整大小的appwidgets。 - Leon Lucardie
我也无法让使用GridView的方法奏效。我猜想唯一的方法就是使用几个具有不同不可调整大小的AppWidget(这似乎也是其他人采用的方法)。希望至少其他人可以从我的问题中受益并节省时间! - zaifrun

3

结合上面的答案和来自https://dev59.com/s3E85IYBdhLWcg3wx2j2#7875656的可爱代码片段,我按照以下方式使其正常工作:

*注意:我有一个带文本的圆形按钮,所以我只需要最小的尺寸。

@Override
public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions){

    super.onAppWidgetOptionsChanged(context,appWidgetManager,appWidgetId,newOptions);

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
        int maxWidth = newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH);
        int maxHeight = newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT);

        int size = Math.min(maxHeight,maxWidth);
        int pxSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,size,context.getResources().getDisplayMetrics());

        RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.widget_button);
        float newSize = refitText(context.getString(R.string.button_text),pxSize);

        remoteViews.setTextViewTextSize(R.id.widget_text, TypedValue.COMPLEX_UNIT_PX,newSize);

        appWidgetManager.updateAppWidget(appWidgetId,remoteViews);
    }

}

private float refitText(String text, int textWidth)
{
    if (textWidth <= 0)
        return 0;

    float hi = 100;
    float lo = 2;
    final float threshold = 0.5f; // How close we have to be

    Paint testPaint = new Paint();

    while((hi - lo) > threshold) {
        float size = (hi+lo)/2;
        testPaint.setTextSize(size);
        if(testPaint.measureText(text) >= textWidth)
            hi = size; // too big
        else
            lo = size; // too small
    }
    // Use lo so that we undershoot rather than overshoot
    return lo;
}

3

1
这可以正常工作,虽然不同的启动器会传递略有不同的值(dp vs. px),因此正确获得它有些混乱。 - Nikolay Elenkov

1
这是一种原始的方法,但它能够工作:

AppWidgetManager manager = AppWidgetManager.getInstance(this);
ComponentName thisWidget = new ComponentName(this, AppWidget.class);
int[] widgetId = manager.getAppWidgetIds(thisWidget);
Bundle options;
options = manager.getAppWidgetOptions(widgetIds[1]);
int minWidth = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
int maxWidth = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH);
int minHeight = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);
int maxHeight = options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT);
int maxtextLen = (maxWidth / currentTextSize) * (maxHeight / currentTextSize);

Boolean isFit = maxtextLen > textInWidgetTextView.length();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接