GitHub:liaohuqiu/android-Ultra-Pull-To-Refresh

推荐阅读:
【框架学习】【android-Ultra-Pull-To-Refresh】
我眼中的下拉刷新

简介:

android-Ultra-Pull-To-Refresh的特点是:内置各种下拉刷新交互风格。遗憾的是这个库不支持上拉加载更多。

Android studio使用,可直接添加依赖:

    compile 'in.srain.cube:ultra-ptr:1.0.11'

android-Ultra-Pull-To-Refresh (简称 UltraPTR )是一个强大的 Andriod 下拉刷新框架。
1.继承自ViewGroup,Content可以包含任何View;
2.简洁完善的Header抽象,方便进行扩展,构建满足需求的Header;

对比于Android-PullToRefresh 来说,UltraPTR没有实现上拉加载,作者认为上拉加载于下拉刷新不是同一个层次的功能,上拉加载应该交由Content自己去实现;Googgle官方的SwipeRefreshLayout也是这样认为的,对比SwipeRefreshLayout,UltraPTR更加灵活,更容易扩展。

UltraPTR首先抽象出两个接口,功能接口和UI接口
PtrHandler代表下拉刷新的功能接口,包含刷新功能回调方法以及判断是否可以下拉的方法,用户实现此接口来进行数据刷新工作。
PtrUIHandler代表下拉刷新的UI接口,包含准备下拉、下拉中、下拉完成、下拉重置以及下拉过程中的位置变化等回调方法。通常情况下,Header需要实现此接口,来处理下拉刷新过程中头部UI的变化。

整个项目围绕核心类PtrFrameLayout。
PtrFrameLayout代表了一个下拉刷新的自定义控件。
PtrFrameLayout继承自ViewGroup,有且只能有两个子View,头部Header和内容Content。通常情况下,Header会实现PtrUIHandler接口,Content可以为任意的View。
和所有的自定义控件一样,PtrFrameLayout通过重写onFinishInflate、onMeasure、onLayout来确定控件的大小和位置,通过重写dispatchTouchEvent来确定控件的下拉行为。

使用方法:

 //使用上主要分四步
        //1、设置头部
        initHeaders();
        //2、添加头部
        ptrFrameLayout.setHeaderView(header);
        //3、处理下拉刷新过程中头部UI的变化
        ptrFrameLayout.addPtrUIHandler(header);
        //4、判断是否可以下拉,数据刷新工作。
        ptrFrameLayout.setPtrHandler(new PtrHandler() {

            //判断是否可以下拉刷新。 
            //UltraPTR 的 Content 可以包含任何内容,用户在这里判断决定是否可以下拉。
//例如,如果 Content 是 TextView,则可以直接返回 true,表示可以下拉刷新。
//如果 Content 是 ListView,当第一条在顶部时返回 true,表示可以下拉刷新。
//如果 Content 是 ScrollView,当滑动到顶部时返回 true,表示可以刷新。
            @Override
            public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {
                return true;
            }

            //开始刷新:刷新回调函数,
            //用户在这里写自己的刷新功能实现,处理业务数据的刷新。
            @Override
            public void onRefreshBegin(PtrFrameLayout frame) {
                progressBar.setVisibility(View.VISIBLE);
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        updateData(true);
                    }
                }, 3000);
            }
        });

头部的定制:

头部风格

  /**
         * //第一种头部
         * StoreHouse风格的头部实现
         */
        storeHouseHeader = new StoreHouseHeader(this);
        storeHouseHeader.setBackgroundColor(Color.BLACK);
        storeHouseHeader.setTextColor(Color.WHITE);
        storeHouseHeader.setLineWidth(5);
        storeHouseHeader.initWithString("ENGLISH ONLY HAHA");    //只可英文,中文不可运行(添加时间)
//"last update @" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())

        /**
         * //第二种头部
         * Material Design风格的头部实现
         */
        materialHeader = new MaterialHeader(this);
        materialHeader.setColorSchemeColors(new int[]{Color.RED, Color.GREEN, Color.BLUE});//类似SwipeRefreshLayout


        /**
         * //第三种头部
         * 经典 风格的头部实现
         */
        ptrClassicDefaultHeader = new PtrClassicDefaultHeader(this);

有6个参数可配置:

阻尼系数:Resistance
//默认: 1.7f,越大,感觉下拉时越吃力。

触发刷新时移动的位置比例:RatioOfHeaderHeightToRefresh
//默认,1.2f,移动达到头部高度1.2倍时可触发刷新操作。

回弹延时:DurationToClose
//默认 200ms,回弹到刷新高度所用时间

头部回弹时间:DurationToCloseHeader
//默认1000ms

刷新是保持头部:KeepHeaderWhenRefresh
//默认值 true.

下拉刷新 / 释放刷新:PullToRefresh
//默认为释放刷新,默认false  

xml中配置头部参数:

<in.srain.cube.views.ptr.PtrFrameLayout  
    android:id="@+id/store_house_ptr_frame"  
    xmlns:cube_ptr="http://schemas.android.com/apk/res-auto"  
    android:layout_width="match_parent"  
    android:layout_height="match_parent"  

    cube_ptr:ptr_resistance="1.7"  
    cube_ptr:ptr_ratio_of_header_height_to_refresh="1.2"  
    cube_ptr:ptr_duration_to_close="300"  
    cube_ptr:ptr_duration_to_close_header="2000"  
    cube_ptr:ptr_keep_header_when_refresh="true"  
    cube_ptr:ptr_pull_to_fresh="false" >  

    <LinearLayout  
        android:id="@+id/store_house_ptr_image_content"  
        android:layout_width="match_parent"  
        android:layout_height="match_parent"  
        android:background="@color/cube_mints_333333"  
        android:clickable="true"  
        android:padding="10dp">  

        <in.srain.cube.image.CubeImageView  
            android:id="@+id/store_house_ptr_image"  
            android:layout_width="match_parent"  
            android:layout_height="match_parent" />  
    </LinearLayout>  

</in.srain.cube.views.ptr.PtrFrameLayout>  

java代码中也可设置头部参数:

// the following are default settings  
mPtrFrame.setResistance(1.7f);  
mPtrFrame.setRatioOfHeaderHeightToRefresh(1.2f);  
mPtrFrame.setDurationToClose(200);  
mPtrFrame.setDurationToCloseHeader(1000);  
// default is false  
mPtrFrame.setPullToRefresh(false);  
// default is true  
mPtrFrame.setKeepHeaderWhenRefresh(true);  

示例:

布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:ptr="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <in.srain.cube.views.ptr.PtrFrameLayout
        android:id="@+id/ptrFrameLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        ptr:ptr_keep_header_when_refresh="true"
        ptr:ptr_pull_to_fresh="false"
        ptr:ptr_ratio_of_header_height_to_refresh="1.2"
        ptr:ptr_resistance="1.7">

        <ListView
            android:id="@+id/listView"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </in.srain.cube.views.ptr.PtrFrameLayout>

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyleLarge"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true" />

    <ImageButton
        android:id="@+id/btnBack"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_margin="@dimen/btnBackMargin"
        android:src="@mipmap/ic_launcher" />

</RelativeLayout>

java代码:

package com.example.administrator.myapplication;

import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.SimpleAdapter;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import in.srain.cube.views.ptr.PtrClassicDefaultHeader;
import in.srain.cube.views.ptr.PtrDefaultHandler;
import in.srain.cube.views.ptr.PtrFrameLayout;
import in.srain.cube.views.ptr.PtrHandler;
import in.srain.cube.views.ptr.header.MaterialHeader;
import in.srain.cube.views.ptr.header.StoreHouseHeader;
import in.srain.cube.views.ptr.util.PtrLocalDisplay;

/**
 * Created by Administrator on 2017/5/11.
 */

public class PtrActivity extends AppCompatActivity {

    private PtrFrameLayout ptrFrameLayout;
    private ListView listView;
    private ProgressBar progressBar;
    private ImageButton btnBack;
    private List<Map<String, String>> data;
    private Handler handler = new Handler();
    private SimpleAdapter adapter;
    private StoreHouseHeader storeHouseHeader;
    private MaterialHeader materialHeader;
    private PtrClassicDefaultHeader ptrClassicDefaultHeader;


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.ptr_layout);

        findViews();
        initData();
        initPtrRefresh();
        initBtnBack();
    }

    //第三步:
    private void initPtrRefresh() {
        //第3.1步:
        initHeaders();

//        ptrFrameLayout.setHeaderView(ptrClassicDefaultHeader);
//        ptrFrameLayout.addPtrUIHandler(ptrClassicDefaultHeader);

//        ptrFrameLayout.setHeaderView(storeHouseHeader);
//        ptrFrameLayout.addPtrUIHandler(storeHouseHeader);

        ptrFrameLayout.setHeaderView(materialHeader);//类似SwipeRefreshLayout
        ptrFrameLayout.addPtrUIHandler(materialHeader);


        ptrFrameLayout.setPtrHandler(new PtrHandler() {

            //检查是否可以刷新
            @Override
            public boolean checkCanDoRefresh(PtrFrameLayout frame, View content, View header) {
                return true;
            }

            //开始刷新
            @Override
            public void onRefreshBegin(PtrFrameLayout frame) {
                progressBar.setVisibility(View.VISIBLE);
                handler.postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        //第3.2步:
                        updateData(true);
                    }
                }, 3000);
            }
        });
    }

    //第3.1步:
    private void initHeaders() {

        /**
         * //第一种头部
         * StoreHouse风格的头部实现
         */
        storeHouseHeader = new StoreHouseHeader(this);
        storeHouseHeader.setBackgroundColor(Color.BLACK);
        storeHouseHeader.setTextColor(Color.WHITE);
        storeHouseHeader.setLineWidth(5);
        storeHouseHeader.initWithString("ENGLISH ONLY HAHA");    //只可英文,中文不可运行(添加时间)
//"last update @" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())

        /**
         * //第二种头部
         * Material Design风格的头部实现
         */
        materialHeader = new MaterialHeader(this);
        materialHeader.setColorSchemeColors(new int[]{Color.RED, Color.GREEN, Color.BLUE});//类似SwipeRefreshLayout


        /**
         * //第三种头部
         * 经典 风格的头部实现
         */
        ptrClassicDefaultHeader = new PtrClassicDefaultHeader(this);
    }

    //第3.2步:
    private void updateData(boolean addToTop) {
        HashMap<String, String> map = new HashMap<>();
        if (addToTop) {
            map.put("key", "im added head");
            ((LinkedList) data).addFirst(map);
        } else {
            map.put("key", "im added tail");
            ((LinkedList) data).addLast(map);
        }

        adapter.notifyDataSetChanged();
        progressBar.setVisibility(View.GONE);
        ptrFrameLayout.refreshComplete();
    }

    //第四步
    private void initBtnBack() {
        btnBack.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
//                listView.setSelection(0);
                listView.smoothScrollToPosition(0);
            }
        });
    }

    //第一步:
    private void findViews() {
        ptrFrameLayout = ((PtrFrameLayout) findViewById(R.id.ptrFrameLayout));
        listView = ((ListView) findViewById(R.id.listView));
        progressBar = ((ProgressBar) findViewById(R.id.progressBar));
        btnBack = ((ImageButton) findViewById(R.id.btnBack));
        progressBar.setVisibility(View.GONE);
    }

    //第二步:
    private void initData() {
        data = new LinkedList<>();
        for (int i = 0; i < 20; i++) {
            HashMap<String, String> map = new HashMap<>();
            map.put("key", "im item " + i);
            data.add(map);
        }
        adapter = new SimpleAdapter(this, data,
                android.R.layout.simple_list_item_1, new String[]{"key"}, new int[]{android.R.id.text1});
        listView.setAdapter(adapter);
    }
}

参考:

android-Ultra-Pull-To-Refresh 使用简介

android-Ultra-Pull-To-Refresh 的基本用法(适合于初学者)

Android 定制下拉刷新头部【原创】

支持上拉加载更多,下拉刷新的android-Ultra-Pull-To-Refresh改进库:

GitHub地址:captainbupt/android-Ultra-Pull-To-Refresh-With-Load-More

添加依赖:

  compile 'in.srain.cube:ptr-load-more:1.0.6'

使用方法

同android-Ultra-Pull-To-Refresh

唯一区别:

 /*支持上拉加载,下拉刷新*/
        ptrFrameLayout.setPtrHandler(new PtrDefaultHandler2() {
            @Override
            public void onLoadMoreBegin(PtrFrameLayout frame) {
                updateData(false);
            }

            @Override
            public void onRefreshBegin(PtrFrameLayout frame) {
                updateData(true);
            }
        });

        /*仅支持下拉刷新*/
        ptrFrameLayout.setPtrHandler(new PtrDefaultHandler() {
            @Override
            public void onRefreshBegin(PtrFrameLayout frame) {

            }
        });

参考:

Ultra-Pull-To-Refresh上拉加载的使用
UltraPullToRefreshWithLoadMore (为UltraPullToRefresh添加上拉加载更多功能)

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐