onMeasure簡單方法 完美解決ListView與ScollView衝突問題!

許佳佳233發表於2016-05-22

近期做專案碰到ScrollView與Listview衝突的情況,檢視了網上一些解決listview和scollView的衝突的方法,最終選擇了重寫onMeasure的方法來解決這個問題。

在此對各種方法個人做一個總結評價。


主要的方法有四種

1、手動設定ListView高度(比如把高度設定為200dp)

評價:特別簡單無腦,但是大大提高了程式碼的耦合性,比較適合“圖方便”的新手。


2、使用單個ListView的addHeaderView()方法(給listview設定頂部固定的一個view)

評價:比較簡便的方法,但是如果頂部佈局需要監聽滑動事件,也不可取。


3、使用LinearLayout取代ListView(重寫LinearLayout)

評價:完全可行,但是讓一個LinearLayout來實現Listview的功能真的覺得好奇怪啊。


4、重寫ListView的onMeasure()

評價:只需要寫幾行程式碼,輕鬆解決衝突問題。不僅降低程式碼耦合性,而且簡單。唯一的缺點,可能就是理解需要花比較多的時間。



最終效果:(左圖為改之前,右圖為改之後,原始碼在文章結尾

  


主要實現程式碼:

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
                MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec);
    }


如上所示,使用expandSpec代替heightMeasureSpec。很容易理解,就是我們改變了的listview的高度獲取方式

那麼MeasureSpec.makeMeasureSpec(int size,int mode)中的兩個引數又是什麼呢?


size:表示父佈局提供給你的大小參考

mode:表示規格,有EXACTLY、AT_MOST、UNSPECIFIED三種。


那麼我們程式碼中填的兩個值又分別表示什麼呢?

Integer.MAX_VALUE >> 2:表示父佈局給的參考的大小無限大。(listview無邊界)

MeasureSpec.AT_MOST:表示根據佈局的大小來確定listview最終的高度,也就是有多少內容就顯示多高。


(此處三種方式解釋引用郭霖前輩文章中部分內容)

1. EXACTLY

表示父檢視希望子檢視的大小應該是由specSize的值來決定的,系統預設會按照這個規則來設定子檢視的大小,開發人員當然也可以按照自己的意願設定成任意的大小。

2. AT_MOST

表示子檢視最多隻能是specSize中指定的大小,開發人員應該儘可能小得去設定這個檢視,並且保證不會超過specSize。系統預設會按照這個規則來設定子檢視的大小,開發人員當然也可以按照自己的意願設定成任意的大小。

3. UNSPECIFIED

表示開發人員可以將檢視按照自己的意願設定成任意的大小,沒有任何限制。這種情況比較少見,不太會用到。


倘若讀者還有疑問或者對View的繪製過程比較感興趣,可以參考郭霖前輩的部落格:

Android檢視繪製流程完全解析,帶你一步步深入瞭解View(二)

http://blog.csdn.net/guolin_blog/article/details/16330267



MainActivity:

package com.example.double2.listviewscollview;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ArrayAdapter;

public class MainActivity extends AppCompatActivity {

    private MyListView mMyListView;
    final private String[] test = {
            "first", "second", "third", "fourth", "fifth",
            "first", "second", "third", "fourth", "fifth"};

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

        initListView();
    }

    private void initListView() {
        mMyListView = (MyListView) findViewById(R.id.lv_main);

        mMyListView.setAdapter(
                new ArrayAdapter<String>(
                        this, android.R.layout.simple_list_item_1, test));
    }
}


MyListView:

package com.example.double2.listviewscollview;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ListView;

/**
 * 專案名稱:ListViewScollView
 * 建立人:Double2號
 * 建立時間:2016/5/22 19:01
 * 修改備註:
 */
public class MyListView extends ListView {

    public MyListView(Context context) {
        super(context);
    }

    public MyListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //此處是程式碼的關鍵
        //MeasureSpec.AT_MOST的意思就是wrap_content
        //Integer.MAX_VALUE >> 2 是使用最大值的意思,也就表示的無邊界模式
        //Integer.MAX_VALUE >> 2 此處表示是福佈局能夠給他提供的大小
        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
                MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec);
    }
}


activity_main:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        >

        <View
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:background="@android:color/holo_green_light"
            />

        <com.example.double2.listviewscollview.MyListView
            android:id="@+id/lv_main"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </LinearLayout>
</ScrollView>


原始碼地址:http://download.csdn.net/detail/double2hao/9527896

相關文章