Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 解決GridView內容顯示不全問題

解決GridView內容顯示不全問題

編輯:關於Android編程

我用GridView來顯示一些字符串,而字符串的長度是不固定的,然後就遇到問題了:有時字符重疊,有時顯示不全,有時兩種問題同時出現。見下圖:

這裡寫圖片描述

圖一 GridView顯示重疊、顯示不全

這到底是什麼情況,該怎麼解決呢?
第一反應是上網查找方案,有兩種方案:
1, 自定義GridView,重寫onMeasure,如下:

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

經過測試,不能解決問題。

2, 先在Adapter中獲取GridView的高度,然後均分給每排:
代碼如下:

        int height = mGv.getHeight();  
        int width = mGv.getWidth();         
        //得到GridView每一項的高度與寬度       
if(height>0){
            GridView.LayoutParams params = new GridView.LayoutParams(width / 3,  height /2);  
//針對我的情況,3列2排,直接寫數測試
            //設置每一行的高度和寬度
            view.setLayoutParams(params);
        }

發現有時能解決問題,有時不行。當然對於圖一中遇到的問題,也是不能解決的,但是情況有所變化,截圖如下:

這裡寫圖片描述

圖二 GridView顯示不全,不可滑動

可以看出,沒有重疊了,但是第一排的字,已經有丟失的情況發生了。第二排的也是丟失了,因為此時的GridView是不能滑動的。(圖一的情況,還可以滑動顯示全第二排的內容)

我的目標是兩排都能顯示全,而且不用滑動來進行顯示。那麼,該怎麼辦呢?既然沒有現成的解決方案,那就自己來研究下GridView的工作邏輯吧。

下面描述下我的測試環境,也就是問題現場:
主界面使用了一個GridView,裡面的子項內容是一個TextView,文本的內容是一項水果名,共有6種,分為2排3列顯示。

xml文件中,GridView的布局:

    

GridView子項的內容布局:




    

提供的數據如下:

    private void initFruits() {

        Log.i("MainActivity", "log: initFruits");

        Fruit banana = new Fruit("仙人蕉");
        fruitList.add(banana);

        Fruit apple = new Fruit("紅嘎拉蘋果");
        fruitList.add(apple);

        Fruit strawberry = new Fruit("玉麟草莓");
        fruitList.add(strawberry);

        Fruit pineapple = new Fruit("北界紅提葡萄");
        fruitList.add(pineapple);

        Fruit orange = new Fruit("褚橙");
        fruitList.add(orange);  

        Fruit watermelon = new Fruit("黑美人西瓜");
        fruitList.add(watermelon);

    } 

適配器裡面是這樣寫的:

public View getView(int position, View convertView, ViewGroup parent) {

        Fruit fruit = getItem(position);
        View view;
        ViewHolder viewHolder;
        TextView tv_record ;
        String strLog;

        if(convertView == null){        
            view = LayoutInflater.from(getContext()).inflate(resoureId, null);
            strLog = "log: new ViewHolder ";
            viewHolder = new ViewHolder();
            viewHolder.fruitName = (TextView) view.findViewById(R.id.fruit_name);
            view.setTag(viewHolder);            
            viewHolder.fruitName.setText(fruit.getName());          
        }
        else{
            strLog = "log: use old ViewHolder ";
            view = convertView;
            viewHolder = (ViewHolder)view.getTag();             
        }

        tv_record = viewHolder.fruitName;
        Log.i("FruitAdapter", strLog+" pos="+position+" fruitName=" + fruit.getName()+" mGv.getHeight="+mGv.getHeight());
        Log.i("FruitAdapter", "log: getView: lines="+tv_record.getLineCount() +" LineHeight="+ tv_record.getLineHeight()+" tv.height="+tv_record.getHeight());

        return view;
      }

我測試的主要方法,就是看getView()中的輸出信息。如下:

07-24 22:11:58.010: I/FruitAdapter(8061): log: new ViewHolder  pos=0 fruitName=仙人蕉 mGv.getHeight=0
07-24 22:11:58.010: I/FruitAdapter(8061): log: getView: lines=0 LineHeight=105 tv.height=0
07-24 22:11:58.030: I/FruitAdapter(8061): log: use old ViewHolder  pos=0 fruitName=仙人蕉 mGv.getHeight=0
07-24 22:11:58.030: I/FruitAdapter(8061): log: getView: lines=2 LineHeight=105 tv.height=0
07-24 22:11:58.060: I/FruitAdapter(8061): log: use old ViewHolder  pos=0 fruitName=仙人蕉 mGv.getHeight=458
07-24 22:11:58.060: I/FruitAdapter(8061): log: getView: lines=2 LineHeight=105 tv.height=0

我們可以看出,在getView()中,第一個位置的view會執行3次,

第一次,新建view,所有高度值都是0 ,除了字體的高度是105。
第二次,convertView已經存在了,我們看到lines=2,即此時已經根據文本內容計算出行數了,但是GridView的總高度仍然是0。
第三次,GridView的總高度已經有值了,但是TextView的高度仍然是0。

怎樣才能看到TextView的高度呢?
我有一次在調整文本初始化的順序時,畫面顯示不全,在滑動顯示時,看見了TextView的高度值不為0 ,此時界面如下:

這裡寫圖片描述

圖三 GridView顯示不全,可滑動顯示

Log如下:

07-25 21:54:05.760: I/FruitAdapter(28214): log: use old ViewHolder  pos=0 fruitName=褚橙 mGv.getHeight=248
07-25 21:54:05.760: I/FruitAdapter(28214): log: getView: lines=1 LineHeight=105 tv.height=124
07-25 21:54:05.760: I/FruitAdapter(28214): log: use old ViewHolder  pos=1 fruitName=玉麟草莓 mGv.getHeight=248
07-25 21:54:05.760: I/FruitAdapter(28214): log: getView: lines=2 LineHeight=105 tv.height=229

有了這些數據,就能做一些分析工作了:
例如內容為“褚橙”時,字符串沒有換行,字高105,TextView高度為124,則字與控件中還有空余為124-105=19。
對於“玉麟草莓”,字分2行,字高105,兩行為105*2=210,加上空余間隔為19,加起來是210+19=229,與日志中的值相符合。
此時GridView的高度為248,恰好是124的2倍。應該是通過內容的總個數計算出來的(後面的試驗用更豐富的數據支撐了這個判斷)。
在構建 FruitAdapter 時,已經通過輸入參數 fruitList,知道總共有多少項了,本例中為6項。又已經在布局中設置了numColumns=”3” ,就知道格子有幾排了:6/3=2。這樣,按照第一個格子的高度值124,總計2排,計算出GridView的總體高度為2*124=248。

通過滑動屏幕,能看到文本總共有6行。說明下,此時文本的順序是:褚橙,玉麟草莓,北界紅提葡萄,紅嘎拉蘋果,仙人蕉,黑美人西瓜。我通過調整字體,使兩個字為一行,超過則換行。此時的6行的高度,應該是兩個3行相加的結果。第一排,毫無疑問,只有“北界紅提葡萄”是分為3行的,所以,第一行的內容高度,是取的最後一個格子的高度。第二排是不是也是使用的最後一個格子的高度呢?通過調整第二排的內容順序,以及進一步的調整到2列3排,我驗證了這個想法。

總結:
1, GridView有一個視圖高度,其計算方法是:第一個格子的高度*總的排數;
2, GridView有一個內容高度,其計算方法是:每排最後一個格子的高度之和;
3, 若視圖高度小於內容高度,則內容顯示不全,可以滑動來顯示;
4,GridView每排的高度,不是固定的,使用的是最後一個格子的高度。
5,若某一排中有內容超過最後一個格子高度的,則多出的部分,會顯示到下一排上,從而出現重疊現象。若這排就是最後一排了,則多出的部分不能顯示。

根據以上結論,我們可以分析前面3張圖中遇到的問題:
第一張圖:字符重疊的原因,第二個格子的高度(3行)大於該排中最後一個格子的高度(2行)。字符顯示不全的原因:GridView總高度=2行*2=4行,而內容高度為2行+3行=5行,內容高度大於視圖高度,從而顯示不全。

第二張圖:字符顯示不全的原因:GridView視圖高度=2行*2=4行,進行均分,則每排為2行,所有高度值超過2行的格子,超過2行的內容部分都顯示不了。

第三張圖:字符顯示不全的原因:GridView總高度=1行*2=2行,而內容高度為3行+3行=6行,內容高度大於視圖高度,從而顯示不全。

再回到最初的問題,若要把內容顯示全,需要滿足兩個條件:
1,第一個格子的高度,是所有格子高度的最大值;
2,每排的最後一個格子的高度,是這一排中所有格子高度的最大值;

對於每個格子高度都一樣的,這兩個條件完全滿足。
但是字符串的長度不確定,從而導致了格子的高度不確定,怎麼辦呢?

我的辦法是,先全部遍歷一遍所有格子,找出內容最多的,放在第一個格子裡,通過系統的3次嘗試,獲取出高度最大值來。對於字符串而言,自然是最長的字符串換行最多,從而有最大的高度值。然後將所有格子的高度統一設置為這個值。當然,計算完成後,將第一個格子的內容也恢復為正常內容。

關鍵代碼如下:

package com.example.gridviewdemo;

import java.util.List;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.GridView;
import android.widget.TextView;

public class FruitAdapter extends ArrayAdapter {

    private int  resoureId;
    GridView mGv;

    static int heightTextView=0;
    static int numFlushTextView=0;

    public FruitAdapter (Context context, GridView gv, int textViewResourceId,
            List objects
            ) {
        super(context, textViewResourceId,objects);
        resoureId=textViewResourceId;
        this.mGv = gv;
        Log.i("FruitAdapter", "log: consturctor: resoureId=" + resoureId);

    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        Fruit fruit = getItem(position);
        View view;
        ViewHolder viewHolder;
        TextView tv_record ;
        String strLog;

        if(convertView == null){        
            view = LayoutInflater.from(getContext()).inflate(resoureId, null);
            strLog = "log: new ViewHolder ";
            viewHolder = new ViewHolder();
            viewHolder.fruitName = (TextView) view.findViewById(R.id.fruit_name);
            view.setTag(viewHolder);            
            viewHolder.fruitName.setText(fruit.getName());          

            tv_record = viewHolder.fruitName;
            Log.i("FruitAdapter", strLog+" pos="+position+" fruitName=" + fruit.getName()+" mGv.getHeight="+mGv.getHeight());
            Log.i("FruitAdapter", "log: getView: lines="+tv_record.getLineCount() +" LineHeight="+ tv_record.getLineHeight()+" tv.height="+tv_record.getHeight());

            if(heightTextView>0)
            {
                Log.i("adapter","to SetHeight="+heightTextView);
                tv_record.setHeight(heightTextView);        
            }

            //只在第一次的時候,獲取最長字符串,並進行設置。以便於在後面進入時,獲取到系統測算的實際布局高度值
            if((position==0)&&(numFlushTextView==0))
            {
                int posForMaxLen=0;
                int maxLength=0;
                for(int i=0;i0){
                int numRows=mGv.getCount()/mGv.getNumColumns();
                heightTextView = height/numRows;

                if(position==0){
                    tv_record.setText(getItem(0).getName().toString());//將內容改回原本應該使用的內容
                    tv_record.setHeight(heightTextView);
                    numFlushTextView++;                                     
                    Log.i(" fruitadapter","log:="" heightview="+heightTextView+" numflush="+numFlushTextView);
                }                   
            }                       
        }

        return view;
      }

    class ViewHolder{
        TextView fruitName;
    }

}

最終效果如下:

這裡寫圖片描述

後記:
現在其實還有個問題,就是若某一排中所有格子的內容都比較少,例如只有2行的高度,而GridView按最大高度值計算,給它安排的是3行的高度,就會有一行的空白了。
所以對於第一排之外的其他排,應該計算該排中內容最多的那個格子的高度值,用來設置該排最後一個格子的高度。
但是,Android系統只對第一排的第一個格子進行了3次計算,其他排的格子沒有這種計算,所以用這種方法就實現不了。
若有高人有方法實現這種精准的排列,請留言告訴我,萬分感謝!

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved