編輯:關於Android編程
最近搞一個項目,需要用到類似於新浪微博的消息流,即每一項有文字、有九宮格圖片,因此這就涉及到ListView或者ScrollView嵌套GridView的問題。其中GridView的高度問題在網上都很容易找到答案,即覆寫onMeasure方法,然後設置高度的MeasureSpec。但是寬度問題確實沒有什麼資料,這裡所說的寬度問題是比如GridView的列數為3,那麼即使只有一張圖片,gridview的寬度也是match_parent的,導致用戶點擊在圖片范圍外但是在gridview范圍內時ListView的點擊事件不能捕獲。
如圖 :

出現的問題截圖如上,當只有一個圖標時GridView的寬度(灰色區域)也是match_parent的,這個時候點擊gridview區域是ListView是不能響應的,但是如果GridView的背景色與ListView的背景一致,用戶是看不到GridView的寬度,當用戶點擊圖片以外的區域,可能的操作就是進入到該條消息的詳情頁,但是由於此時GridView是match_parent的,所以ListView根本不會獲取到點擊事件,這樣的體驗很不好。我們需要的效果是這樣的 :

即GridView的大小剛好能夠包含圖片的大小,這樣當GridView的背景色為默認時,用戶點擊圖片以外的區域就是點擊了ListView的Item。
我們看看如何解決這個問題吧,首先布局方面就不講了,主要還是講講GridView的寬高問題吧。解決GridView的高度問題,需要覆寫GridView的onMeasure方法,代碼如下 :
public class MGridView extends GridView {
public boolean hasScrollBar = true;
/**
* @param context
*/
public MGridView(Context context) {
this(context, null);
}
public MGridView(Context context, AttributeSet attrs) {
super(context, attrs, 0);
}
public MGridView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = heightMeasureSpec;
if (hasScrollBar) {
expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);// 注意這裡,這裡的意思是直接測量出GridView的高度
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
}
在onMeasure方法中,因為hasScrollBase為true, 我們會注意到代碼中有注釋的分支。這裡實際上就是在onMeasure的時候計算出GridView的高度,而不是只計算其中幾個View的高度。如果沒有這一步,那麼GridView的高度將顯示不全。將GridView的高度計算出來,這樣就不需要上下滑動來顯示其它的item了,因為問題所在就是GridView嵌套在了ScrollView或者包含ScrollView的組件中,從而引發的沖突。
下面解決寬度的問題,思路就是在ListView的getView方法中手動計算每個GridView的圖片個數,如果圖片個數小於GridView每行的列數,則手動計算每個child view所需的寬度,然後GridView的寬度 = child個數 * 每個child view的寬度。為了避免重復計算,我們會緩存計算結果。計算代碼如下 :
/**
* @author mrsimple
*/
public final class GridViewUtils {
/**
* 存儲寬度
*/
static SparseIntArray mGvWidth = new SparseIntArray();
/**
* 計算GridView的高度
*
* @param gridView 要計算的GridView
*/
public static void updateGridViewLayoutParams(MGridView gridView, int maxColumn) {
int childs = gridView.getAdapter().getCount();
if (childs > 0) {
int columns = childs < maxColumn ? childs % maxColumn : maxColumn;
gridView.setNumColumns(columns);
int width = 0;
int cacheWidth = mGvWidth.get(columns);
if (cacheWidth != 0) {
width = cacheWidth;
} else { // 計算gridview每行的寬度, 如果item小於3則計算所有item的寬度;
// 否則只計算3個child寬度,因此一行最多3個child。 (這裡我們以3為例)
int rowCounts = childs < maxColumn ? childs : maxColumn;
for (int i = 0; i < rowCounts; i++) {
View childView = gridView.getAdapter().getView(i, null, gridView);
childView.measure(0, 0);
width += childView.getMeasuredWidth();
}
}
ViewGroup.LayoutParams params = gridView.getLayoutParams();
params.width = width;
gridView.setLayoutParams(params);
if (mGvWidth.get(columns) == 0) {
mGvWidth.append(columns, width);
}
}
}
ListView的getView方法如下 :
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.listview_item, parent, false);
viewHolder = new ViewHolder();
viewHolder.mGridView = (MGridView) convertView.findViewById(R.id.my_gridview);
viewHolder.mTextView = (TextView) convertView.findViewById(R.id.my_tv);
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
final ListViewItem item = getItem(position);
// 設置GridView的Adapter
viewHolder.mGridView.setAdapter(new GridViewAdapter(mContext, item.mImages));
// 計算GridView寬度, 設置默認為numColumns為3.
GridViewUtils.updateGridViewLayoutParams(viewHolder.mGridView, 3);
viewHolder.mTextView.setText(item.mText);
return convertView;
}
Android簡易實戰教程--第二十四話《畫畫板》
今天完成一個畫畫板。首先來個布局: 可見,要分紅綠色,而且還要保存最後畫的圖片。 看一下主活動代碼: package com.it
Android AsyncTask 源碼解析
1、概述 相信大家對AsyncTask都不陌生,對於執行耗時任務,然後更新UI是一把利器,當然也是替代Thread + Handler 的一種方式。如果你對
Android自定義控件(狀態提示圖表)
1 背景前面分析那麼多系統源碼了,也該暫停下來休息一下,趁昨晚閒著看見一個有意思的需求就操練一下分析源碼後的實例演練—-自定義控件。這個實例很適合
Android 根據EditText搜索框ListView動態顯示數據
根據EditText搜索框ListView動態顯示數據是根據需求來的,覺得這之中涉及的東西可能比較的有意思,所以動手來寫一寫,希望對大家有點幫助。首先,我們來分析下整個過