有换行时切换软键盘,TextView宽度抖动问题

浸淫Android这么多年,收敛君表示第一次碰到这么基础而又棘手的问题。

  • 以下分析基于api23
  • 4.4/5.0系统都有该问题

情景再现

MainActivity

public class TestListActivity extends Activity {
    private ListView vList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_b2);

        List> data = new ArrayList<>();
        Map map = new HashMap<>();
        map.put("title", "uuuuu\nuu");
        data.add(map);

        vList = (ListView) findViewById(R.id.list);
        SimpleAdapter adapter = new SimpleAdapter(this,
                data,
                R.layout.item_list,
                new String[]{"title"},
                new int[]{android.R.id.text1}
        );
        vList.setAdapter(adapter);
    }
}

activity_main.xml




    

    

item.xml




    

这个简单的显示一个ListView的小例子,初学Java时恐怕都写过。我们运行看看效果,为了看的明白,打开显示布局边界开关:


有换行时切换软键盘,TextView宽度抖动问题_第1张图片
1.png

现在让我们点击EditText,打开软键盘:


有换行时切换软键盘,TextView宽度抖动问题_第2张图片
2.png

这个小问题在这个例子中的表现还算温和,TextView的宽度只会抖动一次。但是在收敛君的工作中,每次切换软键盘都会出现!快跑!boss要发飙了!!!

刨根问底

这个小问题陪伴我两天两夜,其中的辛酸就不啰嗦了,且看把它扒光的结果吧。
先来看一段TextView.onMeasure方法的片段:

//……此处省略几行
Layout mLayout = getLayout();
TextUtils.TruncateAt mEllipsize = getEllipsize();
 if (mLayout != null && mEllipsize == null) {
     des = desired(mLayout);
 }
//……此处省略若干行
if (des < 0) {
   des = (int) Math.ceil(Layout.getDesiredWidth(mTransformed, mTextPaint));
}

首次执行onMeasure方法时,mLayout==null,此时des从第二段代码取值;当切换软键盘,页面重新布局,再次调用onMeasure方法时,mLayout!=null,此时des从第一段代码取值。而des就是宽度的值。
讲道理两段代码获取的尺寸应该是一样的,BUT!!!第一段代码会计算\n也就是换行符的宽度,第二段代码不会。

这也就是今天收敛君想分享的Android系统的BUG


了解了问题的根源,解决起来也就方便了。只要每次都从第二段代码取值就可以了。别问我为什么不从第一段代码取值,我肯定不会告诉你是因为第一次mLayout==null
简单的修改方法是每次执行onMeasure方法时,都通过反射把mLayout置为null

今天记录这么多,有什么错误的地方还请各位大大指正!

今天受同事提醒,因为mEllipsize == null时才会执行第一段代码进行测量,所以直接给TextView设置ellipsize属性也可以解决。不过常在河边走,哪有不湿鞋,总有遗忘的时候,想一劳永逸的话,还是继承一下TextView吧,然后在内部设置ellipsize属性。

你可能感兴趣的:(有换行时切换软键盘,TextView宽度抖动问题)