1. 程式人生 > >Android控制元件----關於上拉重新整理上拉載入的自定義控制元件

Android控制元件----關於上拉重新整理上拉載入的自定義控制元件

首先需要明白的是,平常用的ListView做不到類似於小說章節閱讀的瀏覽效果,去實現重新整理載入的功能。雖然GitHub上有一些開源庫可以使用,但是這種東西自己如果有時間能夠親歷一遍瞭解的更加透徹,畢竟在很多Android的APP中都有這方面的功能。話不多說,下面我們就開始上程式碼。

首先把頭部尾部的佈局弄好

headview.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation
="vertical" android:layout_width="match_parent" android:layout_height="match_parent" >
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/head" android:orientation="horizontal" android:gravity
="center" android:padding="5dp">
<ProgressBar android:layout_width="wrap_content" android:layout_height="wrap_content" style="?android:attr/progressBarStyleInverse" android:id="@+id/progressbar"/> <TextView android:layout_width
="wrap_content" android:layout_height="wrap_content" android:text="正在重新整理。。。。" android:id="@+id/update_info"/>
</LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/update_time" /> </LinearLayout> </LinearLayout>

footview.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:id="@+id/foot_load"
        android:padding="5dp"
        android:gravity="center">
        <ProgressBar
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            style="?android:attr/progressBarStyle"
            />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="載入中。。。。"
            />
    </LinearLayout>

</LinearLayout>

根據這2個介面佈局我們就可以去搭建一個自己的自定義ListView,以此來實現我們想要的效果

下面我們就可以著手自定義的ListView的編寫了

package com.yakir.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AbsListView;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.example.t210_06.R;

import java.text.SimpleDateFormat;

/**
 * 自定義listview實現上拉重新整理下拉載入
 */
public class MyListView extends ListView implements AbsListView.OnScrollListener{
    private View footview;
    private View headview;
    private int totaItemCounts;
    private int lasstVisible;
    private int fistVisiable;
    private LoadListener loadListener;
    private int footViewHeight;
    private int headViewHeight;
    private int yload;
    boolean isLoading;
    private TextView updateInfo;
    private TextView updateTime;
    private ProgressBar progressBar;
    public MyListView(Context context) {
        super(context);
        initView(context);
    }
    public MyListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    public MyListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context);
    }

    private void initView(Context context) {
        //拿到頭佈局xml
        headview=LayoutInflater.from(context).inflate(R.layout.headview,null);
        updateInfo=(TextView)headview.findViewById(R.id.update_info);
        updateTime=(TextView)headview.findViewById(R.id.update_time);
        progressBar=(ProgressBar)headview.findViewById(R.id.progressbar);
        updateTime.setText("更新於:"+new SimpleDateFormat("yyyy-MM-dd  HH:mm:ss").format(System.currentTimeMillis()));
        //拿到尾佈局xml
        footview=LayoutInflater.from(context).inflate(R.layout.footview,null);
        //測量footview的高度
        footview.measure(0,0);
        //拿到高度
        footViewHeight=footview.getMeasuredHeight();
        //隱藏view
        footview.setPadding(0,-footViewHeight,0,0);
        headview.measure(0,0);
        headViewHeight=headview.getMeasuredHeight();
        headview.setPadding(0,-headViewHeight,0,0);
        //設定不可見
        // footview.findViewById(R.id.foot_load).setVisibility(View.GONE);
        // headview.findViewById(R.id.head).setVisibility(View.GONE);
        //新增到listview底部
        this.addFooterView(footview);
        //新增到listview頭部
        this.addHeaderView(headview);
        //設定拉動監聽
        this.setOnScrollListener(this);


    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        switch (ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                yload=(int)ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                int moveY=(int)ev.getY();
                int paddingY=-headViewHeight+(moveY-yload)/2;

                if (paddingY<0){
                    updateInfo.setText("下拉重新整理。。。");
                    progressBar.setVisibility(View.GONE);
                }
                if (paddingY>0){
                    updateInfo.setText("鬆開重新整理。。。");
                    progressBar.setVisibility(View.GONE);
                }

                headview.setPadding(0,paddingY,0,0);

                break;
        }
        return super.onTouchEvent(ev);
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        if (totaItemCounts==lasstVisible&&scrollState==SCROLL_STATE_IDLE) {
            if (!isLoading) {
                isLoading=true;
                footview.setPadding(0,0,0,0);
                //載入資料
                loadListener.onLoad();

            }
        }
        if (fistVisiable==0){
            headview.setPadding(0,0,0,0);
            updateInfo.setText("正在重新整理。。。");
            progressBar.setVisibility(View.VISIBLE);
            loadListener.pullLoad();
        }
    }



    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        this.fistVisiable=firstVisibleItem;
        this.lasstVisible=firstVisibleItem+visibleItemCount;
        this.totaItemCounts=totalItemCount;

    }
    //載入完成
    public void loadComplete(){
        isLoading=false;
        footview.setPadding(0,-footViewHeight,0,0);
        headview.setPadding(0,-headViewHeight,0,0);


    }
    public void setInterface(LoadListener loadListener){
        this.loadListener=loadListener;

    }
    //介面回撥
    public interface LoadListener{

        void onLoad();
        void pullLoad();


    }
}

然後在外面的主介面佈局裡呼叫這個我們自己寫的外掛就行了

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.yakir.view.MyListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/list_view">
    </com.yakir.view.MyListView>


</RelativeLayout>

MainActivity.java

package com.example.t210_06;

import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.widget.ArrayAdapter;

import com.yakir.view.MyListView;

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

public class MainActivity extends AppCompatActivity implements MyListView.LoadListener{
    private MyListView listview;
    private List<Integer>list=new ArrayList<>();
    private ArrayAdapter adapter;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        for (int i=1;i<20;i++){
            list.add(i);
        }
        initView();
        adapter=new ArrayAdapter<>(this,android.R.layout.simple_expandable_list_item_1,list);
        listview.setAdapter(adapter);

    }

    private void initView() {
        listview=(MyListView) findViewById(R.id.list_view);
        listview.setInterface(this);
    }

    @Override
    public void onLoad() {
        //設定三秒延遲模仿延時獲取資料
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                //載入資料
                for (int j=1;j<11;j++){

                    list.add(j);
                }
                //更新 資料
                adapter.notifyDataSetChanged();
                //載入完畢
                listview.loadComplete();

            }
        },3000);


    }

    @Override
    public void pullLoad() {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                list.clear();
                for (int i=1;i<20;i++){
                    list.add(i+1);
                }
                adapter.notifyDataSetChanged();
                listview.loadComplete();

            }
        },2000);
    }
}

這1點必須注意: 在initView(context)方法中通過LayoutInfalter.from(context).from(你的xml,null);拿到xml。返回一個View物件,ListView中有一個setfootView()方法,使用他可以設定View到ListView的底部,當然做了這兩步是完全不夠的,我們還需要對這個View做一個互動的操作,當用戶滑到底部時這個View顯示,資料載入完畢之後這個View消失。這裡就能通過設定底部檢視的焦點位置去,使其隱藏,當下拉的時候觸發事件就可以達到我們的效果。