如何解决sdk 17和18之间列表项布局行为的变化?

时间:2014-01-29 20:52:51

标签: android android-layout android-listview android-linearlayout android-compatibility

我创建了一个简单的应用程序来说明在包含在SDK 17和SDK 18之间的RelativeLayout中时LinearLayout的行为方式的变化。首先,截图:

当targetSdkVersion为“17”时:

enter image description here

当targetSdkVersion为“18”时:

enter image description here

此活动的布局为:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#00ffff"
    android:orientation="vertical" >

    <include layout="@layout/test_list_item"/>

    <ListView
        android:id="@+id/listview"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:overScrollMode="never"
        android:scrollingCache="false" >
    </ListView>

</LinearLayout>

text_list_item.xml是:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#ff0000" >

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:background="#ffff00"
        android:padding="10dp"
        android:text="foobar"
        android:textColor="#000000" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignBottom="@id/text"
        android:layout_alignTop="@id/text"
        android:background="#00ff00"
        android:orientation="horizontal"
        android:weightSum="1.0" >

        <View
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="0.5"
            android:background="#0000ff" />
    </LinearLayout>

</RelativeLayout>

活动的onCreate()如下所示:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_test);
    findViewById(R.id.text).bringToFront();
    final ListView mListView = (ListView) findViewById(R.id.listview);
    mListView.setAdapter(new TestAdapter());
}

TestAdapter看起来像这样:

public class TestAdapter extends BaseAdapter {

    private static final int COUNT = 3;

    @Override
    public int getCount() {
        return COUNT;
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public boolean areAllItemsEnabled() {
        return true;
    }

    @Override
    public boolean isEnabled(int position) {
        return false;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.test_list_item, null);
        view.findViewById(R.id.text).bringToFront();
        return view;
    }

当target = 17时,LinearLayout的子视图在ListView内部和ListView外部时,可以正确调整为可用宽度的50%。当target = 18时,当用作列表项的布局时,它不会调整大小。在这种情况下,它的宽度保持在“0dp”并且永远不会调整大小。

理想情况下,我想针对SDK 19.但是,为了做到这一点,我要以某种方式适应这种行为变化。关于如何实现这一点的任何想法?

顺便说一句,有些理由说明布局既复杂又“怪异”;我意识到有更直接的方法来实现这种特殊的视觉效果。

修改

为了更多地了解我为什么使用这种病态布局:它用于“仪表”。使用ScaleAnimation拉伸或缩小LinearLayout内的视图,使其占据总可用宽度的所需百分比。令我觉得棘手的是我需要在仪表顶部叠加文字,我希望测量仪的高度由文字确定。

因此,外部RelativeLayout应该“与其父级一样宽”,但只“与它包含的TextView一样高”。 RelativeLayout中的LinearLayout应该与其父级一样宽和高。 LinearLayout中的View应该与包含它的LinearLayout一样高,但只有一半宽。

当布局未用作ListView项目的内容时,这正是我在SDK 18+ 中定位SDK 17 和/或时所获得的行为。

修改

发布在开发者小组:

https://groups.google.com/forum/#!msg/android-developers/KuoY5Tklyms/TbNq6ndD_PwJ

3 个答案:

答案 0 :(得分:4)

更改

final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.test_list_item, null);

为:

final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.test_list_item, parent, false);

我认为你会有更好的运气。


<强>更新

嗯,这是我可以告诉你的。

如果启动层次结构视图,您将看到在“ListView内部”场景中提供蓝色背景的View高度为0。宽度是正确的,这表明问题与重量无关,而不是问题的其他答案。

如果你看一下the source code to RelativeLayout,他们确实增加了一些聪明的东西来改变android:targetSdkVersion 17和18+之间分界线的行为。我的猜测是,你在某个与mAllowBrokenMeasureSpecs容器相关的场景中绊倒了ListView,但这只是猜测。我有足够的时间来处理容器的所有布局/测量内容,因为它是一个简单的容器,我写的,当我有一整晚的睡眠时 - 理解RelativeLayout有限的睡眠是超出我的能力。而且我已经戳了戳你的样本,尝试了各种各样的事情,看看他们是否能解决问题,但没有结果。

关于你在我开玩笑时发布的编辑内容:

  • 原则上,您不需要基本布局为RelativeLayoutFrameLayout应该也可以正常工作,因为你需要它做的就是能够在Z轴上堆叠东西并且能够使你的标签居中。话虽这么说,当我沿着这条路走下去时,我的结果甚至更奇怪,虽然这些结果似乎与targetSdkVersion无关,所以我可能刚刚搞砸了某个地方

  • 即使您坚持使用RelativeLayout,也不应该使用LinearLayout。在运行时,您知道您的宽度,因此您应该设置仪表宽度的动画,而不是它的重量。因此,只需将View放在RelativeLayout(或FrameLayout)就足够了。

但我很乐意同意这是奇怪的行为。

答案 1 :(得分:1)

看起来因为它只是一个视图而且不需要渲染任何东西,为了一些优化,我们跳过了测量方法。将视图更改为TextView并设置一些文本,您将看到它确实按预期显示。我确实理解LinearLayout以不同的方式呈现视图(不确定这是正确的还是ListView是正确的)

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ff0000" >

<TextView
    android:id="@+id/text"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:background="#ffff00"
    android:padding="10dp"
    android:text="foobar"
    android:textColor="#000000" />

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_alignBottom="@id/text"
    android:layout_alignTop="@id/text"
    android:background="#00ff00"
    android:orientation="horizontal"
    android:weightSum="1.0" >

    <TextView
        android:id="@+id/testView"
        android:layout_width="0dp"
        android:layout_height="fill_parent"
        android:layout_weight="0.5"
        android:background="#0000ff"
        android:singleLine="false" />
</LinearLayout>

 @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.text_list_item, null);

        view.findViewById(R.id.text).bringToFront();
        TextView testView = (TextView)view.findViewById(R.id.testView);
        testView.setText("some test text for viewNo:"+String.valueOf(position));

        return view;
    }

enter image description here

答案 2 :(得分:0)

我认为layout_weight(尝试使用int number&gt; = 0)的方式已经改变了。与android:layout_width="0dp"(尝试match_parent)结合使用会更加不稳定。

weight参数的另一个问题是,某些设备处理它与其他设备不同。

在gerneral我建议只使用LinearLayouts,如果可能的话没有重量。 您可以使用gravity(例如gravity="center"),layout_gravitypaddingmargin执行相同的操作,但保存即可。

编辑 - example1:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#ff0000" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#00ff00"
        android:orientation="horizontal">

        <View
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#0000ff" />

        <TextView
            android:id="@+id/text"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:background="#ffff00"
            android:padding="10dp"
            android:text="foobar"
            android:textColor="#000000" />

        <View
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="#00ff00" />
    </LinearLayout>

</LinearLayout>

例2:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#ff0000" >

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:background="#ffff00"
        android:padding="10dp"
        android:text="foobar"
        android:textColor="#000000" />

</LinearLayout>