Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> ListView的下拉刷新上拉加載以及帶列的橫向滾動

ListView的下拉刷新上拉加載以及帶列的橫向滾動

編輯:關於Android編程

相信有很人做的項目估計都用的到這個。就是ListView的下拉刷新上拉加載還有就是列的橫向滾動;
PS:橫向滾動帶表頭與固定列(相信蠻多人都有這樣的需求吧?就是在ListView上支持很多列,然而設備屏幕寬度有限)
PS:這是我個人在網上找的兩個示例demo結合而成的一個示例demo,還可以繼續拓展,後續有時間就會更新,大家互相學習

接下來就是曬一下項目列表圖
java代碼
java代碼圖
布局文件xml

xml布局

效果圖:

橫向滾動過的圖和下拉刷新,由於不會弄動態圖只能這樣了
下拉刷新
刷新中
刷新中
上拉加載中
上拉加載

接下來就是上代碼了,請往下看

這是自定義重寫了ListView控件AutoListView.java
package com.example.testlistview.widget;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import com.example.testlistview.R;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.AbsListView;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;

/**
 * @author 
 * @create
 * @version 1.0
 * @desc 自定義Listview??下拉刷新,上拉加載更多
 */

public class AutoListView extends ListView implements OnScrollListener {

    // 區分當前操作是刷新還是加??
    public static final int REFRESH = 0;
    public static final int LOAD = 1;

    // 區分PULL和RELEASE的距離的大小
    private static final int SPACE = 20;

    // 定義header的四種狀態和當前狀???
    private static final int NONE = 0;
    private static final int PULL = 1;
    private static final int RELEASE = 2;
    private static final int REFRESHING = 3;
    private int state;

    private LayoutInflater inflater;
    private View header;
    private View footer;
    private TextView tip;
    private TextView lastUpdate;
    private ImageView arrow;
    private ProgressBar refreshing;

    private TextView noData;
    private TextView loadFull;
    private TextView more;
    private ProgressBar loading;

    private RotateAnimation animation;
    private RotateAnimation reverseAnimation;

    private int startY;

    private int firstVisibleItem;
    private int scrollState;
    private int headerContentInitialHeight;
    private int headerContentHeight;

    // 只有在listview第一個item顯示的時候(listview滑到了頂部)才進行下拉刷新, 否則此時的下拉只是滑動listview
    private boolean isRecorded;
    private boolean isLoading;// 判斷是否正在加載
    private boolean loadEnable = true;// ??啟或者關閉加載更多功??
    private boolean isLoadFull;
    private int pageSize = 10;

    private OnRefreshListener onRefreshListener;
    private OnLoadListener onLoadListener;

    public AutoListView(Context context) {
        super(context);
        initView(context);
    }

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

    public AutoListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView(context);
    }

    // 下拉刷新監聽
    public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
        this.onRefreshListener = onRefreshListener;
    }

    // 加載更多監聽
    public void setOnLoadListener(OnLoadListener onLoadListener) {
        this.loadEnable = true;
        this.onLoadListener = onLoadListener;
    }

    public boolean isLoadEnable() {
        return loadEnable;
    }

    // 這裡的開啟或者關閉加載更多,並不支持動???調??
    public void setLoadEnable(boolean loadEnable) {
        this.loadEnable = loadEnable;
        this.removeFooterView(footer);
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        this.pageSize = pageSize;
    }

    // 初始化組??
    private void initView(Context context) {

        // 設置箭頭特效
        animation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f);
        animation.setInterpolator(new LinearInterpolator());
        animation.setDuration(1000);
        animation.setFillAfter(true);

        reverseAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f);
        reverseAnimation.setInterpolator(new LinearInterpolator());
        reverseAnimation.setDuration(1000);
        reverseAnimation.setFillAfter(true);

        inflater = LayoutInflater.from(context);
        footer = inflater.inflate(R.layout.listview_footer, null);
        loadFull = (TextView) footer.findViewById(R.id.loadFull);
        noData = (TextView) footer.findViewById(R.id.noData);
        more = (TextView) footer.findViewById(R.id.more);
        loading = (ProgressBar) footer.findViewById(R.id.loading);

        header = inflater.inflate(R.layout.pull_to_refresh_header, null);
        arrow = (ImageView) header.findViewById(R.id.arrow);
        tip = (TextView) header.findViewById(R.id.tip);
        lastUpdate = (TextView) header.findViewById(R.id.lastUpdate);
        refreshing = (ProgressBar) header.findViewById(R.id.refreshing);

        // 為listview添加頭部和尾部,並進行初始化
        headerContentInitialHeight = header.getPaddingTop();
        measureView(header);
        headerContentHeight = header.getMeasuredHeight();
        topPadding(-headerContentHeight);
        this.addHeaderView(header);
        this.addFooterView(footer);
        this.setOnScrollListener(this);
    }

    public void onRefresh() {
        if (onRefreshListener != null) {
            onRefreshListener.onRefresh();
        }
    }

    public void onLoad() {
        if (onLoadListener != null) {
            onLoadListener.onLoad();
        }
    }

    public void onRefreshComplete(String updateTime) {
        lastUpdate.setText(this.getContext().getString(R.string.lastUpdateTime, getCurrentTime()));
        state = NONE;
        refreshHeaderViewByState();
    }

    // 用於下拉刷新結束後的回調
    public void onRefreshComplete() {
        String currentTime = getCurrentTime();
        onRefreshComplete(currentTime);
    }

    // 用於加載更多結束後的回調
    public void onLoadComplete() {
        isLoading = false;
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        this.firstVisibleItem = firstVisibleItem;
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        this.scrollState = scrollState;
        ifNeedLoad(view, scrollState);
    }

    // 根據listview滑動的狀態判斷是否需要加載更??
    private void ifNeedLoad(AbsListView view, int scrollState) {
        if (!loadEnable) {
            return;
        }
        try {
            if (scrollState == OnScrollListener.SCROLL_STATE_IDLE && !isLoading
                    && view.getLastVisiblePosition() == view.getPositionForView(footer) && !isLoadFull) {
                onLoad();
                isLoading = true;
            }
        } catch (Exception e) {
        }
    }

    /**
     * 監聽觸摸事件,解讀手??
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {

        switch (ev.getAction()) {
//      case MotionEvent.ACTION_DOWN:
//          if (firstVisibleItem == 0) {
//              isRecorded = true;
//              startY = (int) ev.getY();
//          }
//          break;
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            if (state == PULL) {
                state = NONE;
                refreshHeaderViewByState();
            } else if (state == RELEASE) {
                state = REFRESHING;
                refreshHeaderViewByState();
                onRefresh();
            }
            isRecorded = false;
            break;
        case MotionEvent.ACTION_MOVE:
            whenMove(ev);
            break;
        }
        return super.onTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            if (firstVisibleItem == 0) {
                isRecorded = true;
                startY = (int) ev.getY();
            }
        }
        return super.onInterceptTouchEvent(ev);
    }

    // 解讀手勢,刷新header狀???
    private void whenMove(MotionEvent ev) {
        if (!isRecorded) {
            return;
        }
        int tmpY = (int) ev.getY();
        int space = tmpY - startY;
        int topPadding = space - headerContentHeight;
        switch (state) {
        case NONE:
            if (space > 0) {
                state = PULL;
                refreshHeaderViewByState();
            }
            break;
        case PULL:
            topPadding(topPadding);
            if (scrollState == SCROLL_STATE_TOUCH_SCROLL && space > headerContentHeight + SPACE) {
                state = RELEASE;
                refreshHeaderViewByState();
            }
            break;
        case RELEASE:
            topPadding(topPadding);
            if (space > 0 && space < headerContentHeight + SPACE) {
                state = PULL;
                refreshHeaderViewByState();
            } else if (space <= 0) {
                state = NONE;
                refreshHeaderViewByState();
            }
            break;
        }

    }

    // 調整header的大小???其實調整的只是距離頂部的高度???
    private void topPadding(int topPadding) {
        header.setPadding(header.getPaddingLeft(), topPadding, header.getPaddingRight(), header.getPaddingBottom());
        header.invalidate();
    }

    /**
     * 這個方法是根據結果的大小來決定footer顯示的???
     * 

* 這裡假定每次請求的條數為10。如果請求到??10條???則認為還有數據。如過結果不??10條,則認為數據已經全部加載, * 這時footer顯示已經全部加載 *

* * @param resultSize */ public void setResultSize(int resultSize) { if (resultSize == 0) { isLoadFull = true; loadFull.setVisibility(View.GONE); loading.setVisibility(View.GONE); more.setVisibility(View.GONE); noData.setVisibility(View.VISIBLE); } else if (resultSize > 0 && resultSize < pageSize) { isLoadFull = true; loadFull.setVisibility(View.VISIBLE); loading.setVisibility(View.GONE); more.setVisibility(View.GONE); noData.setVisibility(View.GONE); } else if (resultSize == pageSize) { isLoadFull = false; loadFull.setVisibility(View.GONE); loading.setVisibility(View.VISIBLE); more.setVisibility(View.VISIBLE); noData.setVisibility(View.GONE); } } // 根據當前狀???,調整header private void refreshHeaderViewByState() { switch (state) { case NONE: topPadding(-headerContentHeight); tip.setText(R.string.pull_to_refresh); refreshing.setVisibility(View.GONE); arrow.clearAnimation(); arrow.setImageResource(R.drawable.pull_to_refresh_arrow); break; case PULL: arrow.setVisibility(View.VISIBLE); tip.setVisibility(View.VISIBLE); lastUpdate.setVisibility(View.VISIBLE); refreshing.setVisibility(View.GONE); tip.setText(R.string.pull_to_refresh); arrow.clearAnimation(); arrow.setAnimation(reverseAnimation); break; case RELEASE: arrow.setVisibility(View.VISIBLE); tip.setVisibility(View.VISIBLE); lastUpdate.setVisibility(View.VISIBLE); refreshing.setVisibility(View.GONE); tip.setText(R.string.pull_to_refresh); tip.setText(R.string.release_to_refresh); arrow.clearAnimation(); arrow.setAnimation(animation); break; case REFRESHING: topPadding(headerContentInitialHeight); refreshing.setVisibility(View.VISIBLE); arrow.clearAnimation(); arrow.setVisibility(View.GONE); tip.setVisibility(View.GONE); lastUpdate.setVisibility(View.GONE); break; } } // 用來計算header大小的???比較隱晦???因為header的初始高度就??0,貌似可以不用?? private void measureView(View child) { ViewGroup.LayoutParams p = child.getLayoutParams(); if (p == null) { p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); } int childWidthSpec = ViewGroup.getChildMeasureSpec(0, 0 + 0, p.width); int lpHeight = p.height; int childHeightSpec; if (lpHeight > 0) { childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); } else { childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } child.measure(childWidthSpec, childHeightSpec); } /* * 定義下拉刷新接口 */ public interface OnRefreshListener { public void onRefresh(); } /* * 定義加載更多接口 */ public interface OnLoadListener { public void onLoad(); } public String getCurrentTime(String format) { Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.getDefault()); String currentTime = sdf.format(date); return currentTime; } public String getCurrentTime() { return getCurrentTime("yyyy-MM-dd HH:mm:ss"); } } 這是自定義HorizontalScrollView的重寫 CHScrollView.java
package com.example.testlistview.widget;

import java.util.ArrayList;
import java.util.List;

import com.example.testlistview.widget.CHScrollView.CHScrollViewHelper;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.HorizontalScrollView;
import android.widget.Toast;

public class CHScrollView extends HorizontalScrollView {

    private Context context;
    float startx = 0;
    float offset;

    public CHScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.context = context;
    }

    public CHScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
    }

    public CHScrollView(Context context) {
        super(context);
        this.context = context;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        // 進行觸摸賦值
        CHScrollViewHelper.mTouchView = this;
        return super.onTouchEvent(ev);

    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        // 當當前的CHSCrollView被觸摸時,滑動其它
        if (CHScrollViewHelper.mTouchView == this) {
            onScrollChanged(l, t, oldl, oldt, 0);
        } else {
            super.onScrollChanged(l, t, oldl, oldt);
        }
    }

    public void onScrollChanged(int l, int t, int oldl, int oldt, int none) {
        for (CHScrollView scrollView : CHScrollViewHelper.mHScrollViews) {
            // 防止重復滑動
            if (CHScrollViewHelper.mTouchView != scrollView)
                scrollView.smoothScrollTo(l, t);
        }
    }

    public static class CHScrollViewHelper {
        public static HorizontalScrollView mTouchView;
        public static List mHScrollViews = new ArrayList();

        public static void addHViews(final CHScrollView hScrollView, AutoListView autoListView) {
            if (!CHScrollViewHelper.mHScrollViews.isEmpty()) {
                int size = CHScrollViewHelper.mHScrollViews.size();
                CHScrollView scrollView = CHScrollViewHelper.mHScrollViews.get(size - 1);
                final int scrollX = scrollView.getScrollX();
                // 第一次滿屏後,向下滑動,有一條數據在開始時未加入
                if (scrollX != 0) {
                    autoListView.post(new Runnable() {
                        @Override
                        public void run() {
                            // 當listView刷新完成之後,把該條移動到最終位置
                            hScrollView.scrollTo(scrollX, 0);
                        }
                    });
                }
            }
            CHScrollViewHelper.mHScrollViews.add(hScrollView);
        }
    }
}
這是ListView的適配器adapter ,ListViewScrollAdapter.java
package com.example.testlistview.adapter;

import java.util.List;
import java.util.Map;

import com.example.testlistview.R;
import com.example.testlistview.widget.AutoListView;
import com.example.testlistview.widget.CHScrollView;
import com.example.testlistview.widget.CHScrollView.CHScrollViewHelper;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.SimpleAdapter;
import android.widget.TextView;

public class ListViewScrollAdapter extends SimpleAdapter {

    private List> datas;
    private int res;
    private String[] from;
    private int[] to;
    private Context context;
    private int resScroll;
    private AutoListView lstv;

    public ListViewScrollAdapter(Context context, List> data, int resource, String[] from,
            int[] to, int resourceItem,AutoListView autoListView) {
        super(context, data, resource, from, to);
        this.context = context;
        this.datas = data;
        this.res = resource;
        this.from = from;
        this.to = to;
        this.resScroll = resourceItem;
        this.lstv = autoListView;
    }

    @Override
    public int getCount() {

        return this.datas.size();
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View v = convertView;
        if (v == null) {
            v = LayoutInflater.from(context).inflate(res, null);
            // 第一次初始化的時候裝進來
            CHScrollViewHelper.addHViews((CHScrollView) v.findViewById(resScroll), lstv);
            View[] views = new View[to.length];
            for (int i = 0; i < to.length; i++) {
                View tv = v.findViewById(to[i]);
                views[i] = tv;
            }
            v.setTag(views);
        }
        v.setBackgroundResource(R.drawable.selector_bg_white_gray);
        View[] holders = (View[]) v.getTag();
        int len = holders.length;
        for (int i = 0; i < len; i++) {
            ((TextView) holders[i]).setText(this.datas.get(position).get(from[i]).toString());
        }
        return v;
    }

    public Context getContext() {
        return context;
    }

}
這是MainActivity.java
package com.example.testlistview;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.example.testlistview.widget.AutoListView.OnLoadListener;
import com.example.testlistview.widget.AutoListView.OnRefreshListener;
import com.example.testlistview.R;
import com.example.testlistview.adapter.ListViewScrollAdapter;
import com.example.testlistview.widget.AutoListView;
import com.example.testlistview.widget.CHScrollView;
import com.example.testlistview.widget.CHScrollView.CHScrollViewHelper;
import android.annotation.SuppressLint;
import android.app.Activity;

public class MainActivity extends Activity implements OnRefreshListener, OnLoadListener, OnItemClickListener {

    private AutoListView lstv;
    private CHScrollView headerScroll;
    List> list = new ArrayList>();
    private ListViewScrollAdapter adapter;
    @SuppressLint("HandlerLeak")
    private Handler handler = new Handler() {
        @SuppressWarnings("unchecked")
        public void handleMessage(Message msg) {
            List> result = (List>) msg.obj;
            switch (msg.what) {
            case AutoListView.REFRESH:
                lstv.onRefreshComplete();
                list.clear();
                list.addAll(result);
                break;
            case AutoListView.LOAD:
                lstv.onLoadComplete();
                list.addAll(result);
                break;
            }
            lstv.setResultSize(result.size());
            adapter.notifyDataSetChanged();
        };
    };

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

    private void initView() {

        headerScroll = (CHScrollView) findViewById(R.id.item_scroll_title);
        CHScrollViewHelper.mHScrollViews.clear();
        // 添加頭滑動事件
        CHScrollViewHelper.mHScrollViews.add(headerScroll);
        lstv = (AutoListView) findViewById(R.id.scroll_list);

        adapter = new ListViewScrollAdapter(this, list, R.layout.auto_listview_item,
                new String[] { "title", "data_1", "data_2", "data_3", "data_4", "data_5", "data_6", },
                new int[] { R.id.item_title, R.id.item_data1, R.id.item_data2, R.id.item_data3, R.id.item_data4,
                        R.id.item_data5, R.id.item_data6 },
                R.id.item_scroll, lstv);

        lstv.setAdapter(adapter);
        lstv.setOnRefreshListener(this);
        lstv.setOnLoadListener(this);
        lstv.setOnItemClickListener(this);
    }

    private void initData() {
        loadData(AutoListView.REFRESH);
    }

    private void loadData(final int what) {
        // 這裡模擬從服務器獲取數據
        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    Thread.sleep(700);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Message msg = handler.obtainMessage();
                msg.what = what;
                msg.obj = getData();
                handler.sendMessage(msg);
            }
        }).start();
    }

    @Override
    public void onRefresh() {
        loadData(AutoListView.REFRESH);
    }

    @Override
    public void onLoad() {
        loadData(AutoListView.LOAD);
    }

    @Override
    public void onItemClick(AdapterView arg0, View arg1, int arg2, long arg3) {
        try {
            TextView textView = (TextView) arg1.findViewById(R.id.item_data2);

            Toast.makeText(this, "你點擊了:" + textView.getText(), Toast.LENGTH_SHORT).show();
        } catch (Exception ex) {

        }
    }


    // 測試數據
    public List> getData() {
        List> result = new ArrayList>();
        Map data = null;
        for (int i = 0; i < 10; i++) {
            data = new HashMap();
            data.put("title", "Title_" + i);
            data.put("data_" + 1, "Date_" + 1 + "_" + i);
            data.put("data_" + 2, "Date_" + 2 + "_" + i);
            data.put("data_" + 3, "Date_" + 3 + "_" + i);
            data.put("data_" + 4, "Date_" + 4 + "_" + i);
            data.put("data_" + 5, "Date_" + 5 + "_" + i);
            data.put("data_" + 6, "Date_" + 6 + "_" + i);
            result.add(data);
        }
        return result;
    }


}
這是layout布局文件 activity_main.xml



    

        

        

            

                

                

                

                

                

                
            
        
    

    

auto_listview_item.xml布局文件 ListView的item布局文件



    

    

        

            

            

            

            

            

            
        
    

Listview底部提示正在加載中的布局文件 listview_footer.xml



    

    

    

    

ListView頂部提示下拉刷新的一些狀態布局xml文件 pull_to_refresh_header.xml



    

        

            

            

            
        

        
    

    


    Android編譯和目標版本是4.0.3
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved