在 ListView 中修改文本大小时更新项目高度

Posted

技术标签:

【中文标题】在 ListView 中修改文本大小时更新项目高度【英文标题】:Update item height when modifying text size in ListView 【发布时间】:2012-09-24 23:47:26 【问题描述】:

我有一个ListView 和一个ArrayAdapter,它使用类似于simple_list_item_1 的XML 布局来扩充其内容。我在应用程序菜单中有两个选项来增加/减小文本大小。我设法通过覆盖ArrayAdaptergetView 函数来修改ListViewTextViews 的文本大小。像这样的:

adapter = new ArrayAdapter<Line>(MyActivity.this, R.layout.line_list, lines)
    @Override
    public View getView(int position, View convertView, ViewGroup parent) 
        TextView textView = (TextView) super.getView(position, convertView, parent);
        textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, fontSizeDp + zoom);
        return textView;
    
;
listView.setAdapter(adapter);

菜单选项更改缩放值并调用adapter.notifyDataSetChanged(); 以使适配器更改文本大小。 在那之前一切正常。

问题是当我将文本大小减小太多时,每个 TextView 的高度都没有包裹其内容。 也就是说,ListView 项目太高了。当我增加文本大小时,项目高度没有问题。

如果我调用 super.getView(position, convertView, parent);在 convertView 为空的情况下,我使适配器始终膨胀。在这种情况下,由于高度被换行,因此减小文本大小可以正常工作。但是,我导致工作量过大,我不希望这样。

我尝试使列表视图和/或文本视图无效或强制布局,但没有成功。

感谢任何帮助

编辑:这是 line_list 布局:

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/text1"
android:layout_
android:layout_
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="@dimen/lineTextSize"
android:gravity="center"
android:paddingLeft="6dip"
android:paddingRight="6dip" />

lineTextSize 默认为 22dp,大为 40dp

编辑 2: 看起来像这样

而不是这个屏幕:

【问题讨论】:

你能发布R.layout.line_list文件吗? 我之前测试过你的代码,它的工作原理应该是这样,TextView 正在包装TextView 的内容,无论我如何修改大小。在我的测试中,fontSizeDp 是一个常数,比如 17,我只是在onOptionsItemSelected 回调中增加/减少了zoom 变量,然后在适配器上调用notifyDataSetChanged。怎么修改大小? 是的,就这样。在 onOptionsItemSelected 我更改缩放值,然后调用 adapter.notifyDataSetChanged()。我在平板电脑上测试 fontSizeDp 的初始值为 40。当我在某个点缩小时,线条的高度不再更新并且仍然太高 如果将dp 单位替换为sp 单位(就像您从一开始就应该做的那样)字体大小,您会看到相同的行为吗? 是的,我刚刚测试过,但行为是一样的 【参考方案1】:

我发现 here 这是 Android 3.1+ 的一个已知错误

解决办法是像这样添加一个字符串

String ZERO_WIDTH_SPACE = "\u200b";

到 TextViews 的文本。所以,适配器正确的getView函数是:

@Override
public View getView(int position, View convertView, ViewGroup parent) 
    TextView textView = (TextView) super.getView(position, convertView, parent);
    textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, fontSizeDp + zoom);
    textView.setText(textView.getText() + ZERO_WIDTH_SPACE);
    return textView;

【讨论】:

【参考方案2】:

我设法测试了代码,似乎ListView 不想在Honeycomb 及更高版本中更新行高(减小字体大小时)。解决您的问题的一个简单方法是实现适配器的 getView 方法,如果您的字体减少和/或回收的视图不适合当前字体大小,它将重新创建行视图.这是基于您的观察,将 convertView 设置为 null 的强制 super.getView() 方法有效,因为 ListView 将始终从头开始构建新行。我的代码正在做类似的事情,但性能要好得多:

public class CustomAdapter extends ArrayAdapter<String> 

    private LayoutInflater mInflater;
    private int mResource;

    public CustomAdapter(Context context, int resource, String[] objects) 
        super(context, resource, objects);
        mInflater = LayoutInflater.from(context);
        mResource = resource;
    

    @Override
    public View getView(int position, View convertView, ViewGroup parent) 
        if (convertView == null) 
            convertView = mInflater.inflate(mResource, parent, false);
         else 
            if (mZoom - mOldZoom < 0) 
                Integer cacheZoom = (Integer) convertView.getTag();
                if (cacheZoom == null || cacheZoom.intValue() != mZoom) 
                    convertView = mInflater.inflate(mResource, parent, false);
                    convertView.setTag(mZoom);
                
            
        
        ((TextView) convertView).setTextSize(
                    TypedValue.COMPLEX_UNIT_DIP, 40 + mZoom);
        ((TextView) convertView).setText(getItem(position));
        return convertView;
    


mZoommOldZoom 是用于查看字体前进方向的新旧缩放值的变量:

@Override
public boolean onOptionsItemSelected(MenuItem item) 
    switch (item.getItemId()) 
    case R.id.item1:
        mOldZoom = mZoom;
        mZoom += 2;
        mAdapter.notifyDataSetChanged();
        break;
    case R.id.item2:
        mOldZoom = mZoom;
        mZoom -= 2;
        mAdapter.notifyDataSetChanged();
        break;
    
    return super.onOptionsItemSelected(item);

【讨论】:

什么是 R.layout.adapters_fontchange?如果与 R.layout.line_list 的布局相同,则问题仍然存在(我正在 ICS 上测试)。 @Ivan R.layout.adapters_fontchange 是我为您的布局文件命名的(布局相同)。我已经在ICS 上进行了测试,实际上它不起作用,因为我的初始逻辑不正确。我从我的答案中编辑了代码,当我在 2.2 设备和两个模拟器上用Honeycomb(API 13) + ICS(API 14) 测试它时,它应该可以工作。看看它的表现。 它有效,谢谢!只有一个错误,但可以通过删除 'if (mZoom != 0)' 来修复,因为如果在 mZoom 为 0 时减少一然后增加一,则未设置大小并且文本行为磨损,因为在文本大小之间发生冲突38 和 40。 @Ivan 你是对的,当我测试时,我在不止一个步骤中增加/减少了字体并且没有注意到它。

以上是关于在 ListView 中修改文本大小时更新项目高度的主要内容,如果未能解决你的问题,请参考以下文章

用动画展开 ListView 项

Textview 文本大小应为 editText 文本大小并显示在 listview 中

在ListView中动态更新列表元素高度

过滤后ListView不更新

ScrollView中嵌套ListView时,listview高度显示的问题

根据里面的多行文本视图动态设置 ListView 高度