PullToRefresh的个性化扩展

一:实现区别下拉刷新和上拉加载

参考资料:http://blog.csdn.net/losetowin/article/details/18261389

在PullToRefresh的类库的com.handmark.pulltorefresh.library包下,打开PullToRefreshBase.java,在这个类的最后面添加代码。注意,需要重新添加library库。

//根据下拉和上拉显示的布局的可见状态类区分上拉还是下拉,然后执行相应操作
    public boolean isHeaderShown() {
        return getHeaderLayout().isShown();
    }

    public boolean isFooterShown() {
        return getFooterLayout().isShown();
    }

使用方法大概如下:

private boolean isRefreshing = false;//是否正在刷新的标志

private PullToRefreshListView news_list;//列表控件news_list

//设置上拉下拉事件
        news_list.setOnRefreshListener(new OnRefreshListener<ListView>() {

            @Override
            public void onRefresh(PullToRefreshBase<ListView> refreshView) {
                //在PullToRefresh的类库的com.handmark.pulltorefresh.library包下,打开PullToRefreshBase.java,在这个类的最后面添加代码。注意,需要重新添加library库。
                //原理:根据下拉和上拉显示的布局的可见状态类区分上拉还是下拉,然后执行相应操作
                if (!isRefreshing) {

                    isRefreshing = true;

                    if(refreshView.isHeaderShown()){
                        //下拉刷新 业务代码
                        refreshFirstPage();//刷新第一页数据
                    }else if(refreshView.isFooterShown()){
                        //上拉加载 业务代码
                        loadNextPage();//加载下一页内容
                    }
                }else{
                    //一般来说我们会开另一个线程去获取数据,所以这儿会加上一个判断,如果已经在获取数据了,就onRefreshComplete(),就是将下拉收起;否则就去开新线程取数据,取完记得也要onRefreshComplete()哦
                    news_list.onRefreshComplete();
                    isRefreshing = false;
                }
            }
        });

二:实现下拉刷新、下拉加载的图片个性化(图片居中)
参考资料:http://blog.csdn.net/superjunjin/article/details/45022595

定义刷新动画的layout

根据layout中的pull_to_refresh_header_vertical.xml文件修改成如下(图片居中,文字全部设置为gone。不占用空间)

<?xml version="1.0" encoding="utf-8"?>
<!-- (1)实现下拉刷新、下拉加载的动画个性化(图片居中) -->
<merge xmlns:android="http://schemas.android.com/apk/res/android" >

    <FrameLayout
        android:id="@+id/fl_inner"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="@dimen/header_footer_top_bottom_padding"
        android:paddingLeft="@dimen/header_footer_left_right_padding"
        android:paddingRight="@dimen/header_footer_left_right_padding"
        android:paddingTop="@dimen/header_footer_top_bottom_padding" >

        <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center" >

            <ImageView
                android:id="@+id/pull_to_refresh_image"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center" />

            <ProgressBar
                android:id="@+id/pull_to_refresh_progress"
                style="?android:attr/progressBarStyleSmall"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:indeterminate="true"
                android:visibility="gone" />

        </FrameLayout>

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:gravity="center_horizontal"
            android:orientation="vertical" >

            <TextView
                android:id="@+id/pull_to_refresh_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:singleLine="true"
                android:textAppearance="?android:attr/textAppearance"
                android:textStyle="bold"
                android:visibility="gone" />

            <TextView
                android:id="@+id/pull_to_refresh_sub_text"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:singleLine="true"
                android:textAppearance="?android:attr/textAppearanceSmall"
                android:visibility="gone" />
        </LinearLayout>
    </FrameLayout>

</merge>

pull_to_refresh_header_custom.xml

设置自定义动画效果

设置一个简单的京东小人走的动画效果,在drawable文件夹下新建一个xml

<?xml version="1.0" encoding="utf-8"?>
<!-- (2)实现下拉刷新、下拉加载的动画个性化(图片居中) -->
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">

    <item android:drawable="@drawable/app_refresh_people_0" android:duration="100"></item>
    <item android:drawable="@drawable/app_refresh_people_1" android:duration="100"></item>
    <item android:drawable="@drawable/app_refresh_people_2" android:duration="100"></item>
    <item android:drawable="@drawable/app_refresh_people_3" android:duration="100"></item>

</animation-list>

jd_refreshlist.xml

新建刷新动画的layout,TweenAnimLoadingLayout,类似于之前的源码中的FlipLoadingLayout和RotateLoadingLayout

package com.handmark.pulltorefresh.library.internal;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.View;

import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode;
import com.handmark.pulltorefresh.library.PullToRefreshBase.Orientation;
import com.handmark.pulltorefresh.library.R;
/**
 * (3)实现下拉刷新、下拉加载的动画个性化(图片居中)*/
public class TweenAnimLoadingLayout extends LoadingLayout{

    private AnimationDrawable animationDrawable;//创建动画序列对象

    public TweenAnimLoadingLayout(Context context, Mode mode,
            Orientation scrollDirection, TypedArray attrs) {
        super(context, mode, scrollDirection, attrs);
        // TODO Auto-generated constructor stub

        //初始化
        mHeaderImage.setImageResource(R.drawable.jd_refreshlist);
        animationDrawable = (AnimationDrawable) mHeaderImage.getDrawable();

    }

    // 默认图片
    protected int getDefaultDrawableResId() {
        // TODO Auto-generated method stub
        return R.drawable.app_refresh_people_0;
    }

    @Override
    protected void onLoadingDrawableSet(Drawable imageDrawable) {

    }

    @Override
    protected void onPullImpl(float scaleOfLayout) {
        // TODO Auto-generated method stub

    }

     // 下拉以刷新
    protected void pullToRefreshImpl() {
        // TODO Auto-generated method stub

    }

    // 正在刷新时回调
    protected void refreshingImpl() {
        // 播放帧动画
        animationDrawable.start();
    }

    // 释放以刷新
    protected void releaseToRefreshImpl() {
        // TODO Auto-generated method stub

    }

    // 重新设置
    protected void resetImpl() {
         mHeaderImage.setVisibility(View.VISIBLE);
         mHeaderImage.clearAnimation();  

    }

}

TweenAnimLoadingLayout

替换之前的布局文件,在LoadingLayout类的构造函数中修改引用的布局文件:

public LoadingLayout(Context context, final Mode mode, final Orientation scrollDirection, TypedArray attrs) {
        super(context);
        mMode = mode;
        mScrollDirection = scrollDirection;

        switch (scrollDirection) {
            case HORIZONTAL:
                LayoutInflater.from(context).inflate(R.layout.pull_to_refresh_header_horizontal, this);

                break;
            case VERTICAL:
            default:
                //LayoutInflater.from(context).inflate(R.layout.pull_to_refresh_header_vertical, this);

                /*(4)实现下拉刷新、下拉加载的动画个性化(图片居中)*/
                LayoutInflater.from(context).inflate(R.layout.pull_to_refresh_header_custom, this);
                break;
        }

LoadingLayout

替换之前的刷新layout为TweenAnimLoadingLayout

找到library项目com.handmark.pulltorefresh.library包下的PullToRefreshListView的createLoadingLayout进入,在createLoadingLayout方法中再进入createLoadingLayout,找到最原始的新建动画layout的地方,把默认的RotateLoadingLayout改成TweenAnimLoadingLayout就行了。在PullToRefreshBase类下:

LoadingLayout createLoadingLayout(Context context, Mode mode, Orientation scrollDirection, TypedArray attrs) {
            switch (this) {
                case ROTATE:
                default:
                    //return new RotateLoadingLayout(context, mode, scrollDirection, attrs);
                    /*(5)实现下拉刷新、下拉加载的动画个性化(图片居中)*/
                    return new TweenAnimLoadingLayout(context, mode, scrollDirection, attrs);
                case FLIP:
                    return new FlipLoadingLayout(context, mode, scrollDirection, attrs);
            }
        }

PullToRefreshBase

三:实现下拉刷新、下拉加载的动画自定义

1、需要将项目中用到的动画文件和图片资源复制一份到library工程中。

2、主要修改RotateLoadingLayout文件

/*******************************************************************************
 * Copyright 2011, 2012 Chris Banes.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************/
package com.handmark.pulltorefresh.library.internal;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Matrix;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.RotateAnimation;
import android.widget.ImageView.ScaleType;

import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode;
import com.handmark.pulltorefresh.library.PullToRefreshBase.Orientation;
import com.handmark.pulltorefresh.library.R;

public class RotateLoadingLayout extends LoadingLayout {

    static final int ROTATION_ANIMATION_DURATION = 1200;

    private final Animation mRotateAnimation;
    private final Matrix mHeaderImageMatrix;

    private float mRotationPivotX, mRotationPivotY;

    private final boolean mRotateDrawableWhilePulling;

    /*(1)实现自定义加载动画*/
    private boolean mUseIntrinsicAnimation;//标记传入的drawable是否是AnimationDrawable
    private AnimationDrawable animationDrawable;//创建动画序列对象

    public RotateLoadingLayout(Context context, Mode mode, Orientation scrollDirection, TypedArray attrs) {
        super(context, mode, scrollDirection, attrs);

        mRotateDrawableWhilePulling = attrs.getBoolean(R.styleable.PullToRefresh_ptrRotateDrawableWhilePulling, true);

        mHeaderImage.setScaleType(ScaleType.MATRIX);
        mHeaderImageMatrix = new Matrix();
        mHeaderImage.setImageMatrix(mHeaderImageMatrix);

        mRotateAnimation = new RotateAnimation(0, 720, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF,
                0.5f);
        mRotateAnimation.setInterpolator(ANIMATION_INTERPOLATOR);
        mRotateAnimation.setDuration(ROTATION_ANIMATION_DURATION);
        mRotateAnimation.setRepeatCount(Animation.INFINITE);
        mRotateAnimation.setRepeatMode(Animation.RESTART);
    }

    public void onLoadingDrawableSet(Drawable imageDrawable) {

        /*(2)实现自定义加载动画*/
        //如果传进来的是动画,那么
        if(imageDrawable instanceof AnimationDrawable){

            mUseIntrinsicAnimation = true;//设置标记值为true
            mHeaderImage.setImageResource(R.drawable.jd_refreshlist);//给图标引用想用的动画(此处需要保证项目中用到的动画文件和图片资源复制一份到library中)
            animationDrawable = (AnimationDrawable) imageDrawable;
        }
        else{
            if (null != imageDrawable) {
                mRotationPivotX = Math.round(imageDrawable.getIntrinsicWidth() / 2f);
                mRotationPivotY = Math.round(imageDrawable.getIntrinsicHeight() / 2f);
            }
        }

    }

    protected void onPullImpl(float scaleOfLayout) {
        /*(2)实现自定义加载动画*/
        //如果传进来的是动画,那么
        if(mUseIntrinsicAnimation){

        }else{
            float angle;
            if (mRotateDrawableWhilePulling) {
                angle = scaleOfLayout * 90f;
            } else {
                angle = Math.max(0f, Math.min(180f, scaleOfLayout * 360f - 180f));
            }

            mHeaderImageMatrix.setRotate(angle, mRotationPivotX, mRotationPivotY);
            mHeaderImage.setImageMatrix(mHeaderImageMatrix);
        }

    }

    // 正在刷新时回调
    protected void refreshingImpl() {

        /*(2)实现自定义加载动画*/
        //如果传进来的是动画,那么
        if(mUseIntrinsicAnimation){
            animationDrawable.start();// 播放帧动画
        }else{
            mHeaderImage.startAnimation(mRotateAnimation);// 播放帧动画
        }

    }

     // 重新设置
    protected void resetImpl() {
        /*(2)实现自定义加载动画*/
        //如果传进来的是动画,那么
        if(mUseIntrinsicAnimation){
            mHeaderImage.setVisibility(View.VISIBLE);
            mHeaderImage.clearAnimation();
        }else{
            mHeaderImage.clearAnimation();
            resetImageRotation();
        }

    }

    private void resetImageRotation() {
        /*(2)实现自定义加载动画*/
        //如果传进来的是动画,那么
        if(mUseIntrinsicAnimation){

        }else{
            if (null != mHeaderImageMatrix) {
                mHeaderImageMatrix.reset();
                mHeaderImage.setImageMatrix(mHeaderImageMatrix);
            }
        }

    }

    // 下拉以刷新
    protected void pullToRefreshImpl() {
        // NO-OP
    }

     // 释放以刷新
    protected void releaseToRefreshImpl() {
        // NO-OP
    }

    // 默认图片
    protected int getDefaultDrawableResId() {
        /*(2)实现自定义加载动画*/
        //如果传进来的是动画,那么
        if(mUseIntrinsicAnimation){
            return R.drawable.app_refresh_people_0;
        }else{
            return R.drawable.default_ptr_rotate;
        }

    }

}

RotateLoadingLayout

3、使用方法

//额外的设置:设置下拉刷新和上拉加载的图片和文字,背景颜色等
    private void setPullToRefreshAttribute(){

        ILoadingLayout startLabels = news_list.getLoadingLayoutProxy(true, false);
        startLabels.setPullLabel("下拉刷新...");// 刚下拉时,显示的提示
        startLabels.setReleaseLabel("松开刷新...");//下来达到一定距离时,显示的提示
        startLabels.setRefreshingLabel("正在刷新...");// 刷新时

        /*(3)实现自定义加载动画*/
        //设置加载动画图标:方式一
        AnimationDrawable jdAnimation = (AnimationDrawable) getResources().getDrawable(R.drawable.jd_refreshlist);
        startLabels.setLoadingDrawable(jdAnimation);

        ILoadingLayout endLabels = news_list.getLoadingLayoutProxy(false, true);
        endLabels.setPullLabel("上拉加载...");// 刚下拉时,显示的提示
        endLabels.setReleaseLabel("松开加载...");//下来达到一定距离时,显示的提示
        endLabels.setRefreshingLabel("正在加载...");// 刷新时
        /*(3)实现自定义加载动画*/
        //设置加载动画图标:方式二
        Drawable drawable2 = (Drawable) getResources().getDrawable(R.drawable.progressbar1);
        endLabels.setLoadingDrawable(drawable2);
    }

时间: 2024-10-18 19:16:40

PullToRefresh的个性化扩展的相关文章

Android项目:使用pulltorefresh开源项目扩展为下拉刷新上拉加载更多的处理方法,监听listview滚动方向

很多android应用的下拉刷新都是使用的pulltorefresh这个开源项目,但是它的扩展性在下拉刷新同时又上拉加载更多时会有一定的局限性.查了很多地方,发现这个开源项目并不能很好的同时支持下拉刷新和上拉加载更多.这个组件有个mode的属性,可以设置为both,即上下同时都可拉动.但是只设置这个属性的话,上拉与下拉产生的效果是完全一致的.所以要使用这个开源项目做到下拉刷新并同时可上拉加载更多,就需要在代码中进行一些处理. ==========================pulltoref

App个性化安装——程序第三方安装的新舞台!

现今业界的一个共识是:移动互联网并不是PC互联网的扩展,移动互联网是一种新的互联网形态,传统的程序第三方安装服务生存的空间不存在了,但移动互联网的新特点,却为新的程序(App)第三方安装提供了舞台. 这个第三方安装的新舞台就是:App个性化安装. 移动设备的应用程序安装,不必再如PC程序安装一样千篇一律地标准化了,而是需要在应用安装过程实现APP个性化安装,以满足不同客户的个性化需求.这就好比一个顾客刚进饭馆,就看到店家已经备好了合乎自己心意的菜肴一样--这样的个性化服务,肯定比排位.叫号.点菜

软件体系结构---安卓系统架构之应用程序框架层分析---1

本博客只介绍安卓系统架构中的应用程序框架层 什么是应用程序框架? 应用程序框架可以说是一个应用程序的核心,是所有参与开发的程序员共同使用和遵守的约定,大家在其约定上进行必要的扩展,但程序始终保持主体结构的一致性.其作用是让程序保持清晰和一目了然,在满足不同需求的同时又不互相影响. 而对于安卓来说:Android系统提供给应用开发者的本身就是一个框架,所有的应用开发都必须遵守这个框架的原则.我们在开发应用时就是在这个框架上进行扩展.在这个框架中我们可以完全访问核心应用程序所使用的API框架,即我们

LibRec: 基于机器学习的大数据推荐系统

简介: LibRec 是领先的推荐系统Java开源算法工具库,覆盖了70余个各类型推荐算法,有效解决评分预测和物品推荐两大关键的推荐问题.推荐系统是机器学习和大数据技术的经典实际应用,旨在提供高效准确的个性化物品推荐,是现代Web应用的重要组件. 项目结构清晰,代码风格良好,测试充分,注释与手册完善.目前项目使用GPL3.0协议开源在github中,欢迎大家试用. Librec: http://www.librec.net/ GithubRepo:  https://github.com/guo

01 Apache Solr:提升检索体验 为什么是Solr

背景: 最近开发一个大型的仓储管理平台项目,项目的前身是无数个版本的历史悠久的基于CS模式的Windows桌面程序.然后对于每一个客户,我们可能需要为之定制比较个性化的特殊功能.于是,有一个核心研发团队,以一两年为周期开发一个核心功能版本的软件:然后拿出去推广销售,每每销售成功,做售前的同事都是拿了一大堆定制化的需求回来的:然后一场在核心功能上的定制和个性化扩展就开始了,完成开发就可以去客户现场实施了:最后,就会有部分维护的同事将这个客户的系统纳入他们的日常工作清单中.周而复始.诚然,这种方式在

Visual Studio Code,完美的编辑器

今日凌晨,微软的文本(代码)编辑器 Visual Studio Code(简称 VS Code),发布了首个正式版,距离首个 beta 版上线时间刚好一年. 在十多年的编程经历中,我使用过非常多的的代码编辑器(包括 IDE),例如 FrontPage.Dreamweaver.EditPlus.EmEditor.Notepad++.Apatana.MyEclipse.TextMate.Coda.VIM.Intellij IDEA.Sublime Text.PhpStorm.Atom.Bracket

列表组件概述(转)

全文转至:http://www.cnblogs.com/lyzg/ 这次要介绍的是列表组件.为了写它,我花了有将近2周的晚上,才一点一点的把它写到现在这个程度.到目前为止,一共写了有17个文件,虽然没有覆盖到一些更复杂的场景,但是把我当时计划写这个组件的基本目的已经完成了.先给大家看看我最后写出来的文件情况: 也许有人会好奇,一个列表的功能怎么会写出这么多东西出来?关于这个问题的答案,我稍后再来总结,先让我描述下我写这些东西之前产生的想法. 1. 背景介绍 我是去年5月份在上家公司开始做的前端开

代码生成器原理

今天突然想玩玩这个..搞搞代码生成器,今天把原理发出来..写好Demo陆续更新 整个架设思路分的4个部分:A:底层物理数据库层,主要是存储数据用的.B:数据库访问层,主要是为了写一套代码可以跑在多种数据库上.C:一些辅助工具.基础组件,是为了加强自动产生代码的功能.简化代码复杂性,进行合理的分工协作用的.D:自动生成的代码部分,用PowerDesigner设计简洁明了.易于沟通理解,代码分自动生成及人工部分,为了重复生成方便. 详细功能部分只要是分12个部分来讲解,分别如下:01:我业务里需要的

C#装箱与拆箱的研究

在对这个问题展开讨论之前,我们不妨先来问这么几个问题,以系统的了解我们今天要探究的主题. 观者也许曾无数次的使用过诸如System.Console类或.NET类库中那些品种繁多的类.那么,我想问的是它们究竟源自何处?C#又是如何联系它们?有没有支持我们个性化扩展的机制或类型系统?又有哪些类型系统可供我们使用呢?如果我们这些PL们连这些问题都不知其然,更不知其所以然的话,C#之门恐怕会把我们拒之门外的. 那就让我们先停停手中的活儿,理理头绪,对作为.NET重要技术和基础之一的CTS(Common