GridView添加HeaderView和FooterView的解决方案

最近有一个需求,需要在GridView之上添加HeaderView和FooterView,并实现延迟加载(LazyLoad),但是经过我3天的研究和尝试,只能说自己真的太弱了,真的没有解决方法。

所以,这里我奉劝大家,放弃这个方案吧。

强烈建议大家使用ListView来实现GridView的效果。


以下说说我走过的几条错误的路:

1FooterView添加比较简单,而且可以实现,因为GridView可以位于一个ViewGroup中,通过Visable的控制,可以轻易达到这个效果,这个我就不再多说,主要来说说HeaderView。


1.第一次痛苦的尝试:

Override的GridView,设置Padding,通过控制OnTouchEvent的事件,改变padding并且移动HeaderView。这个方法初看来是十分不错的,可是问题也随之而来。如果HeaderView非常高,GridView就会非常小,手势在ViewGroup中就被拦截到了。而不会反应给GridView,当然,你可以重写ViewGroup,但这其中的麻烦不言而喻,所以我果断放弃了。

    

2.第二次痛苦的尝试:

想法和添加FooterView一样,通过控制View的Visable来达到目的,可是却发现HeaderView是不随GridView滚动的,这个问题本来下手之前就应该遇见到,结果...所以真的应该三思而后行。


3.第三次痛苦的尝试:

通过Override的ViewGroup,然后自己排列,这个我觉得十分麻烦,因为HeaderView并没有真正的属于GridView,所以一切控制起来非常不方便!!!中途就放弃了。


4.第四次痛苦的尝试:

通过对GridView设置一个OnScrollListener,通过callback来改变自身的padding,然后在padding的地方添加一个View,发现还是不行!!!


5.第五次痛苦的尝试:

dVie通过LinearLayout嵌套GridView,之后再加入ScrollView来控制滚动,结果发现ScrollView是无缓存的,和LazyLoad是冲突的,而且对大量数据根本没法处理,果断放弃!


不过今天终于解决这个问题了,改ListView成GridView还是非常简单的。思路是这样的,一个LinearLayout 根据

  1. mColumns 的具体数值去装入child(就是之前的getView),这样就可以轻松实现gridView的功能了,所以只需要修改getView和getCount就可以了,下面是代码:  

package cn.xs8.app.activity.news;


import java.util.concurrent.atomic.AtomicInteger;


import android.content.Context;

import android.database.DataSetObserver;

import android.view.View;

import android.view.View.OnClickListener;

import android.view.ViewGroup;

import android.widget.AbsListView.LayoutParams;

import android.widget.AdapterView.OnItemClickListener;

import android.widget.BaseAdapter;

import android.widget.LinearLayout;

import android.widget.ListView;


/**

 * Wrapper adapter and make it like GridView

 * <hr>

 * notice : {@link OnGridItemClickListener} instead of {@link OnItemClickListener}

 * <br>

 * e.g: use {@link #setOnItemClickListener(OnGridItemClickListener)} instead of

 * {@link ListView#setOnItemClickListener(OnItemClickListener)}

 * 

 * @author Chaos

 * @date 2013-2-21 

 */

public class GridAdapter<T extends BaseAdapter> extends BaseAdapter implements OnClickListener{


private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);


private static final int ID_POS = fakeGenId();


private static final int ID_REAL_POS = fakeGenId();


    /**

     * The wrapper content --> adapter

     */

    private T mAdapter = null;

    /**

     * The number columns

     */

    private int mColumns = 1;

    /**

     * The real onItemClickListener

     */

    private OnGridItemClickListener mGridListener;

    /**

     * The Context Object

     */

    private Context mContext;

    

    

    @Override

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

        

        if(mColumns == 1){

            

            View child = mAdapter.getView(position, convertView, parent);

            setOnItemClickListenerIfNeed(child, position, position);

            //no need

            return child;

        }

        

        return bindGridView(position, convertView, parent);

    }

    

    protected View bindGridView(int position, View convertView, ViewGroup parent){

        ViewGroup root = null;

        //cache the root

        if(convertView == null || !(convertView instanceof ViewGroup)){

            root = createRoot();

            root.setClickable(false);

            root.setFocusable(false);

        }else{

            root = (ViewGroup) convertView;

        }

        //columns = 3

        //pos --> real pos

        //0   --> 0 1 2

        //1   --> 3 4 5

        //2   --> 6 7 8

        //so do this

        return bindView(root, position);

    }

    

    protected ViewGroup bindView(ViewGroup root, int pos) {

        

        final int count = mAdapter.getCount();

        final int childCount = root.getChildCount();

        

        for (int i = 0; i < mColumns; i++) {

            // real position

            int index = mColumns * pos + i;

            

            // 不足一行时,直接返回现有状态

            if (index == count) {

                // fix bug : root是有可能是系统缓存的root,这里直接返回root将导致如果此行数量

                // 不够columns,就会使用缓存的root里的child,为了避免这个问题,必须

                // 将缓存的child移除。

                // by Chaos at 2012-12-17

                removeCacheChild(root, index);

                break;

            }else if(index > count){

                throw new UnknownError("unknowError");

            }

            

            View child = mAdapter.getView(index, root.getChildAt(i), root);


            setOnItemClickListenerIfNeed(child, pos, index);

            

            if (childCount == mColumns) {

                // root已经包含了Item,就没有必要继续添加了。

                continue;

            } else {

                if (i == 0 && childCount != 0) {

                    // 如果root已经包含item,但是并不全,这里就移除重新添加

                    // FIXME 也许还有更好的方案

                    root.removeAllViews();

                }

                LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(

                        // LinearLayout.LayoutParams.WRAP_CONTENT,

                        mContext.getResources().getDisplayMetrics().widthPixels / mColumns-10,

                        LinearLayout.LayoutParams.WRAP_CONTENT);

                child.setFocusable(true);

                child.setClickable(true);

                if (child instanceof ViewGroup) {

                    ((ViewGroup) child)

                            .setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);

                }

                root.addView(child, lp);

            }

        }

        return root;

    }

    

    /**

     * remove child view in cache of root

     */

    private void removeCacheChild(ViewGroup root,int index){

        int realColumns = (index - 1) % mColumns;

        int moveCount   = (mColumns - 1) - realColumns;

        

        for (int i = 0; i < moveCount; i++) {

            final View child = root.getChildAt((mColumns - 1 - i));

            if(child != null){

                root.removeView(child);

            }

        }

    }

    

    /**

     * create root for item of ListView

     */

    protected ViewGroup createRoot(){

        LinearLayout root = new LinearLayout(mContext);

        root.setOrientation(LinearLayout.HORIZONTAL);

        LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);

        root.setLayoutParams(lp);

        return root;

    }

    

    private boolean setOnItemClickListenerIfNeed(View child,int pos,int realPos) {

        if(mGridListener == null){

            return false;

        }

        child.setOnClickListener(this);

child.setTag(ID_POS, pos);

child.setTag(ID_REAL_POS, realPos);

        return true;

    }

    

    public void setOnItemClickListener(OnGridItemClickListener listener){

        this.mGridListener = listener;

    }

    

    public void setNumColumns(int columns){

        this.mColumns = columns;

    }

    

    public int getNumColumns(){

        return mColumns;

    }

    

    public GridAdapter(Context context,T adapter){

        this.mContext = context;

        this.mAdapter = adapter;

    }


    @Override

    public int getCount() {

        int count = (int) Math.ceil(mAdapter.getCount() / (double)mColumns);

        return count;

    }


    @Override

    public Object getItem(int position) {

        return mAdapter.getItem(position);

    }


    @Override

    public long getItemId(int position) {

        return mAdapter.getItemId(position);

    }


    @Override

    public boolean hasStableIds() {

        return mAdapter.hasStableIds();

    }


    @Override

    public void registerDataSetObserver(DataSetObserver observer) {

        mAdapter.registerDataSetObserver(observer);

    }


    @Override

    public void unregisterDataSetObserver(DataSetObserver observer) {

        mAdapter.unregisterDataSetObserver(observer);

    }


    @Override

    public boolean areAllItemsEnabled() {

        return mAdapter.areAllItemsEnabled();

    }


    @Override

    public boolean isEnabled(int position) {

        return mAdapter.isEnabled(position);

    }


    @Override

    public int getItemViewType(int position) {

        return mAdapter.getItemViewType(position);

    }


    @Override

    public int getViewTypeCount() {

        return mAdapter.getViewTypeCount();

    }


    @Override

    public boolean isEmpty() {

        return mAdapter.isEmpty();

    }

    

    public T getWrappedAdapter(){

        return mAdapter;

    }

    

    public static interface OnGridItemClickListener{

        public void onItemClick(int pos,int realPos);

    }


    @Override

    public void onClick(View v) {

        if(mGridListener == null){

            //no need to feedback

        }

int pos = (Integer) v.getTag(ID_POS);

int realPos = (Integer) v.getTag(ID_REAL_POS);

        

        mGridListener.onItemClick(pos, realPos);

    }

    


/**

* copy from {@link View#generateViewId()} <br>

* @since API 17

* @return

*/

public static int generateViewId() {

for (;;) {

final int result = sNextGeneratedId.get();

// aapt-generated IDs have the high byte nonzero; clamp to the range

// under that.

int newValue = result + 1;

if (newValue > 0x00FFFFFF) {

newValue = 1; // Roll over to 1, not 0.

}

if (sNextGeneratedId.compareAndSet(result, newValue)) {

return result;

}

}

}


/**

* 生成一个ID,让系统误以为是 {@link R}中的id

* @return

*/

public static int fakeGenId() {

int realId = generateViewId();

int fakeId = realId | 0x10000000;

return fakeId;

}


}

调用方法如下:

GridAdapter<BaseAdapter> mAdapter = new GridAdapter<BaseAdapter>(

Xs8_Application.getGlobeContext(), mBookGridViewAdapter);//其中mBookGridViewAdapter是正常的adapter


int screenWidth = Tools.getScreenWidth();

int screenHeight = Tools.getScreenHeight();

// 适配1024*600 屏幕(7寸手机)

if (screenHeight<1024 && screenWidth < 600) {

mAdapter.setNumColumns(3);

}else{

mAdapter.setNumColumns(4);

}

mAdapter.setOnItemClickListener(new OnGridItemClickListener()

{


@Override

public void onItemClick(int pos, int realPos)

{

// 这里的Listener需要自己扩充,可以callback你需要的内容。

}

});


listView.setAdapter(mAdapter);


你可能感兴趣的:(GridView添加HeaderView和FooterView的解决方案)