美文网首页Android软键盘Android知识Android进阶之旅
有换行时切换软键盘,TextView宽度抖动问题

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

作者: sollian | 来源:发表于2017-05-12 19:31 被阅读114次

    浸淫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<Map<String, CharSequence>> data = new ArrayList<>();
            Map<String, CharSequence> 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

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/ll"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="demo.com.demoapp.TestListActivity">
    
        <ListView
            android:id="@+id/list"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:layout_weight="1" />
    
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>
    

    item.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical">
    
        <TextView
            android:id="@android:id/text1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </LinearLayout>
    

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


    1.png

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


    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宽度抖动问题

        本文链接:https://www.haomeiwen.com/subject/oohtxxtx.html