1. 程式人生 > >Android GridView之新增分隔線,動態設定高度,實現高度自適應,並解決第一個item不顯示的問題

Android GridView之新增分隔線,動態設定高度,實現高度自適應,並解決第一個item不顯示的問題

最近做一個專案時遇到一點問題,在這裡分享一下解決思路。

首先看效果圖:


這裡的需求是實現介面中的六個圖示,博主後來和同事討論過這個問題,用 GridView 實現費時費力好嘛,同事認為做6個 Button 就

好了,可能博主就愛鑽牛角尖吧,一開始認為怎麼辦只要還有辦法那就按自己想的去做出來,好了不多廢話了,下面來講思路。

首先是分割線的問題,我們都知道 ListView 中有

分割線顏色  
android:divider="#FFFFFF"
分割線高度
android:dividerHeight="1px"

通過這兩個屬性可以輕鬆給 ListView 新增分隔線,於是博主也查了查文件,發現 GridView 中沒有類似的屬性,那怎麼辦好呢,繼續

翻翻文件吧,發現在 GriView 中有這兩個屬性:

垂直間距
android:verticalSpacing="10dp"
水平間距
android:horizontalSpacing="10dp"

那麼想法就來了,用一個 LinearLayout 佈局包裹 GridView ,將 LinearLayout 的背景色設為分隔線的顏色,然後給GridView 設定垂

直和水平間距,那麼不就達到分隔線的效果了嘛,那說幹就幹,首先是 GridView 佈局檔案:

    <LinearLayout
        android:id="@+id/gridViewLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/color3"
        android:orientation="vertical">

        <GridView
            android:id="@+id/gridView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:horizontalSpacing="1dp"
            android:listSelector="@android:color/transparent"
            android:numColumns="3"
            android:stretchMode="columnWidth"
            android:verticalSpacing="1dp" />

    </LinearLayout>

然後是 item 的佈局:

<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"
    android:background="@color/color1">

    <ImageView
        android:id="@+id/image"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:adjustViewBounds="true"
        android:scaleType="fitXY" />

    <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_marginTop="3dp"
        android:textColor="@color/color2"
        android:textSize="13sp" />

</LinearLayout>

接下來是介面卡:

public class GridAdapter extends BaseAdapter {

    private Context context = null;
    private int[] image;
    private String[] text;

    public GridAdapter(Context context, int[] image, String[] text) {
        this.context = context;
        this.image = image;
        this.text = text;
    }

    @Override
    public int getCount() {
        return image.length;
    }

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

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final ViewHolder viewHolder;
        if (convertView == null) {
            viewHolder = new ViewHolder();
            convertView = LayoutInflater.from(context).inflate(R.layout.gridview_item, parent, false);
            viewHolder.imageView = (ImageView) convertView.findViewById(R.id.image);
            viewHolder.textView = (TextView) convertView.findViewById(R.id.text);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }
        viewHolder.imageView.setImageResource(image[position]);
        viewHolder.textView.setText(text[position]);
        return convertView;
    }

    public class ViewHolder {
        ImageView imageView;
        TextView textView;
    }
}
到這裡感覺要大功告成了,執行一看,出問題了:


GridView 的高度並沒有填充整個 LinearLayout ,可以看到下面灰色的空白處都是LinearLayout 的空間,而 GridView 只是剛剛好包

裹了內容。於是想了想,是不是因為載入介面卡的時候,item 的屬性被重畫了,那就先試試在介面卡中動態設定 item 的高度看看,

於是在 item 載入後新增如下的程式碼,同時在構造器中將 LinearLayout 傳入:

convertView.setLayoutParams(new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                    gridViewLayout.getHeight() / 2));
再執行看看,看到結果的那一瞬間,博主內心不禁吐槽WTF!

第一個 item 去哪裡了,就這樣被吃掉了嘛,查了查資料,說是 GridView 在繪畫時是根據第一個 item 定位其餘 item 的,動態設定

item 高度,會導致第一個 item 丟失。解決方法呢,其實也不難,如果湊巧你可能還不會發現這個問題。方法是不要用ViewHolder 寫

法,刪除 item 佈局,改成每次 getView 時建立新的 View 。

修改後程式碼如下:

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        LinearLayout item = new LinearLayout(context);
        item.setLayoutParams(new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                gridViewLayout.getHeight() / (image.length / COL_NUMBER)));
        item.setOrientation(LinearLayout.VERTICAL);
        item.setBackgroundColor(ContextCompat.getColor(context, R.color.color1));
        item.setGravity(Gravity.CENTER);

        ImageView imageView = new ImageView(context);
        imageView.setLayoutParams(new AbsListView.LayoutParams(120, 120));
        imageView.setAdjustViewBounds(true);
        imageView.setScaleType(ImageView.ScaleType.FIT_XY);
        imageView.setImageResource(image[position]);
        item.addView(imageView);

        TextView textView = new TextView(context);
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
        lp.setMargins(0, 15, 0, 0);
        textView.setLayoutParams(lp);
        textView.setTextSize(13);
        textView.setTextColor(ContextCompat.getColor(context, R.color.color2));
        textView.setText(text[position]);
        item.addView(textView);

        return item;
    }

到這裡總算是大功告成了:


這邊經別人提點,還有一種解決方法,不需要每次 new 一個 View ,依然採用 ViewHolder 寫法:

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        final ViewHolder viewHolder;
        if (convertView == null) {
            Log.i("convertView","null");
            viewHolder = new ViewHolder();
            convertView = LayoutInflater.from(context).inflate(R.layout.gridview_item, parent, false);
            convertView.setLayoutParams(new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                    gridViewLayout.getHeight() / 2));
            viewHolder.imageView = (ImageView) convertView.findViewById(R.id.image);
            viewHolder.textView = (TextView) convertView.findViewById(R.id.text);
            convertView.setTag(viewHolder);
        } else {
            Log.i("convertView","not null");
            convertView.setLayoutParams(new AbsListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                    gridViewLayout.getHeight() / 2));
            viewHolder = (ViewHolder) convertView.getTag();
        }
        viewHolder.imageView.setImageResource(image[position]);
        viewHolder.textView.setText(text[position]);
        return convertView;
    }

但是這裡博主也不是很明白,第一次已經為 convertView 設定了 LayoutParams ,在後面 LayoutParams 的資訊就丟失了,控制檯打

印的資訊如下:

10-30 15:42:23.387 4158-4158/com.liuwan.mydesign.activity I/convertView: null
10-30 15:42:23.407 4158-4158/com.liuwan.mydesign.activity I/convertView: not null
10-30 15:42:23.450 4158-4158/com.liuwan.mydesign.activity I/convertView: not null
10-30 15:42:23.452 4158-4158/com.liuwan.mydesign.activity I/convertView: null
10-30 15:42:23.465 4158-4158/com.liuwan.mydesign.activity I/convertView: null
10-30 15:42:23.475 4158-4158/com.liuwan.mydesign.activity I/convertView: null
10-30 15:42:23.489 4158-4158/com.liuwan.mydesign.activity I/convertView: null
10-30 15:42:23.502 4158-4158/com.liuwan.mydesign.activity I/convertView: null
10-30 15:42:23.515 4158-4158/com.liuwan.mydesign.activity I/convertView: null
10-30 15:42:23.520 4158-4158/com.liuwan.mydesign.activity I/convertView: not null
10-30 15:42:23.666 4158-4158/com.liuwan.mydesign.activity I/convertView: not null
10-30 15:42:23.674 4158-4158/com.liuwan.mydesign.activity I/convertView: not null
6個 item 呼叫了12次 getView ,這裡的順序也是沒看懂什麼意思,可能和 GridView 底層的繪製方法有關吧,如果有人明白希望可以

解答。

最後,博主還是想說一下,這個問題前前後後花了我兩個小時解決,要是用 Button 就是幾分鐘的事,但是我覺得值得,我多學會了

一種設計思路,以後遇到更復雜的設計,以至於 Button 不能解決的時候,那麼收效就有了。

原始碼下載

相關推薦

Android GridView新增分隔動態設定高度實現高度適應解決一個item顯示的問題

最近做一個專案時遇到一點問題,在這裡分享一下解決思路。 首先看效果圖: 這裡的需求是實現介面中的六個圖示,博主後來和同事討論過這個問題,用 GridView 實現費時費力好嘛,同事認為做6個 Button 就 好了,可能博主就愛鑽牛角尖吧,一開始認為怎麼辦只要還有辦法那就

GridView一個item顯示,以及顯示方式正確的調整方式。

專案中在GridView的使用過程中遇到不少問題,在此記錄一下,給自己提個醒: Gridview第一個item不顯示的問題。 在GridView中,我們在getView中可以對映每個item的佈局,通過inflate的方式。這裡參考一下大神的分析,具體在這裡有詳細的描述三種

Android疑難雜症】GridView動態設定Item的寬高導致一個Item響應或顯示正常的問題

在使用Android的GridView控制元件時,很多人都會碰到這麼個奇怪的問題:整個GridView中,所有item的響應都沒問題,只有第一個item不響應,或是顯示不正常,或是點完第一個item後不響應但再點其他的item後其他item會響應、同時第一個item也

根據HTML+CSS完成一個三列布局左右側欄寬為180px高為300px;中間欄適應高為300px;中間欄子元素(寬高確定)實現水平、垂直居中。

使用Flex佈局,更加方便。HTML程式碼省略,以下只是CSS樣式的程式碼,僅供參考。 <!DOCTYPE html> <html> <head> <title></title> </head> &

Android 中為RecyclerView控制元件新增分隔

在上一篇 RecyclerView 控制元件的文章中,我們看了一下ListView控制元件和RecyclerView控制元件的簡單用法,那麼下面我們將關注點放在RecyclerView上,畢竟RecyclerView控制元件在很多方面確實比ListView控制元

android設置GridView高度適應實現全屏鋪滿效果

== post http istview div GridView dap item 拉伸 使GridView每個item的高度自適應拉伸,達到整個GridView剛好鋪滿全屏的效果。 public static void setGridViewMatchParent(G

【Markdown】新增分隔

問題:在 MarkdownPad 2 中新增分隔線,如下圖所示: 處理:在一行中用三個以上的星號(*)、減號(-)、下劃線(_)來建立一個分隔線;除空格外行內不能有其他字元;(除第一個符號的左側最多

android 動態設定控制元件的高度使用對應佈局中的dp值

1. 獲取你要進行改變的控制元件的佈局 LinearLayout.LayoutParams linearParams =(LinearLayout.LayoutParams) myView.getLayoutParams(); 2.設定佈局的高度   後面的引數就是對應

Android RecyclerView新增Item分割線

   在 Android RecyclerView之代替ListView與GridView 這篇部落格中,佈局中可以看到雖然實現了ListView 與GridView的佈局的實現,但是如果不加背景顏色,每個Item間是沒有分割線的,因此分割線的新增需要我們自己進

Android 對TextView新增刪除,下劃線,加粗,斜體等效果

本文轉自:http://blog.csdn.net/lzyang187/article/details/50695563一:介紹大家在專案中,比如購物類,有原價和折扣價這樣很可能就需要對原價新增刪除線,對摺扣價新增加粗效果等等.而給TextView新增超連結,個人認為加點選事

C語言靜態動態順序表的實現

      在學習了C語言之後,我們先來了解一下簡單的資料結構,順序表和連結串列。      順序表和連結串列都屬於線性資料結構。順序表的底層相當於一個數組,因為它的空間是一段地址連續的儲存單元;連結串列的底層不需要所有的空間都連續,只要通過指標就可以找到下一個儲存空間。下面

Android開發貝塞爾曲線進階篇(仿直播送禮物餓了麼購物車動畫)

又是一年畢業季,今年終於輪到我了,最近一邊忙著公司的專案,一邊趕著畢設和論文,還私下和朋友搞了些小外包,然後還要還抽出時間寫部落格,真是忙的不要不要的。 好了,言歸正傳,前幾天寫了一篇關於貝塞爾曲線的基礎篇,如果你對貝塞爾曲線還不是很瞭解,建議你先去閱讀下:Android開發之貝塞爾曲線初體驗 ,今天這篇文

動態規劃算法求解TSP(Traveling Salesman Problem) 附C語言實現例程

影響 () 高效率 let ever 好的 出現 我們 運算 TSP問題描述:   旅行商問題,即TSP問題(Travelling Salesman Problem)又譯為旅行推銷員問題、貨郎擔問題,是數學領域中著名問題之一。假設有一個旅行商人要拜訪n個城市,他必須選擇所

react中使用antdesign中form元件動態設定Input的值

問題: 在使用Antdesign的form元件時,通過initialValue來設定Input的值,在form未驗證之前,可以通過initialValue來對input賦值,但是form驗證之後,雖然state中存在值,但是不能在input中顯示,form也不能再次提交,程式碼如下所示:

Android WebView 圖片超出寬度適應點選檢視大圖

webView 配置  WebSettings webSettings = webView.getSettings(); webSettings.setJava

react專案中使用antd的form元件動態設定input框的值

問題: 建立賬號時,輸入賬號後不搜尋直接儲存,提示查詢後,再點搜尋就不能搜尋這個賬號了 原因: 點選儲存之後,對錶單進行了驗證,導致之後請求的資料無法在更新到input框中,也就是說即使在state中有值,也不會更新initialValue值,就導致搜尋後的值不能正

Android開發百度地圖定位以及簡單覆蓋物的實現

直接上程式碼: 先看下效果圖: 我這裡主要做了三個功能: 1.一秒鐘實時定位功能; 2.新增任意經緯度地點到地圖上; 3.判斷朝陽門是否在本人定位範圍1000米內; 百度地圖初始化方法: DemoApplication.java package com

啟動Java程式時動態設定SpringBoot配置檔案中的配置

比如: springboot配置檔案中有個   spring.redis.host=localhost選項 但是這個配置可能會修改,比如指定到其他伺服器上的redis.那我們需要修改配置檔案嗎?、 答案是NO 我們可以在啟動SPringBoot程式的時候動態指定這

Android app實現靜默安裝自動開啟實現開機啟動異常崩潰重新啟動定時關機等

現在很多公司都開始做智慧硬體產品,主要是在Android開發板上面開發應用app,尤其這兩年物聯網越來越火,這方面的需求越來越多,目前公司也是做智慧公交站臺的,需要開發的app實現開機自啟動,異常崩潰重新啟動,版本升級靜默安裝並自動開啟,定時開關機,感覺都要跟Android系

android的APP呼叫C語言的動態連結庫的實現步驟

1.新建一個類test,通過System.loadLibrary()的方式將so載入進去,注意不要帶有lib 和 so 比如libhello.so,為System.loadLibrary(hello),如下文所示,JAVA 呼叫addtest,返回的Addtest為jn