master 903c9a547c9f cached
41 files
87.2 KB
21.3k tokens
144 symbols
1 requests
Download .txt
Repository: linuxjava/HorizontalRefreshLayout
Branch: master
Commit: 903c9a547c9f
Files: 41
Total size: 87.2 KB

Directory structure:
gitextract_0us6p602/

├── README.md
├── apk/
│   └── app-debug.apk
├── app/
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── com/
│           │       └── example/
│           │           └── robincxiao/
│           │               └── horizontalrefreshlayout/
│           │                   ├── LayoutAdapter.java
│           │                   └── MainActivity.java
│           └── res/
│               ├── drawable/
│               │   └── item_background.xml
│               ├── layout/
│               │   ├── activity_main.xml
│               │   └── item.xml
│               ├── values/
│               │   ├── colors.xml
│               │   ├── dimens.xml
│               │   ├── strings.xml
│               │   └── styles.xml
│               └── values-w820dp/
│                   └── dimens.xml
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── jcenter-push.gradle
├── lib/
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── xiao/
│           │       └── free/
│           │           └── horizontalrefreshlayout/
│           │               ├── HorizontalRefreshLayout.java
│           │               ├── RefreshCallBack.java
│           │               ├── RefreshHeader.java
│           │               ├── refreshhead/
│           │               │   ├── LoadingRefreshHeader.java
│           │               │   ├── MaterialRefreshHeader.java
│           │               │   └── NiceRefreshHeader.java
│           │               └── widget/
│           │                   ├── CircleImageView.java
│           │                   └── MaterialProgressDrawable.java
│           └── res/
│               ├── drawable/
│               │   ├── animated_rotate.xml
│               │   ├── animated_rotate_1.xml
│               │   └── spinner.xml
│               ├── layout/
│               │   ├── common_loading_refresh_header.xml
│               │   ├── material_refresh_header.xml
│               │   └── nice_refresh_header.xml
│               └── values/
│                   └── strings.xml
└── settings.gradle

================================================
FILE CONTENTS
================================================

================================================
FILE: README.md
================================================
:running:HorizontalRefreshLayout-Android:running:
============

开发者使用 HorizontalRefreshLayout-Android 可以对RecycView、Listview、ScrollView等控件实现左右刷新

##  APK下载
[Download](https://github.com/linuxjava/HorizontalRefreshLayout/raw/master/apk/app-debug.apk)
##  Demo使用
运行demo需删除gradle.properties中的代理
```xml
systemProp.http.proxyHost=dev-proxy.oa.com
systemProp.http.proxyPort=8080
systemProp.https.proxyHost=dev-proxy.oa.com
systemProp.https.proxyPort=8080
```
## Gradle配置
compile 'xiao.free.horizontalrefreshlayout:lib:v0.1.2'
## XML配置
```xml
<xiao.free.horizontalrefreshlayout.HorizontalRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/refresh"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/blue">

    <com.lsjwzh.widget.recyclerviewpager.RecyclerViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipToPadding="false"
        app:rvp_flingFactor="0.15"
        app:rvp_singlePageFling="false"
        app:rvp_triggerOffset="0.5" />

</xiao.free.horizontalrefreshlayout.HorizontalRefreshLayout>
```
## Java代码
```java
refreshLayout = (HorizontalRefreshLayout) findViewById(R.id.refresh);
refreshLayout.setRefreshCallback(this);
refreshLayout.setRefreshHeader(new LoadingRefreshHeader(this), HorizontalRefreshLayout.LEFT);
refreshLayout.setRefreshHeader(new LoadingRefreshHeader(this), HorizontalRefreshLayout.RIGHT);
```
通过setRefreshHeader方法可以设置左右刷新头部,库中已支持三种刷新效果,如下图所示:

![image](https://github.com/linuxjava/HorizontalRefreshLayout/raw/master/gif/1.gif) 
![image](https://github.com/linuxjava/HorizontalRefreshLayout/raw/master/gif/2.gif)
![image](https://github.com/linuxjava/HorizontalRefreshLayout/raw/master/gif/3.gif)

## 自定义Header
可通过实现如下接口实现自定义header
```java
public interface RefreshHeader {
    /**
     * @param dragPosition  HorizontalRefreshLayout.START or HorizontalRefreshLayout.END
     */
    void onStart(int dragPosition, View refreshHead);

    /**
     * @param distance
     */
    void onDragging(float distance, float percent, View refreshHead);

    void onReadyToRelease(View refreshHead);

    @NonNull View getView(ViewGroup container);

    void onRefreshing(View refreshHead);
}
```
具体可参考lib库中refreshhead目录中的实现


================================================
FILE: app/build.gradle
================================================
apply plugin: 'com.android.application'

android {
    compileSdkVersion ANDROID_BUILD_SDK_VERSION as int
    buildToolsVersion ANDROID_BUILD_TOOLS_VERSION
    defaultConfig {
        applicationId "com.example.robincxiao.horizontalrefreshlayout"
        minSdkVersion 14
        targetSdkVersion ANDROID_BUILD_SDK_VERSION
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    compile 'com.github.lsjwzh.RecyclerViewPager:lib:v1.1.2'
    //compile project(':lib')
    compile 'xiao.free.horizontalrefreshlayout:lib:v0.1.2'
    //compile 'xiao.free.horizontalrefreshlayout:lib:v1.0.0'
}


================================================
FILE: app/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\android-sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}


================================================
FILE: app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.robincxiao.horizontalrefreshlayout">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

================================================
FILE: app/src/main/java/com/example/robincxiao/horizontalrefreshlayout/LayoutAdapter.java
================================================
/*
 * Copyright (C) 2014 Lucas Rocha
 *
 * 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.example.robincxiao.horizontalrefreshlayout;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

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

public class LayoutAdapter extends RecyclerView.Adapter<LayoutAdapter.SimpleViewHolder> {
    private static final int DEFAULT_ITEM_COUNT = 5;

    private final Context mContext;
    private final RecyclerView mRecyclerView;
    private final List<Integer> mItems;
    private int mCurrentItemId = 0;
    private int[] imageIds = {R.mipmap.card_cover1, R.mipmap.card_cover2, R.mipmap.card_cover3,
            R.mipmap.card_cover4, R.mipmap.card_cover5, R.mipmap.card_cover6,
            R.mipmap.card_cover7, R.mipmap.card_cover8};

    public static class SimpleViewHolder extends RecyclerView.ViewHolder {
        public final TextView title;
        public final ImageView myImage;

        public SimpleViewHolder(View view) {
            super(view);
            title = (TextView) view.findViewById(R.id.title);
            myImage = (ImageView) view.findViewById(R.id.image);
        }
    }

    public LayoutAdapter(Context context, RecyclerView recyclerView) {
        this(context, recyclerView, DEFAULT_ITEM_COUNT);
    }

    public LayoutAdapter(Context context, RecyclerView recyclerView, int itemCount) {
        mContext = context;
        mItems = new ArrayList<>(itemCount);
        for (int i = 0; i < itemCount; i++) {
            addItem(i);
        }

        mRecyclerView = recyclerView;
    }

    public void addItem(int position) {
        final int id = mCurrentItemId++;
        mItems.add(position, id);
        notifyItemInserted(position);
    }

    public void removeItem(int position) {
        mItems.remove(position);
        notifyItemRemoved(position);
    }

    public void getMore() {
        int size = getItemCount();
        for (int i = size; i < size + 5; i++) {
            addItem(i);
        }
    }

    @Override
    public SimpleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        final View view = LayoutInflater.from(mContext).inflate(R.layout.item, parent, false);
        return new SimpleViewHolder(view);
    }

    @Override
    public void onBindViewHolder(SimpleViewHolder holder, int position) {
        holder.title.setText("Index " + mItems.get(position));
        holder.myImage.setImageResource(imageIds[position % imageIds.length]);

        final View itemView = holder.itemView;
        itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(mContext, "", Toast.LENGTH_SHORT).show();
            }
        });
        final int itemId = mItems.get(position);
    }

    @Override
    public int getItemCount() {
        return mItems.size();
    }
}


================================================
FILE: app/src/main/java/com/example/robincxiao/horizontalrefreshlayout/MainActivity.java
================================================
package com.example.robincxiao.horizontalrefreshlayout;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;

import com.lsjwzh.widget.recyclerviewpager.RecyclerViewPager;

import xiao.free.horizontalrefreshlayout.HorizontalRefreshLayout;
import xiao.free.horizontalrefreshlayout.RefreshCallBack;
import xiao.free.horizontalrefreshlayout.refreshhead.LoadingRefreshHeader;
import xiao.free.horizontalrefreshlayout.refreshhead.MaterialRefreshHeader;
import xiao.free.horizontalrefreshlayout.refreshhead.NiceRefreshHeader;

public class MainActivity extends AppCompatActivity implements RefreshCallBack {
    private HorizontalRefreshLayout refreshLayout;
    protected RecyclerViewPager mRecyclerView;
    private LayoutAdapter mLayoutAdapter;

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

        refreshLayout = (HorizontalRefreshLayout) findViewById(R.id.refresh);
        refreshLayout.setRefreshCallback(this);
        refreshLayout.setRefreshHeader(new NiceRefreshHeader(this), HorizontalRefreshLayout.LEFT);
        refreshLayout.setRefreshHeader(new NiceRefreshHeader(this), HorizontalRefreshLayout.RIGHT);

        mRecyclerView = (RecyclerViewPager) findViewById(R.id.viewpager);
        LinearLayoutManager layout = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);
        mRecyclerView.setLayoutManager(layout);
        mLayoutAdapter = new LayoutAdapter(this, mRecyclerView);
        mRecyclerView.setAdapter(mLayoutAdapter);
        mRecyclerView.setHasFixedSize(true);
        mRecyclerView.setLongClickable(true);

        mRecyclerView.addOnPageChangedListener(new RecyclerViewPager.OnPageChangedListener() {
            @Override
            public void OnPageChanged(int oldPosition, int newPosition) {
                int size = mLayoutAdapter.getItemCount();
                if (size > 1 && newPosition == size - 1) {
                    //mLayoutAdapter.getMore();
                    //refreshLayout.startAutoRefresh(HorizontalRefreshLayout.RIGHT);
                }
            }
        });

        //refreshLayout.startAutoRefresh(HorizontalRefreshLayout.LEFT);
    }

    @Override
    public void onLeftRefreshing() {
        refreshLayout.postDelayed(new Runnable() {
            @Override
            public void run() {
                refreshLayout.onRefreshComplete();
            }
        }, 2000);
    }

    @Override
    public void onRightRefreshing() {
        refreshLayout.postDelayed(new Runnable() {
            @Override
            public void run() {
                mLayoutAdapter.getMore();
                refreshLayout.onRefreshComplete();
            }
        }, 2000);
    }

}


================================================
FILE: app/src/main/res/drawable/item_background.xml
================================================
<!--
  ~ Copyright (C) 2014 Lucas Rocha
  ~
  ~ 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.
  -->

<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_activated="true"
          android:drawable="@color/item_activated_color"/>

    <item android:state_pressed="true"
          android:drawable="@color/item_pressed_color"/>

    <item>
        <shape android:shape="rectangle">
            <solid android:color="@color/material_blue_grey_900"></solid>
            <stroke android:color="@color/item_activated_color" android:width="2px"></stroke>
            <corners android:radius="5dp"></corners>
        </shape>
    </item>

</selector>

================================================
FILE: app/src/main/res/layout/activity_main.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<xiao.free.horizontalrefreshlayout.HorizontalRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/refresh"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/blue">

    <com.lsjwzh.widget.recyclerviewpager.RecyclerViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipToPadding="false"
        app:rvp_flingFactor="0.15"
        app:rvp_singlePageFling="false"
        app:rvp_triggerOffset="0.5" />

</xiao.free.horizontalrefreshlayout.HorizontalRefreshLayout>


================================================
FILE: app/src/main/res/layout/item.xml
================================================
<?xml version="1.0" encoding="utf-8"?>

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginBottom="40dp"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"
        android:layout_marginTop="40dp"
        android:background="@mipmap/home_card_bg">

        <TextView
            android:id="@+id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="#000000"
            android:textSize="22.0sp"
            android:textStyle="bold"
            android:layout_marginLeft="10dp"
            android:layout_marginTop="10dp"/>

        <ImageView
            android:id="@+id/image"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:scaleType="centerCrop"
            android:layout_centerVertical="true"/>
    </RelativeLayout>

</FrameLayout>

================================================
FILE: app/src/main/res/values/colors.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#3F51B5</color>
    <color name="colorPrimaryDark">#303F9F</color>
    <color name="colorAccent">#FF4081</color>

    <color name="item_pressed_color">#CCCCCC</color>
    <color name="item_activated_color">#77CEEE</color>
    <color name="blue">#ff33b5e5</color>
</resources>


================================================
FILE: app/src/main/res/values/dimens.xml
================================================
<resources>
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>
</resources>


================================================
FILE: app/src/main/res/values/strings.xml
================================================
<resources>
    <string name="app_name">HorizontalRefreshLayout</string>
</resources>


================================================
FILE: app/src/main/res/values/styles.xml
================================================
<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>

</resources>


================================================
FILE: app/src/main/res/values-w820dp/dimens.xml
================================================
<resources>
    <!-- Example customization of dimensions originally defined in res/values/dimens.xml
         (such as screen margins) for screens with more than 820dp of available width. This
         would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
    <dimen name="activity_horizontal_margin">64dp</dimen>
</resources>


================================================
FILE: build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:$GRADLE_VERSION"

        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'
        classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        maven { url "https://jitpack.io" }
        jcenter()
    }

    tasks.withType(Javadoc).all {
        enabled = false
        options.setEncoding('UTF-8')
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}


================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
#Mon Dec 28 10:00:20 PST 2015
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip


================================================
FILE: gradle.properties
================================================
# Project-wide Gradle settings.

# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.

# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html

# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m

# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
#gradle版本
GRADLE_VERSION=2.1.0
#目标SDK版本
ANDROID_BUILD_TARGET_SDK_VERSION=19
#编译SDK版本
ANDROID_BUILD_SDK_VERSION=23
#编译工具版本
ANDROID_BUILD_TOOLS_VERSION=23.0.2
#V7包版本
SUPPORT_LIBRARY_VERSION=23.4.0

#代理
systemProp.http.proxyHost=dev-proxy.oa.com
systemProp.http.proxyPort=8080
systemProp.https.proxyHost=dev-proxy.oa.com
systemProp.https.proxyPort=8080


================================================
FILE: gradlew
================================================
#!/usr/bin/env bash

##############################################################################
##
##  Gradle start up script for UN*X
##
##############################################################################

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""

APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"

warn ( ) {
    echo "$*"
}

die ( ) {
    echo
    echo "$*"
    echo
    exit 1
}

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
  CYGWIN* )
    cygwin=true
    ;;
  Darwin* )
    darwin=true
    ;;
  MINGW* )
    msys=true
    ;;
esac

# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
    ls=`ls -ld "$PRG"`
    link=`expr "$ls" : '.*-> \(.*\)$'`
    if expr "$link" : '/.*' > /dev/null; then
        PRG="$link"
    else
        PRG=`dirname "$PRG"`"/$link"
    fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar

# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
        # IBM's JDK on AIX uses strange locations for the executables
        JAVACMD="$JAVA_HOME/jre/sh/java"
    else
        JAVACMD="$JAVA_HOME/bin/java"
    fi
    if [ ! -x "$JAVACMD" ] ; then
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
    fi
else
    JAVACMD="java"
    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi

# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
    MAX_FD_LIMIT=`ulimit -H -n`
    if [ $? -eq 0 ] ; then
        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
            MAX_FD="$MAX_FD_LIMIT"
        fi
        ulimit -n $MAX_FD
        if [ $? -ne 0 ] ; then
            warn "Could not set maximum file descriptor limit: $MAX_FD"
        fi
    else
        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
    fi
fi

# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi

# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
    JAVACMD=`cygpath --unix "$JAVACMD"`

    # We build the pattern for arguments to be converted via cygpath
    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
    SEP=""
    for dir in $ROOTDIRSRAW ; do
        ROOTDIRS="$ROOTDIRS$SEP$dir"
        SEP="|"
    done
    OURCYGPATTERN="(^($ROOTDIRS))"
    # Add a user-defined pattern to the cygpath arguments
    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
    fi
    # Now convert the arguments - kludge to limit ourselves to /bin/sh
    i=0
    for arg in "$@" ; do
        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option

        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
        else
            eval `echo args$i`="\"$arg\""
        fi
        i=$((i+1))
    done
    case $i in
        (0) set -- ;;
        (1) set -- "$args0" ;;
        (2) set -- "$args0" "$args1" ;;
        (3) set -- "$args0" "$args1" "$args2" ;;
        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
    esac
fi

# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
    JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"

exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"


================================================
FILE: gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem  Gradle startup script for Windows
@rem
@rem ##########################################################################

@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal

@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=

set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome

set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init

echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe

if exist "%JAVA_EXE%" goto init

echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:init
@rem Get command-line arguments, handling Windowz variants

if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args

:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2

:win9xME_args_slurp
if "x%~1" == "x" goto execute

set CMD_LINE_ARGS=%*
goto execute

:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$

:execute
@rem Setup the command line

set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd

:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1

:mainEnd
if "%OS%"=="Windows_NT" endlocal

:omega


================================================
FILE: jcenter-push.gradle
================================================
apply plugin: 'com.jfrog.bintray'
apply plugin: 'com.github.dcendents.android-maven'

def siteUrl = "https://github.com/linuxjava/HorizontalRefreshLayout"
def gitUrl = "https://github.com/linuxjava/HorizontalRefreshLayout.git"

group = 'xiao.free.horizontalrefreshlayout'// library name
version = 'v0.1.2'// version

install {
    repositories.mavenInstaller {
        // This generates POM.xml with proper paramters
        pom {
            project {
                packaging 'aar'

                name 'HorizontalRefreshLayout for Android'//添加项目描述
                url siteUrl

                licenses {
                    license {
                        name 'The Apache Software License, Version 2.0'
                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
                    }
                }

                developers {
                    developer {
                        id 'guochangxiao'
                        name 'guochangxiao'
                        email 'guochangxiao@gmail.com'
                    }
                }

                scm {
                    connection gitUrl
                    developerConnection gitUrl
                    url siteUrl
                }
            }
        }
    }
}

task sourcesJar(type: Jar) {
    from android.sourceSets.main.java.srcDirs
    classifier = 'sources'
}

task javadoc(type: Javadoc) {
    source = android.sourceSets.main.java.srcDirs
    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
}

task javadocJar(type: Jar, dependsOn: javadoc) {
    classifier = 'javadoc'
    from javadoc.destinationDir
}

artifacts {
    archives javadocJar
    archives sourcesJar
}

Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())

bintray {
    user = properties.getProperty("bintray.user")
    key = properties.getProperty("bintray.apikey")

    configurations = ['archives']

    pkg {
        repo = "maven" //JCenter上仓储名
        name = "horizontalrefreshlayout" //JCenter上的项目中的packageName
        websiteUrl = siteUrl
        vcsUrl = gitUrl
        licenses = ["Apache-2.0"]
        publish = true
    }
}

================================================
FILE: lib/build.gradle
================================================
apply plugin: 'com.android.library'

android {
    compileSdkVersion ANDROID_BUILD_SDK_VERSION as int
    buildToolsVersion ANDROID_BUILD_TOOLS_VERSION
    resourcePrefix "horizontalrefreshlayout_"

    defaultConfig {
        minSdkVersion 14
        targetSdkVersion ANDROID_BUILD_SDK_VERSION
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:23.4.0'
}


apply from: '../jcenter-push.gradle'





================================================
FILE: lib/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\android-sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
#   http://developer.android.com/guide/developing/tools/proguard.html

# Add any project specific keep options here:

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
#   public *;
#}


================================================
FILE: lib/src/main/AndroidManifest.xml
================================================
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="xiao.free.horizontalrefreshlayout">

    <application android:allowBackup="true" android:label="@string/app_name"
        android:supportsRtl="true">

    </application>

</manifest>


================================================
FILE: lib/src/main/java/xiao/free/horizontalrefreshlayout/HorizontalRefreshLayout.java
================================================
package xiao.free.horizontalrefreshlayout;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.FrameLayout;

/**
 * Created by robincxiao on 2017/2/6.
 * 1.View布局问题,onMeasure、onLayout
 * 2.滑动冲突问题
 * 2.1事件拦截
 * 2.2拖动效果
 * 3.释放时自动归位问题
 * 值得注意的问题:
 * 1.onlayout中header初始化
 * 2.onTouchEvent的返回值
 */

public class HorizontalRefreshLayout extends FrameLayout {
    private static final int DURATION = 150;
    private Context context;
    private RefreshHeader leftRefreshHeader;
    private RefreshHeader rightRefreshHeader;
    private View mTargetView;
    private View leftHeaderView;
    private View rightHeaderView;
    private RefreshCallBack refreshCallback;
    private int touchSlop;
    private int dragMarginPx;
    private int leftHeaderWidth;
    private int rightHeaderWidth;
    //最大拖动距离
    private int dragMaxHeaderWidth;
    private int mLastInterceptX;
    private int mLastInterceptY;
    private int mLastX;
    private int mLastY;

    private float mTargetTranslationX = 0;
    //header状态,当前显示是左边header、右边header
    private int headerState = -1;
    public static final int LEFT = 0;
    public static final int RIGHT = 1;
    //刷新状态
    private static final int REFRESH_STATE_IDLE = 0;
    private static final int REFRESH_STATE_START = 1;
    private static final int REFRESH_STATE_DRAGGING = 2;
    private static final int REFRESH_STATE_READY_TO_RELEASE = 3;
    private static final int REFRESH_STATE_REFRESHING = 4;
    private int refreshState = REFRESH_STATE_IDLE;


    public HorizontalRefreshLayout(Context context) {
        super(context);

        init();
    }

    public HorizontalRefreshLayout(Context context, AttributeSet attrs) {
        super(context, attrs);

        init();
    }

    public HorizontalRefreshLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        init();
    }

    public void setRefreshCallback(RefreshCallBack callback) {
        refreshCallback = callback;
    }

    private void init() {
        context = getContext();
        touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        if(leftHeaderView != null) {
            leftHeaderWidth = leftHeaderView.getMeasuredWidth();
            dragMarginPx = (int) (leftHeaderWidth * 0.6);
            dragMaxHeaderWidth = leftHeaderWidth + dragMarginPx;
        }

        if(rightHeaderView != null) {
            rightHeaderWidth = rightHeaderView.getMeasuredWidth();
            if(dragMarginPx == 0){
                dragMarginPx = (int) (rightHeaderWidth * 0.6);
                dragMaxHeaderWidth = rightHeaderWidth + dragMarginPx;
            }
        }
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        if (getChildCount() == 0) {
            return;
        }

        if (mTargetView == null) {
            findTargetView();
            if (mTargetView == null) {
                return;
            }
        }

        /**
         * 注意:只有状态是IDLE时才初始化刷新header的TranslationX;因为在滑动mTargetView时onLayout会被重新调用,
         * 如果不是在REFRESH_STATE_IDLE状态下设置setTranslationX,则会产生问题
         */
        if (refreshState == REFRESH_STATE_IDLE) {
            if (leftHeaderView != null) {
                leftHeaderView.setTranslationX(-leftHeaderWidth);
            }

            if (rightHeaderView != null) {
                rightHeaderView.setTranslationX(rightHeaderWidth);
            }
        }

        super.onLayout(changed, left, top, right, bottom);
    }

    private void findTargetView() {
        if (mTargetView == null) {
            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                if (!child.equals(leftHeaderView) && !child.equals(rightHeaderView)) {
                    mTargetView = child;
                    break;
                }
            }
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        int x = (int) ev.getX();
        int y = (int) ev.getY();

        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastX = mLastInterceptX = x;
                mLastY = mLastInterceptY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                int deltaX = x - mLastInterceptX;
                int deltaY = y - mLastInterceptY;

                mLastX = mLastInterceptX = x;
                mLastY = mLastInterceptY = y;

                /**
                 * 注意:需要判断refreshState != REFRESH_STATE_REFRESHING,否则当处于REFRESH_STATE_REFRESHING状态
                 * 再次拖动滑动时,会有些许小瑕疵
                 */
                if (Math.abs(deltaX) > Math.abs(deltaY)) {//判断是否是水平滑动
                    if (leftHeaderView != null && deltaX > 0 && !canChildScrollRight() && refreshState != REFRESH_STATE_REFRESHING) {//手指向右滑动
                        headerState = LEFT;
                        refreshState = REFRESH_STATE_START;
                        leftRefreshHeader.onStart(LEFT, leftHeaderView);

                        return true;
                    } else if (rightHeaderView != null && deltaX < 0 && !canChildScrollLeft() && refreshState != REFRESH_STATE_REFRESHING) {//手指向左滑动
                        headerState = RIGHT;
                        refreshState = REFRESH_STATE_START;
                        rightRefreshHeader.onStart(RIGHT, rightHeaderView);

                        return true;
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                mLastInterceptX = 0;
                mLastInterceptY = 0;
                break;
        }

        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int x = (int) event.getX();
        int y = (int) event.getY();

        /**
         * 为什么不在onTouchEvent中直接返回true,而是在ACTION_MOVE/ACTION_UP/ACTION_CANCEL返回true,ACTION_DOWN不返回true?
         * 在如下场景下需要这样设计:header正在刷新的时候,用户点击在header上开始drag,但是当header正在刷新的时候,我们并不希望
         * headerview和mTargetView被拖动,因此需要这样去处理。
         */
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mLastX = x;
                mLastY = y;
                break;
            case MotionEvent.ACTION_MOVE:
                int deltaX = x - mLastX;

                mLastX = x;
                mLastY = y;

                float dampingDX = deltaX * (1 - Math.abs((mTargetTranslationX / dragMaxHeaderWidth)));  //let drag action has resistance
                mTargetTranslationX += dampingDX;

                if (headerState == LEFT) {
                    if (mTargetTranslationX <= 0) {
                        Log.d("xiao1", "test1");
                        mTargetTranslationX = 0;
                        mTargetView.setTranslationX(0);
                    } else if (mTargetTranslationX >= dragMaxHeaderWidth) {
                        Log.d("xiao1", "test2");
                        mTargetTranslationX = dragMaxHeaderWidth;
                        mTargetView.setTranslationX(mTargetTranslationX);
                    } else {
                        Log.d("xiao1", "test3");

                        mTargetView.setTranslationX(mTargetTranslationX);

                        if (refreshState != REFRESH_STATE_READY_TO_RELEASE && mTargetTranslationX >= leftHeaderWidth) {
                            refreshState = REFRESH_STATE_READY_TO_RELEASE;

                            leftRefreshHeader.onReadyToRelease(leftHeaderView);
                        } else {
                            refreshState = REFRESH_STATE_DRAGGING;
                            //计算出拖动的比率
                            float percent = Math.abs(mTargetTranslationX / leftHeaderWidth);
                            leftRefreshHeader.onDragging(mTargetTranslationX, percent, leftHeaderView);
                        }
                    }

                    leftHeaderView.setTranslationX(-leftHeaderWidth + mTargetTranslationX);
                } else if ((headerState == RIGHT)) {
                    if (mTargetTranslationX >= 0) {
                        Log.d("xiao1", "test4");
                        mTargetTranslationX = 0;
                        mTargetView.setTranslationX(0);
                    } else if (mTargetTranslationX <= -dragMaxHeaderWidth) {
                        Log.d("xiao1", "test5");
                        mTargetTranslationX = -dragMaxHeaderWidth;
                        mTargetView.setTranslationX(mTargetTranslationX);
                    } else {
                        Log.d("xiao1", "test6");
                        mTargetView.setTranslationX(mTargetTranslationX);

                        if (refreshState != REFRESH_STATE_READY_TO_RELEASE && mTargetTranslationX <= -rightHeaderWidth) {
                            refreshState = REFRESH_STATE_READY_TO_RELEASE;
                            rightRefreshHeader.onReadyToRelease(rightHeaderView);
                        } else {
                            refreshState = REFRESH_STATE_DRAGGING;
                            //计算出拖动的比率
                            float percent = Math.abs(mTargetTranslationX / rightHeaderWidth);
                            rightRefreshHeader.onDragging(mTargetTranslationX, percent, rightHeaderView);
                        }
                    }

                    rightHeaderView.setTranslationX(rightHeaderWidth + mTargetTranslationX);
                }
                return true;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                mLastX = mLastInterceptX = 0;
                mLastY = mLastInterceptY = 0;

                if (headerState == LEFT) {
                    if (mTargetTranslationX < leftHeaderWidth) {
                        Log.d("xiao1", "test7");
                        smoothRelease();
                    } else {
                        Log.d("xiao1", "test8");
                        smoothLocateToRefresh();
                    }
                } else if (headerState == RIGHT) {
                    if (mTargetTranslationX > -rightHeaderWidth) {
                        Log.d("xiao1", "test9");
                        smoothRelease();
                    } else {
                        Log.d("xiao1", "test10");
                        smoothLocateToRefresh();
                    }
                }
                return true;
        }

        return super.onTouchEvent(event);
    }

    /**
     * 释放滑动
     */
    private void smoothRelease() {
        mTargetView.animate().translationX(0).setDuration(DURATION)
                .setListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        //动画结束后reset状态
                        refreshState = REFRESH_STATE_IDLE;
                        headerState = -1;
                        mTargetTranslationX = 0;
                    }
                })
                .start();

        if (headerState == LEFT) {
            if (leftHeaderView != null) {
                leftRefreshHeader.onStart(LEFT, leftHeaderView);//恢复到开始状态
                leftHeaderView.animate().translationX(-leftHeaderWidth).setDuration(DURATION).start();
            }
        } else if (headerState == RIGHT) {
            if (rightHeaderView != null) {
                rightRefreshHeader.onStart(LEFT, rightHeaderView);//恢复到开始状态
                rightHeaderView.animate().translationX(rightHeaderWidth).setDuration(DURATION).start();
            }
        }
    }

    /**
     * 滑动到刷新位置
     */
    private void smoothLocateToRefresh() {
        if (headerState == LEFT && leftHeaderView != null) {
            refreshState = REFRESH_STATE_REFRESHING;

            leftHeaderView.animate().translationX(0).setDuration(DURATION).start();

            leftRefreshHeader.onRefreshing(leftHeaderView);//正在刷新

            mTargetView.animate().translationX(leftHeaderWidth).setDuration(DURATION)
                    .setListener(new AnimatorListenerAdapter() {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            mTargetTranslationX = leftHeaderWidth;

                            if (refreshCallback != null) {
                                if (headerState == LEFT) {
                                    refreshCallback.onLeftRefreshing();
                                } else {
                                    refreshCallback.onRightRefreshing();
                                }
                            }
                        }
                    })
                    .start();
        } else if (headerState == RIGHT && rightHeaderView != null) {
            refreshState = REFRESH_STATE_REFRESHING;
            //注意,这里使用的translationXBy
            rightHeaderView.animate().translationXBy(-mTargetTranslationX - rightHeaderWidth).setDuration(DURATION).start();

            rightRefreshHeader.onRefreshing(rightHeaderView);//正在刷新

            mTargetView.animate().translationX(-rightHeaderWidth).setDuration(DURATION)
                    .setListener(new AnimatorListenerAdapter() {
                        @Override
                        public void onAnimationEnd(Animator animation) {
                            if (refreshCallback != null) {
                                if (headerState == LEFT) {
                                    refreshCallback.onLeftRefreshing();
                                } else {
                                    refreshCallback.onRightRefreshing();
                                }
                            }

                            mTargetTranslationX = -rightHeaderWidth;
                        }
                    })
                    .start();
        }
    }

    /**
     * 刷新完成
     */
    public void onRefreshComplete() {
        smoothRelease();
    }

    /**
     * 自动刷新
     *
     * @param leftOrRight HorizontalRefreshLayout.LEFT or HorizontalRefreshLayout.RIGHT
     */
    public void startAutoRefresh(final int leftOrRight) {
        // delay to let the animation smoothly
        //此处需要采用postDelayed将消息方式view的消息队列中,如果直接调用smoothLocateToRefresh可能view还没能完全初始化好,导致mTarget为null
        postDelayed(new Runnable() {
            @Override
            public void run() {
                headerState = leftOrRight;
                smoothLocateToRefresh();
            }
        }, 100);
    }

    private void setLeftHeadView(View view) {
        leftHeaderView = view;
        ((LayoutParams) leftHeaderView.getLayoutParams()).gravity = Gravity.START;
        addView(leftHeaderView, 0);
    }

    private void setRightHeadView(View view) {
        rightHeaderView = view;
        ((LayoutParams) rightHeaderView.getLayoutParams()).gravity = Gravity.END;
        addView(rightHeaderView, 0);
    }

    /**
     * 设置刷新header
     * @param header
     * @param startOrEnd
     */
    public void setRefreshHeader(RefreshHeader header, int startOrEnd) {
        if (startOrEnd == LEFT) {
            leftRefreshHeader = header;
            setLeftHeadView(leftRefreshHeader.getView(this));
        } else if (startOrEnd == RIGHT) {
            rightRefreshHeader = header;
            setRightHeadView(rightRefreshHeader.getView(this));
        }
    }

    /**
     * mTargetView是否还能向右滑动
     *
     * @return
     */
    public boolean canChildScrollRight() {
        return ViewCompat.canScrollHorizontally(mTargetView, -1);
    }

    /**
     * mTargetView是否还能向左滑动
     *
     * @return
     */
    public boolean canChildScrollLeft() {
        return ViewCompat.canScrollHorizontally(mTargetView, 1);
    }


    public static int dp2px(Context context, float dpVal) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, context.getResources().getDisplayMetrics());
    }
}


================================================
FILE: lib/src/main/java/xiao/free/horizontalrefreshlayout/RefreshCallBack.java
================================================
package xiao.free.horizontalrefreshlayout;

/**
 * Created by wangqi on 2015/12/24.
 */
public interface RefreshCallBack {
    void onLeftRefreshing();
    void onRightRefreshing();
}


================================================
FILE: lib/src/main/java/xiao/free/horizontalrefreshlayout/RefreshHeader.java
================================================
package xiao.free.horizontalrefreshlayout;

import android.support.annotation.NonNull;
import android.view.View;
import android.view.ViewGroup;

/**
 * Created by wangqi on 2015/12/24.
 */
public interface RefreshHeader {

    /**
     * @param dragPosition  HorizontalRefreshLayout.START or HorizontalRefreshLayout.END
     */
    void onStart(int dragPosition, View refreshHead);

    /**
     * @param distance
     */
    void onDragging(float distance, float percent, View refreshHead);

    void onReadyToRelease(View refreshHead);

    @NonNull View getView(ViewGroup container);

    void onRefreshing(View refreshHead);
}


================================================
FILE: lib/src/main/java/xiao/free/horizontalrefreshlayout/refreshhead/LoadingRefreshHeader.java
================================================
package xiao.free.horizontalrefreshlayout.refreshhead;

import android.content.Context;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ProgressBar;

import xiao.free.horizontalrefreshlayout.R;
import xiao.free.horizontalrefreshlayout.RefreshHeader;

/**
 * Created by xiaoguochang on 2015/12/24.
 */
public class LoadingRefreshHeader implements RefreshHeader {
    private final Context context;
    private ProgressBar progressBar;
    private ImageView staticLoading;

    public LoadingRefreshHeader(Context context) {
        this.context = context;
    }

    @NonNull
    @Override
    public View getView(ViewGroup container) {
        View view = LayoutInflater.from(context).inflate(R.layout.common_loading_refresh_header, container, false);
        progressBar = (ProgressBar) view.findViewById(R.id.progressbar);
        staticLoading = (ImageView) view.findViewById(R.id.static_loading);
        progressBar.setVisibility(View.INVISIBLE);

        return view;
    }

    @Override
    public void onStart(int dragPosition, View refreshHead) {
        staticLoading.setVisibility(View.VISIBLE);
        progressBar.setVisibility(View.INVISIBLE);
    }

    @Override
    public void onDragging(float distance, float percent, View refreshHead) {
        staticLoading.setRotation(percent * 360);
    }

    @Override
    public void onReadyToRelease(View refreshHead) {

    }

    @Override
    public void onRefreshing(View refreshHead) {
        staticLoading.setVisibility(View.INVISIBLE);
        progressBar.setVisibility(View.VISIBLE);
    }
}


================================================
FILE: lib/src/main/java/xiao/free/horizontalrefreshlayout/refreshhead/MaterialRefreshHeader.java
================================================
package xiao.free.horizontalrefreshlayout.refreshhead;

import android.support.annotation.NonNull;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

import xiao.free.horizontalrefreshlayout.HorizontalRefreshLayout;
import xiao.free.horizontalrefreshlayout.R;
import xiao.free.horizontalrefreshlayout.RefreshHeader;
import xiao.free.horizontalrefreshlayout.widget.CircleImageView;
import xiao.free.horizontalrefreshlayout.widget.MaterialProgressDrawable;


/**
 * Created by wangqi on 2016/7/21.
 */
public class MaterialRefreshHeader implements RefreshHeader {

    private final int startOrEnd;
    private CircleImageView mCircleView;
    private MaterialProgressDrawable mProgress;
    private ViewGroup parent;

    public MaterialRefreshHeader(int startOrEnd) {
        this.startOrEnd = startOrEnd;
    }

    @Override
    public void onStart(int dragPosition, View refreshHead) {
        mProgress.stop();
        mProgress.showArrow(false);
        mProgress.setAlpha(0);
        mProgress.setStartEndTrim(0f, 0f);
    }

    @Override
    public void onDragging(float distance, float percent, View refreshHead) {
        mProgress.showArrow(true);
        mProgress.setAlpha((int) (percent * 255));
        mProgress.setProgressRotation(percent);
        mProgress.setStartEndTrim(0f, Math.min(.8f, percent));
    }

    @Override
    public void onReadyToRelease(View refreshHead) {
    }

    @NonNull
    @Override
    public View getView(ViewGroup container) {
        this.parent = container;
        ViewGroup view = (ViewGroup) LayoutInflater.from(container.getContext()).inflate(R.layout.material_refresh_header, container, false);
        mCircleView = new CircleImageView(container.getContext(), 0xFFFAFAFA, 40 / 2);
        mProgress = new MaterialProgressDrawable(container.getContext(), container);
        mProgress.setBackgroundColor(0xFFFAFAFA);
        mCircleView.setImageDrawable(mProgress);
        FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        if (startOrEnd == HorizontalRefreshLayout.LEFT) {
            layoutParams.gravity = Gravity.CENTER;
        } else {
            layoutParams.gravity = Gravity.CENTER;
        }
        mCircleView.setLayoutParams(layoutParams);
        view.addView(mCircleView);
        return view;
    }

    @Override
    public void onRefreshing(View refreshHead) {
        mProgress.showArrow(true);
        mProgress.setAlpha(255);
        mProgress.setProgressRotation(1);
        mProgress.setStartEndTrim(0f, Math.min(.8f, 1));
        mProgress.start();
    }
}


================================================
FILE: lib/src/main/java/xiao/free/horizontalrefreshlayout/refreshhead/NiceRefreshHeader.java
================================================
package xiao.free.horizontalrefreshlayout.refreshhead;

import android.content.Context;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ProgressBar;

import xiao.free.horizontalrefreshlayout.R;
import xiao.free.horizontalrefreshlayout.RefreshHeader;

/**
 * Created by xiaoguochang on 2015/12/24.
 */
public class NiceRefreshHeader implements RefreshHeader {
    private final Context context;
    private ProgressBar progressBar;
    private ImageView staticLoading;

    public NiceRefreshHeader(Context context) {
        this.context = context;
    }

    @NonNull
    @Override
    public View getView(ViewGroup container) {
        View view = LayoutInflater.from(context).inflate(R.layout.nice_refresh_header, container, false);
        progressBar = (ProgressBar) view.findViewById(R.id.progressbar);
        staticLoading = (ImageView) view.findViewById(R.id.static_loading);
        progressBar.setVisibility(View.INVISIBLE);

        return view;
    }

    @Override
    public void onStart(int dragPosition, View refreshHead) {
        staticLoading.setVisibility(View.VISIBLE);
        progressBar.setVisibility(View.INVISIBLE);
    }

    @Override
    public void onDragging(float distance, float percent, View refreshHead) {
        int num = (int) (percent * 10);

        switch (num){
            case 1:
            case 4:
            case 7:
                staticLoading.setBackgroundResource(R.drawable.ic_loading_1);
                break;
            case 2:
            case 5:
            case 8:
                staticLoading.setBackgroundResource(R.drawable.ic_loading_2);
                break;
            case 3:
            case 6:
            case 9:
                staticLoading.setBackgroundResource(R.drawable.ic_loading_3);
                break;
        }
    }

    @Override
    public void onReadyToRelease(View refreshHead) {

    }

    @Override
    public void onRefreshing(View refreshHead) {
        staticLoading.setVisibility(View.INVISIBLE);
        progressBar.setVisibility(View.VISIBLE);
    }
}


================================================
FILE: lib/src/main/java/xiao/free/horizontalrefreshlayout/widget/CircleImageView.java
================================================
/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * 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 xiao.free.horizontalrefreshlayout.widget;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RadialGradient;
import android.graphics.Shader;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.support.v4.view.ViewCompat;
import android.view.animation.Animation;
import android.widget.ImageView;

/**
 * Private class created to work around issues with AnimationListeners being
 * called before the animation is actually complete and support shadows on older
 * platforms.
 */
public class CircleImageView extends ImageView {

    private static final int KEY_SHADOW_COLOR = 0x1E000000;
    private static final int FILL_SHADOW_COLOR = 0x3D000000;
    // PX
    private static final float X_OFFSET = 0f;
    private static final float Y_OFFSET = 1.75f;
    private static final float SHADOW_RADIUS = 3.5f;
    private static final int SHADOW_ELEVATION = 4;

    private Animation.AnimationListener mListener;
    private int mShadowRadius;

    public CircleImageView(Context context, int color, final float radius) {
        super(context);
        final float density = getContext().getResources().getDisplayMetrics().density;
        final int diameter = (int) (radius * density * 2);
        final int shadowYOffset = (int) (density * Y_OFFSET);
        final int shadowXOffset = (int) (density * X_OFFSET);

        mShadowRadius = (int) (density * SHADOW_RADIUS);

        ShapeDrawable circle;
        if (elevationSupported()) {
            circle = new ShapeDrawable(new OvalShape());
            ViewCompat.setElevation(this, SHADOW_ELEVATION * density);
        } else {
            OvalShape oval = new OvalShadow(mShadowRadius, diameter);
            circle = new ShapeDrawable(oval);
            ViewCompat.setLayerType(this, ViewCompat.LAYER_TYPE_SOFTWARE, circle.getPaint());
            circle.getPaint().setShadowLayer(mShadowRadius, shadowXOffset, shadowYOffset,
                    KEY_SHADOW_COLOR);
            final int padding = mShadowRadius;
            // set padding so the inner image sits correctly within the shadow.
            setPadding(padding, padding, padding, padding);
        }
        circle.getPaint().setColor(color);
        setBackgroundDrawable(circle);
    }

    private boolean elevationSupported() {
        return android.os.Build.VERSION.SDK_INT >= 21;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (!elevationSupported()) {
            setMeasuredDimension(getMeasuredWidth() + mShadowRadius*2, getMeasuredHeight()
                    + mShadowRadius*2);
        }
    }

    public void setAnimationListener(Animation.AnimationListener listener) {
        mListener = listener;
    }

    @Override
    public void onAnimationStart() {
        super.onAnimationStart();
        if (mListener != null) {
            mListener.onAnimationStart(getAnimation());
        }
    }

    @Override
    public void onAnimationEnd() {
        super.onAnimationEnd();
        if (mListener != null) {
            mListener.onAnimationEnd(getAnimation());
        }
    }

    /**
     * Update the background color of the circle image view.
     *
     * @param colorRes Id of a color resource.
     */
    public void setBackgroundColorRes(int colorRes) {
        setBackgroundColor(getContext().getResources().getColor(colorRes));
    }

    @Override
    public void setBackgroundColor(int color) {
        if (getBackground() instanceof ShapeDrawable) {
            ((ShapeDrawable) getBackground()).getPaint().setColor(color);
        }
    }

    private class OvalShadow extends OvalShape {
        private RadialGradient mRadialGradient;
        private Paint mShadowPaint;
        private int mCircleDiameter;

        public OvalShadow(int shadowRadius, int circleDiameter) {
            super();
            mShadowPaint = new Paint();
            mShadowRadius = shadowRadius;
            mCircleDiameter = circleDiameter;
            mRadialGradient = new RadialGradient(mCircleDiameter / 2, mCircleDiameter / 2,
                    mShadowRadius, new int[] {
                            FILL_SHADOW_COLOR, Color.TRANSPARENT
                    }, null, Shader.TileMode.CLAMP);
            mShadowPaint.setShader(mRadialGradient);
        }

        @Override
        public void draw(Canvas canvas, Paint paint) {
            final int viewWidth = CircleImageView.this.getWidth();
            final int viewHeight = CircleImageView.this.getHeight();
            canvas.drawCircle(viewWidth / 2, viewHeight / 2, (mCircleDiameter / 2 + mShadowRadius),
                    mShadowPaint);
            canvas.drawCircle(viewWidth / 2, viewHeight / 2, (mCircleDiameter / 2), paint);
        }
    }
}


================================================
FILE: lib/src/main/java/xiao/free/horizontalrefreshlayout/widget/MaterialProgressDrawable.java
================================================
/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * 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 xiao.free.horizontalrefreshlayout.widget;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.Transformation;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;

/**
 * Fancy progress indicator for Material theme.
 */
public class MaterialProgressDrawable extends Drawable implements Animatable {
    private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
    private static final Interpolator MATERIAL_INTERPOLATOR = new FastOutSlowInInterpolator();

    private static final float FULL_ROTATION = 1080.0f;
    @Retention(RetentionPolicy.CLASS)
    @IntDef({LARGE, DEFAULT})
    public @interface ProgressDrawableSize {}
    // Maps to ProgressBar.Large style
    static final int LARGE = 0;
    // Maps to ProgressBar default style
    static final int DEFAULT = 1;

    // Maps to ProgressBar default style
    private static final int CIRCLE_DIAMETER = 40;
    private static final float CENTER_RADIUS = 8.75f; //should add up to 10 when + stroke_width
    private static final float STROKE_WIDTH = 2.5f;

    // Maps to ProgressBar.Large style
    private static final int CIRCLE_DIAMETER_LARGE = 56;
    private static final float CENTER_RADIUS_LARGE = 12.5f;
    private static final float STROKE_WIDTH_LARGE = 3f;

    private final int[] COLORS = new int[] {
        Color.BLACK
    };

    /**
     * The value in the linear interpolator for animating the drawable at which
     * the color transition should start
     */
    private static final float COLOR_START_DELAY_OFFSET = 0.75f;
    private static final float END_TRIM_START_DELAY_OFFSET = 0.5f;
    private static final float START_TRIM_DURATION_OFFSET = 0.5f;

    /** The duration of a single progress spin in milliseconds. */
    private static final int ANIMATION_DURATION = 1332;

    /** The number of points in the progress "star". */
    private static final float NUM_POINTS = 5f;
    /** The list of animators operating on this drawable. */
    private final ArrayList<Animation> mAnimators = new ArrayList<Animation>();

    /** The indicator ring, used to manage animation state. */
    private final Ring mRing;

    /** Canvas rotation in degrees. */
    private float mRotation;

    /** Layout info for the arrowhead in dp */
    private static final int ARROW_WIDTH = 10;
    private static final int ARROW_HEIGHT = 5;
    private static final float ARROW_OFFSET_ANGLE = 5;

    /** Layout info for the arrowhead for the large spinner in dp */
    private static final int ARROW_WIDTH_LARGE = 12;
    private static final int ARROW_HEIGHT_LARGE = 6;
    private static final float MAX_PROGRESS_ARC = .8f;

    private Resources mResources;
    private View mParent;
    private Animation mAnimation;
    private float mRotationCount;
    private double mWidth;
    private double mHeight;
    boolean mFinishing;

    public MaterialProgressDrawable(Context context, View parent) {
        mParent = parent;
        mResources = context.getResources();

        mRing = new Ring(mCallback);
        mRing.setColors(COLORS);

        updateSizes(DEFAULT);
        setupAnimators();
    }

    private void setSizeParameters(double progressCircleWidth, double progressCircleHeight,
            double centerRadius, double strokeWidth, float arrowWidth, float arrowHeight) {
        final Ring ring = mRing;
        final DisplayMetrics metrics = mResources.getDisplayMetrics();
        final float screenDensity = metrics.density;

        mWidth = progressCircleWidth * screenDensity;
        mHeight = progressCircleHeight * screenDensity;
        ring.setStrokeWidth((float) strokeWidth * screenDensity);
        ring.setCenterRadius(centerRadius * screenDensity);
        ring.setColorIndex(0);
        ring.setArrowDimensions(arrowWidth * screenDensity, arrowHeight * screenDensity);
        ring.setInsets((int) mWidth, (int) mHeight);
    }

    /**
     * Set the overall size for the progress spinner. This updates the radius
     * and stroke width of the ring.
     *
     * @param size One of {@link MaterialProgressDrawable.LARGE} or
     *            {@link MaterialProgressDrawable.DEFAULT}
     */
    public void updateSizes(@ProgressDrawableSize int size) {
        if (size == LARGE) {
            setSizeParameters(CIRCLE_DIAMETER_LARGE, CIRCLE_DIAMETER_LARGE, CENTER_RADIUS_LARGE,
                    STROKE_WIDTH_LARGE, ARROW_WIDTH_LARGE, ARROW_HEIGHT_LARGE);
        } else {
            setSizeParameters(CIRCLE_DIAMETER, CIRCLE_DIAMETER, CENTER_RADIUS, STROKE_WIDTH,
                    ARROW_WIDTH, ARROW_HEIGHT);
        }
    }

    /**
     * @param show Set to true to display the arrowhead on the progress spinner.
     */
    public void showArrow(boolean show) {
        mRing.setShowArrow(show);
    }

    /**
     * @param scale Set the scale of the arrowhead for the spinner.
     */
    public void setArrowScale(float scale) {
        mRing.setArrowScale(scale);
    }

    /**
     * Set the start and end trim for the progress spinner arc.
     *
     * @param startAngle start angle
     * @param endAngle end angle
     */
    public void setStartEndTrim(float startAngle, float endAngle) {
        mRing.setStartTrim(startAngle);
        mRing.setEndTrim(endAngle);
    }

    /**
     * Set the amount of rotation to apply to the progress spinner.
     *
     * @param rotation Rotation is from [0..1]
     */
    public void setProgressRotation(float rotation) {
        mRing.setRotation(rotation);
    }

    /**
     * Update the background color of the circle image view.
     */
    public void setBackgroundColor(int color) {
        mRing.setBackgroundColor(color);
     }

    /**
     * Set the colors used in the progress animation from color resources.
     * The first color will also be the color of the bar that grows in response
     * to a user swipe gesture.
     *
     * @param colors
     */
    public void setColorSchemeColors(int... colors) {
        mRing.setColors(colors);
        mRing.setColorIndex(0);
    }

    @Override
    public int getIntrinsicHeight() {
        return (int) mHeight;
    }

    @Override
    public int getIntrinsicWidth() {
        return (int) mWidth;
    }

    @Override
    public void draw(Canvas c) {
        final Rect bounds = getBounds();
        final int saveCount = c.save();
        c.rotate(mRotation, bounds.exactCenterX(), bounds.exactCenterY());
        mRing.draw(c, bounds);
        c.restoreToCount(saveCount);
    }

    @Override
    public void setAlpha(int alpha) {
        mRing.setAlpha(alpha);
    }

    public int getAlpha() {
        return mRing.getAlpha();
    }

    @Override
    public void setColorFilter(ColorFilter colorFilter) {
        mRing.setColorFilter(colorFilter);
    }

    @SuppressWarnings("unused")
    void setRotation(float rotation) {
        mRotation = rotation;
        invalidateSelf();
    }

    @SuppressWarnings("unused")
    private float getRotation() {
        return mRotation;
    }

    @Override
    public int getOpacity() {
        return PixelFormat.TRANSLUCENT;
    }

    @Override
    public boolean isRunning() {
        final ArrayList<Animation> animators = mAnimators;
        final int N = animators.size();
        for (int i = 0; i < N; i++) {
            final Animation animator = animators.get(i);
            if (animator.hasStarted() && !animator.hasEnded()) {
                return true;
            }
        }
        return false;
    }

    @Override
    public void start() {
        mAnimation.reset();
        mRing.storeOriginals();
        // Already showing some part of the ring
        if (mRing.getEndTrim() != mRing.getStartTrim()) {
            mFinishing = true;
            mAnimation.setDuration(ANIMATION_DURATION/2);
            mParent.startAnimation(mAnimation);
        } else {
            mRing.setColorIndex(0);
            mRing.resetOriginals();
            mAnimation.setDuration(ANIMATION_DURATION);
            mParent.startAnimation(mAnimation);
        }
    }

    @Override
    public void stop() {
        mParent.clearAnimation();
        setRotation(0);
        mRing.setShowArrow(false);
        mRing.setColorIndex(0);
        mRing.resetOriginals();
    }

    private float getMinProgressArc(Ring ring) {
        return (float) Math.toRadians(
                ring.getStrokeWidth() / (2 * Math.PI * ring.getCenterRadius()));
    }

    // Adapted from ArgbEvaluator.java
    private int evaluateColorChange(float fraction, int startValue, int endValue) {
        int startInt = (Integer) startValue;
        int startA = (startInt >> 24) & 0xff;
        int startR = (startInt >> 16) & 0xff;
        int startG = (startInt >> 8) & 0xff;
        int startB = startInt & 0xff;

        int endInt = (Integer) endValue;
        int endA = (endInt >> 24) & 0xff;
        int endR = (endInt >> 16) & 0xff;
        int endG = (endInt >> 8) & 0xff;
        int endB = endInt & 0xff;

        return (int)((startA + (int)(fraction * (endA - startA))) << 24) |
                (int)((startR + (int)(fraction * (endR - startR))) << 16) |
                (int)((startG + (int)(fraction * (endG - startG))) << 8) |
                (int)((startB + (int)(fraction * (endB - startB))));
    }

    /**
     * Update the ring color if this is within the last 25% of the animation.
     * The new ring color will be a translation from the starting ring color to
     * the next color.
     */
    private void updateRingColor(float interpolatedTime, Ring ring) {
        if (interpolatedTime > COLOR_START_DELAY_OFFSET) {
            // scale the interpolatedTime so that the full
            // transformation from 0 - 1 takes place in the
            // remaining time
            ring.setColor(evaluateColorChange((interpolatedTime - COLOR_START_DELAY_OFFSET)
                    / (1.0f - COLOR_START_DELAY_OFFSET), ring.getStartingColor(),
                    ring.getNextColor()));
        }
    }

    private void applyFinishTranslation(float interpolatedTime, Ring ring) {
        // shrink back down and complete a full rotation before
        // starting other circles
        // Rotation goes between [0..1].
        updateRingColor(interpolatedTime, ring);
        float targetRotation = (float) (Math.floor(ring.getStartingRotation() / MAX_PROGRESS_ARC)
                + 1f);
        final float minProgressArc = getMinProgressArc(ring);
        final float startTrim = ring.getStartingStartTrim()
                + (ring.getStartingEndTrim() - minProgressArc - ring.getStartingStartTrim())
                * interpolatedTime;
        ring.setStartTrim(startTrim);
        ring.setEndTrim(ring.getStartingEndTrim());
        final float rotation = ring.getStartingRotation()
                + ((targetRotation - ring.getStartingRotation()) * interpolatedTime);
        ring.setRotation(rotation);
    }

    private void setupAnimators() {
        final Ring ring = mRing;
        final Animation animation = new Animation() {
                @Override
            public void applyTransformation(float interpolatedTime, Transformation t) {
                if (mFinishing) {
                    applyFinishTranslation(interpolatedTime, ring);
                } else {
                    // The minProgressArc is calculated from 0 to create an
                    // angle that matches the stroke width.
                    final float minProgressArc = getMinProgressArc(ring);
                    final float startingEndTrim = ring.getStartingEndTrim();
                    final float startingTrim = ring.getStartingStartTrim();
                    final float startingRotation = ring.getStartingRotation();

                    updateRingColor(interpolatedTime, ring);

                    // Moving the start trim only occurs in the first 50% of a
                    // single ring animation
                    if (interpolatedTime <= START_TRIM_DURATION_OFFSET) {
                        // scale the interpolatedTime so that the full
                        // transformation from 0 - 1 takes place in the
                        // remaining time
                        final float scaledTime = (interpolatedTime)
                                / (1.0f - START_TRIM_DURATION_OFFSET);
                        final float startTrim = startingTrim
                                + ((MAX_PROGRESS_ARC - minProgressArc) * MATERIAL_INTERPOLATOR
                                        .getInterpolation(scaledTime));
                        ring.setStartTrim(startTrim);
                    }

                    // Moving the end trim starts after 50% of a single ring
                    // animation completes
                    if (interpolatedTime > END_TRIM_START_DELAY_OFFSET) {
                        // scale the interpolatedTime so that the full
                        // transformation from 0 - 1 takes place in the
                        // remaining time
                        final float minArc = MAX_PROGRESS_ARC - minProgressArc;
                        float scaledTime = (interpolatedTime - START_TRIM_DURATION_OFFSET)
                                / (1.0f - START_TRIM_DURATION_OFFSET);
                        final float endTrim = startingEndTrim
                                + (minArc * MATERIAL_INTERPOLATOR.getInterpolation(scaledTime));
                        ring.setEndTrim(endTrim);
                    }

                    final float rotation = startingRotation + (0.25f * interpolatedTime);
                    ring.setRotation(rotation);

                    float groupRotation = ((FULL_ROTATION / NUM_POINTS) * interpolatedTime)
                            + (FULL_ROTATION * (mRotationCount / NUM_POINTS));
                    setRotation(groupRotation);
                }
            }
        };
        animation.setRepeatCount(Animation.INFINITE);
        animation.setRepeatMode(Animation.RESTART);
        animation.setInterpolator(LINEAR_INTERPOLATOR);
        animation.setAnimationListener(new Animation.AnimationListener() {

                @Override
            public void onAnimationStart(Animation animation) {
                mRotationCount = 0;
            }

                @Override
            public void onAnimationEnd(Animation animation) {
                // do nothing
            }

                @Override
            public void onAnimationRepeat(Animation animation) {
                ring.storeOriginals();
                ring.goToNextColor();
                ring.setStartTrim(ring.getEndTrim());
                if (mFinishing) {
                    // finished closing the last ring from the swipe gesture; go
                    // into progress mode
                    mFinishing = false;
                    animation.setDuration(ANIMATION_DURATION);
                    ring.setShowArrow(false);
                } else {
                    mRotationCount = (mRotationCount + 1) % (NUM_POINTS);
                }
            }
        });
        mAnimation = animation;
    }

    private final Callback mCallback = new Callback() {
        @Override
        public void invalidateDrawable(Drawable d) {
            invalidateSelf();
        }

        @Override
        public void scheduleDrawable(Drawable d, Runnable what, long when) {
            scheduleSelf(what, when);
        }

        @Override
        public void unscheduleDrawable(Drawable d, Runnable what) {
            unscheduleSelf(what);
        }
    };

    private static class Ring {
        private final RectF mTempBounds = new RectF();
        private final Paint mPaint = new Paint();
        private final Paint mArrowPaint = new Paint();

        private final Callback mCallback;

        private float mStartTrim = 0.0f;
        private float mEndTrim = 0.0f;
        private float mRotation = 0.0f;
        private float mStrokeWidth = 5.0f;
        private float mStrokeInset = 2.5f;

        private int[] mColors;
        // mColorIndex represents the offset into the available mColors that the
        // progress circle should currently display. As the progress circle is
        // animating, the mColorIndex moves by one to the next available color.
        private int mColorIndex;
        private float mStartingStartTrim;
        private float mStartingEndTrim;
        private float mStartingRotation;
        private boolean mShowArrow;
        private Path mArrow;
        private float mArrowScale;
        private double mRingCenterRadius;
        private int mArrowWidth;
        private int mArrowHeight;
        private int mAlpha;
        private final Paint mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        private int mBackgroundColor;
        private int mCurrentColor;

        public Ring(Callback callback) {
            mCallback = callback;

            mPaint.setStrokeCap(Paint.Cap.SQUARE);
            mPaint.setAntiAlias(true);
            mPaint.setStyle(Style.STROKE);

            mArrowPaint.setStyle(Style.FILL);
            mArrowPaint.setAntiAlias(true);
        }

        public void setBackgroundColor(int color) {
            mBackgroundColor = color;
        }

        /**
         * Set the dimensions of the arrowhead.
         *
         * @param width Width of the hypotenuse of the arrow head
         * @param height Height of the arrow point
         */
        public void setArrowDimensions(float width, float height) {
            mArrowWidth = (int) width;
            mArrowHeight = (int) height;
        }

        /**
         * Draw the progress spinner
         */
        public void draw(Canvas c, Rect bounds) {
            final RectF arcBounds = mTempBounds;
            arcBounds.set(bounds);
            arcBounds.inset(mStrokeInset, mStrokeInset);

            final float startAngle = (mStartTrim + mRotation) * 360;
            final float endAngle = (mEndTrim + mRotation) * 360;
            float sweepAngle = endAngle - startAngle;

            mPaint.setColor(mCurrentColor);
            c.drawArc(arcBounds, startAngle, sweepAngle, false, mPaint);

            drawTriangle(c, startAngle, sweepAngle, bounds);

            if (mAlpha < 255) {
                mCirclePaint.setColor(mBackgroundColor);
                mCirclePaint.setAlpha(255 - mAlpha);
                c.drawCircle(bounds.exactCenterX(), bounds.exactCenterY(), bounds.width() / 2,
                        mCirclePaint);
            }
        }

        private void drawTriangle(Canvas c, float startAngle, float sweepAngle, Rect bounds) {
            if (mShowArrow) {
                if (mArrow == null) {
                    mArrow = new Path();
                    mArrow.setFillType(Path.FillType.EVEN_ODD);
                } else {
                    mArrow.reset();
                }

                // Adjust the position of the triangle so that it is inset as
                // much as the arc, but also centered on the arc.
                float inset = (int) mStrokeInset / 2 * mArrowScale;
                float x = (float) (mRingCenterRadius * Math.cos(0) + bounds.exactCenterX());
                float y = (float) (mRingCenterRadius * Math.sin(0) + bounds.exactCenterY());

                // Update the path each time. This works around an issue in SKIA
                // where concatenating a rotation matrix to a scale matrix
                // ignored a starting negative rotation. This appears to have
                // been fixed as of API 21.
                mArrow.moveTo(0, 0);
                mArrow.lineTo(mArrowWidth * mArrowScale, 0);
                mArrow.lineTo((mArrowWidth * mArrowScale / 2), (mArrowHeight
                        * mArrowScale));
                mArrow.offset(x - inset, y);
                mArrow.close();
                // draw a triangle
                mArrowPaint.setColor(mCurrentColor);
                c.rotate(startAngle + sweepAngle - ARROW_OFFSET_ANGLE, bounds.exactCenterX(),
                        bounds.exactCenterY());
                c.drawPath(mArrow, mArrowPaint);
            }
        }

        /**
         * Set the colors the progress spinner alternates between.
         *
         * @param colors Array of integers describing the colors. Must be non-<code>null</code>.
         */
        public void setColors(@NonNull int[] colors) {
            mColors = colors;
            // if colors are reset, make sure to reset the color index as well
            setColorIndex(0);
        }

        /**
         * Set the absolute color of the progress spinner. This is should only
         * be used when animating between current and next color when the
         * spinner is rotating.
         *
         * @param color int describing the color.
         */
        public void setColor(int color) {
            mCurrentColor = color;
        }

        /**
         * @param index Index into the color array of the color to display in
         *            the progress spinner.
         */
        public void setColorIndex(int index) {
            mColorIndex = index;
            mCurrentColor = mColors[mColorIndex];
        }

        /**
         * @return int describing the next color the progress spinner should use when drawing.
         */
        public int getNextColor() {
            return mColors[getNextColorIndex()];
        }

        private int getNextColorIndex() {
            return (mColorIndex + 1) % (mColors.length);
        }

        /**
         * Proceed to the next available ring color. This will automatically
         * wrap back to the beginning of colors.
         */
        public void goToNextColor() {
            setColorIndex(getNextColorIndex());
        }

        public void setColorFilter(ColorFilter filter) {
            mPaint.setColorFilter(filter);
            invalidateSelf();
        }

        /**
         * @param alpha Set the alpha of the progress spinner and associated arrowhead.
         */
        public void setAlpha(int alpha) {
            mAlpha = alpha;
        }

        /**
         * @return Current alpha of the progress spinner and arrowhead.
         */
        public int getAlpha() {
            return mAlpha;
        }

        /**
         * @param strokeWidth Set the stroke width of the progress spinner in pixels.
         */
        public void setStrokeWidth(float strokeWidth) {
            mStrokeWidth = strokeWidth;
            mPaint.setStrokeWidth(strokeWidth);
            invalidateSelf();
        }

        @SuppressWarnings("unused")
        public float getStrokeWidth() {
            return mStrokeWidth;
        }

        @SuppressWarnings("unused")
        public void setStartTrim(float startTrim) {
            mStartTrim = startTrim;
            invalidateSelf();
        }

        @SuppressWarnings("unused")
        public float getStartTrim() {
            return mStartTrim;
        }

        public float getStartingStartTrim() {
            return mStartingStartTrim;
        }

        public float getStartingEndTrim() {
            return mStartingEndTrim;
        }

        public int getStartingColor() {
            return mColors[mColorIndex];
        }

        @SuppressWarnings("unused")
        public void setEndTrim(float endTrim) {
            mEndTrim = endTrim;
            invalidateSelf();
        }

        @SuppressWarnings("unused")
        public float getEndTrim() {
            return mEndTrim;
        }

        @SuppressWarnings("unused")
        public void setRotation(float rotation) {
            mRotation = rotation;
            invalidateSelf();
        }

        @SuppressWarnings("unused")
        public float getRotation() {
            return mRotation;
        }

        public void setInsets(int width, int height) {
            final float minEdge = (float) Math.min(width, height);
            float insets;
            if (mRingCenterRadius <= 0 || minEdge < 0) {
                insets = (float) Math.ceil(mStrokeWidth / 2.0f);
            } else {
                insets = (float) (minEdge / 2.0f - mRingCenterRadius);
            }
            mStrokeInset = insets;
        }

        @SuppressWarnings("unused")
        public float getInsets() {
            return mStrokeInset;
        }

        /**
         * @param centerRadius Inner radius in px of the circle the progress
         *            spinner arc traces.
         */
        public void setCenterRadius(double centerRadius) {
            mRingCenterRadius = centerRadius;
        }

        public double getCenterRadius() {
            return mRingCenterRadius;
        }

        /**
         * @param show Set to true to show the arrow head on the progress spinner.
         */
        public void setShowArrow(boolean show) {
            if (mShowArrow != show) {
                mShowArrow = show;
                invalidateSelf();
            }
        }

        /**
         * @param scale Set the scale of the arrowhead for the spinner.
         */
        public void setArrowScale(float scale) {
            if (scale != mArrowScale) {
                mArrowScale = scale;
                invalidateSelf();
            }
        }

        /**
         * @return The amount the progress spinner is currently rotated, between [0..1].
         */
        public float getStartingRotation() {
            return mStartingRotation;
        }

        /**
         * If the start / end trim are offset to begin with, store them so that
         * animation starts from that offset.
         */
        public void storeOriginals() {
            mStartingStartTrim = mStartTrim;
            mStartingEndTrim = mEndTrim;
            mStartingRotation = mRotation;
        }

        /**
         * Reset the progress spinner to default rotation, start and end angles.
         */
        public void resetOriginals() {
            mStartingStartTrim = 0;
            mStartingEndTrim = 0;
            mStartingRotation = 0;
            setStartTrim(0);
            setEndTrim(0);
            setRotation(0);
        }

        private void invalidateSelf() {
            mCallback.invalidateDrawable(null);
        }
    }
}


================================================
FILE: lib/src/main/res/drawable/animated_rotate.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/loading_1"
    android:duration="5"
    android:indeterminate="true"
    android:pivotX="50%"
    android:pivotY="50%">

</animated-rotate>


================================================
FILE: lib/src/main/res/drawable/animated_rotate_1.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<animation-list android:oneshot="false"
  xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:duration="120" android:drawable="@drawable/ic_loading_1" />
    <item android:duration="120" android:drawable="@drawable/ic_loading_2" />
    <item android:duration="120" android:drawable="@drawable/ic_loading_3" />
</animation-list>

================================================
FILE: lib/src/main/res/drawable/spinner.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<animation-list android:oneshot="false"
  xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:duration="60" android:drawable="@drawable/loading_1" />
    <item android:duration="60" android:drawable="@drawable/loading_2" />
    <item android:duration="60" android:drawable="@drawable/loading_3" />
    <item android:duration="60" android:drawable="@drawable/loading_4" />
    <item android:duration="60" android:drawable="@drawable/loading_5" />
    <item android:duration="60" android:drawable="@drawable/loading_6" />
    <item android:duration="60" android:drawable="@drawable/loading_7" />
    <item android:duration="60" android:drawable="@drawable/loading_8" />
</animation-list>

================================================
FILE: lib/src/main/res/layout/common_loading_refresh_header.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="88dp"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/static_loading"
        android:layout_width="35dp"
        android:layout_height="35dp"
        android:layout_gravity="center"
        android:background="@drawable/loading_1"
        android:indeterminate="true" />

    <ProgressBar
        android:id="@+id/progressbar"
        android:layout_width="35dp"
        android:layout_height="35dp"
        android:layout_gravity="center"
        android:indeterminate="true"
        android:indeterminateDrawable="@drawable/spinner" />

</FrameLayout>

================================================
FILE: lib/src/main/res/layout/material_refresh_header.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="88dp"
    android:layout_height="match_parent">

</FrameLayout>

================================================
FILE: lib/src/main/res/layout/nice_refresh_header.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="88dp"
              android:layout_height="match_parent">

    <ImageView
        android:id="@+id/static_loading"
        android:layout_width="52dp"
        android:layout_height="58dp"
        android:indeterminate="true"
        android:background="@drawable/ic_loading_1"
        android:layout_gravity="center"/>

    <ProgressBar
        android:id="@+id/progressbar"
        android:layout_width="52dp"
        android:layout_height="58dp"
        android:indeterminate="true"
        android:indeterminateDrawable="@drawable/animated_rotate_1"
        android:layout_gravity="center"/>

</FrameLayout>

================================================
FILE: lib/src/main/res/values/strings.xml
================================================
<resources>
    <string name="app_name">lib</string>
</resources>


================================================
FILE: settings.gradle
================================================
include ':app', ':lib'
Download .txt
gitextract_0us6p602/

├── README.md
├── apk/
│   └── app-debug.apk
├── app/
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── com/
│           │       └── example/
│           │           └── robincxiao/
│           │               └── horizontalrefreshlayout/
│           │                   ├── LayoutAdapter.java
│           │                   └── MainActivity.java
│           └── res/
│               ├── drawable/
│               │   └── item_background.xml
│               ├── layout/
│               │   ├── activity_main.xml
│               │   └── item.xml
│               ├── values/
│               │   ├── colors.xml
│               │   ├── dimens.xml
│               │   ├── strings.xml
│               │   └── styles.xml
│               └── values-w820dp/
│                   └── dimens.xml
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── jcenter-push.gradle
├── lib/
│   ├── build.gradle
│   ├── proguard-rules.pro
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── xiao/
│           │       └── free/
│           │           └── horizontalrefreshlayout/
│           │               ├── HorizontalRefreshLayout.java
│           │               ├── RefreshCallBack.java
│           │               ├── RefreshHeader.java
│           │               ├── refreshhead/
│           │               │   ├── LoadingRefreshHeader.java
│           │               │   ├── MaterialRefreshHeader.java
│           │               │   └── NiceRefreshHeader.java
│           │               └── widget/
│           │                   ├── CircleImageView.java
│           │                   └── MaterialProgressDrawable.java
│           └── res/
│               ├── drawable/
│               │   ├── animated_rotate.xml
│               │   ├── animated_rotate_1.xml
│               │   └── spinner.xml
│               ├── layout/
│               │   ├── common_loading_refresh_header.xml
│               │   ├── material_refresh_header.xml
│               │   └── nice_refresh_header.xml
│               └── values/
│                   └── strings.xml
└── settings.gradle
Download .txt
SYMBOL INDEX (144 symbols across 10 files)

FILE: app/src/main/java/com/example/robincxiao/horizontalrefreshlayout/LayoutAdapter.java
  class LayoutAdapter (line 31) | public class LayoutAdapter extends RecyclerView.Adapter<LayoutAdapter.Si...
    class SimpleViewHolder (line 42) | public static class SimpleViewHolder extends RecyclerView.ViewHolder {
      method SimpleViewHolder (line 46) | public SimpleViewHolder(View view) {
    method LayoutAdapter (line 53) | public LayoutAdapter(Context context, RecyclerView recyclerView) {
    method LayoutAdapter (line 57) | public LayoutAdapter(Context context, RecyclerView recyclerView, int i...
    method addItem (line 67) | public void addItem(int position) {
    method removeItem (line 73) | public void removeItem(int position) {
    method getMore (line 78) | public void getMore() {
    method onCreateViewHolder (line 85) | @Override
    method onBindViewHolder (line 91) | @Override
    method getItemCount (line 106) | @Override

FILE: app/src/main/java/com/example/robincxiao/horizontalrefreshlayout/MainActivity.java
  class MainActivity (line 15) | public class MainActivity extends AppCompatActivity implements RefreshCa...
    method onCreate (line 20) | @Override
    method onLeftRefreshing (line 52) | @Override
    method onRightRefreshing (line 62) | @Override

FILE: lib/src/main/java/xiao/free/horizontalrefreshlayout/HorizontalRefreshLayout.java
  class HorizontalRefreshLayout (line 28) | public class HorizontalRefreshLayout extends FrameLayout {
    method HorizontalRefreshLayout (line 62) | public HorizontalRefreshLayout(Context context) {
    method HorizontalRefreshLayout (line 68) | public HorizontalRefreshLayout(Context context, AttributeSet attrs) {
    method HorizontalRefreshLayout (line 74) | public HorizontalRefreshLayout(Context context, AttributeSet attrs, in...
    method setRefreshCallback (line 80) | public void setRefreshCallback(RefreshCallBack callback) {
    method init (line 84) | private void init() {
    method onMeasure (line 89) | @Override
    method onLayout (line 108) | @Override
    method findTargetView (line 138) | private void findTargetView() {
    method onInterceptTouchEvent (line 150) | @Override
    method onTouchEvent (line 197) | @Override
    method smoothRelease (line 306) | private void smoothRelease() {
    method smoothLocateToRefresh (line 335) | private void smoothLocateToRefresh() {
    method onRefreshComplete (line 388) | public void onRefreshComplete() {
    method startAutoRefresh (line 397) | public void startAutoRefresh(final int leftOrRight) {
    method setLeftHeadView (line 409) | private void setLeftHeadView(View view) {
    method setRightHeadView (line 415) | private void setRightHeadView(View view) {
    method setRefreshHeader (line 426) | public void setRefreshHeader(RefreshHeader header, int startOrEnd) {
    method canChildScrollRight (line 441) | public boolean canChildScrollRight() {
    method canChildScrollLeft (line 450) | public boolean canChildScrollLeft() {
    method dp2px (line 455) | public static int dp2px(Context context, float dpVal) {

FILE: lib/src/main/java/xiao/free/horizontalrefreshlayout/RefreshCallBack.java
  type RefreshCallBack (line 6) | public interface RefreshCallBack {
    method onLeftRefreshing (line 7) | void onLeftRefreshing();
    method onRightRefreshing (line 8) | void onRightRefreshing();

FILE: lib/src/main/java/xiao/free/horizontalrefreshlayout/RefreshHeader.java
  type RefreshHeader (line 10) | public interface RefreshHeader {
    method onStart (line 15) | void onStart(int dragPosition, View refreshHead);
    method onDragging (line 20) | void onDragging(float distance, float percent, View refreshHead);
    method onReadyToRelease (line 22) | void onReadyToRelease(View refreshHead);
    method getView (line 24) | @NonNull View getView(ViewGroup container);
    method onRefreshing (line 26) | void onRefreshing(View refreshHead);

FILE: lib/src/main/java/xiao/free/horizontalrefreshlayout/refreshhead/LoadingRefreshHeader.java
  class LoadingRefreshHeader (line 17) | public class LoadingRefreshHeader implements RefreshHeader {
    method LoadingRefreshHeader (line 22) | public LoadingRefreshHeader(Context context) {
    method getView (line 26) | @NonNull
    method onStart (line 37) | @Override
    method onDragging (line 43) | @Override
    method onReadyToRelease (line 48) | @Override
    method onRefreshing (line 53) | @Override

FILE: lib/src/main/java/xiao/free/horizontalrefreshlayout/refreshhead/MaterialRefreshHeader.java
  class MaterialRefreshHeader (line 20) | public class MaterialRefreshHeader implements RefreshHeader {
    method MaterialRefreshHeader (line 27) | public MaterialRefreshHeader(int startOrEnd) {
    method onStart (line 31) | @Override
    method onDragging (line 39) | @Override
    method onReadyToRelease (line 47) | @Override
    method getView (line 51) | @NonNull
    method onRefreshing (line 71) | @Override

FILE: lib/src/main/java/xiao/free/horizontalrefreshlayout/refreshhead/NiceRefreshHeader.java
  class NiceRefreshHeader (line 17) | public class NiceRefreshHeader implements RefreshHeader {
    method NiceRefreshHeader (line 22) | public NiceRefreshHeader(Context context) {
    method getView (line 26) | @NonNull
    method onStart (line 37) | @Override
    method onDragging (line 43) | @Override
    method onReadyToRelease (line 66) | @Override
    method onRefreshing (line 71) | @Override

FILE: lib/src/main/java/xiao/free/horizontalrefreshlayout/widget/CircleImageView.java
  class CircleImageView (line 36) | public class CircleImageView extends ImageView {
    method CircleImageView (line 49) | public CircleImageView(Context context, int color, final float radius) {
    method elevationSupported (line 76) | private boolean elevationSupported() {
    method onMeasure (line 80) | @Override
    method setAnimationListener (line 89) | public void setAnimationListener(Animation.AnimationListener listener) {
    method onAnimationStart (line 93) | @Override
    method onAnimationEnd (line 101) | @Override
    method setBackgroundColorRes (line 114) | public void setBackgroundColorRes(int colorRes) {
    method setBackgroundColor (line 118) | @Override
    class OvalShadow (line 125) | private class OvalShadow extends OvalShape {
      method OvalShadow (line 130) | public OvalShadow(int shadowRadius, int circleDiameter) {
      method draw (line 142) | @Override

FILE: lib/src/main/java/xiao/free/horizontalrefreshlayout/widget/MaterialProgressDrawable.java
  class MaterialProgressDrawable (line 49) | public class MaterialProgressDrawable extends Drawable implements Animat...
    method MaterialProgressDrawable (line 116) | public MaterialProgressDrawable(Context context, View parent) {
    method setSizeParameters (line 127) | private void setSizeParameters(double progressCircleWidth, double prog...
    method updateSizes (line 149) | public void updateSizes(@ProgressDrawableSize int size) {
    method showArrow (line 162) | public void showArrow(boolean show) {
    method setArrowScale (line 169) | public void setArrowScale(float scale) {
    method setStartEndTrim (line 179) | public void setStartEndTrim(float startAngle, float endAngle) {
    method setProgressRotation (line 189) | public void setProgressRotation(float rotation) {
    method setBackgroundColor (line 196) | public void setBackgroundColor(int color) {
    method setColorSchemeColors (line 207) | public void setColorSchemeColors(int... colors) {
    method getIntrinsicHeight (line 212) | @Override
    method getIntrinsicWidth (line 217) | @Override
    method draw (line 222) | @Override
    method setAlpha (line 231) | @Override
    method getAlpha (line 236) | public int getAlpha() {
    method setColorFilter (line 240) | @Override
    method setRotation (line 245) | @SuppressWarnings("unused")
    method getRotation (line 251) | @SuppressWarnings("unused")
    method getOpacity (line 256) | @Override
    method isRunning (line 261) | @Override
    method start (line 274) | @Override
    method stop (line 291) | @Override
    method getMinProgressArc (line 300) | private float getMinProgressArc(Ring ring) {
    method evaluateColorChange (line 306) | private int evaluateColorChange(float fraction, int startValue, int en...
    method updateRingColor (line 330) | private void updateRingColor(float interpolatedTime, Ring ring) {
    method applyFinishTranslation (line 341) | private void applyFinishTranslation(float interpolatedTime, Ring ring) {
    method setupAnimators (line 359) | private void setupAnimators() {
    method invalidateDrawable (line 448) | @Override
    method scheduleDrawable (line 453) | @Override
    method unscheduleDrawable (line 458) | @Override
    class Ring (line 464) | private static class Ring {
      method Ring (line 496) | public Ring(Callback callback) {
      method setBackgroundColor (line 507) | public void setBackgroundColor(int color) {
      method setArrowDimensions (line 517) | public void setArrowDimensions(float width, float height) {
      method draw (line 525) | public void draw(Canvas c, Rect bounds) {
      method drawTriangle (line 547) | private void drawTriangle(Canvas c, float startAngle, float sweepAng...
      method setColors (line 585) | public void setColors(@NonNull int[] colors) {
      method setColor (line 598) | public void setColor(int color) {
      method setColorIndex (line 606) | public void setColorIndex(int index) {
      method getNextColor (line 614) | public int getNextColor() {
      method getNextColorIndex (line 618) | private int getNextColorIndex() {
      method goToNextColor (line 626) | public void goToNextColor() {
      method setColorFilter (line 630) | public void setColorFilter(ColorFilter filter) {
      method setAlpha (line 638) | public void setAlpha(int alpha) {
      method getAlpha (line 645) | public int getAlpha() {
      method setStrokeWidth (line 652) | public void setStrokeWidth(float strokeWidth) {
      method getStrokeWidth (line 658) | @SuppressWarnings("unused")
      method setStartTrim (line 663) | @SuppressWarnings("unused")
      method getStartTrim (line 669) | @SuppressWarnings("unused")
      method getStartingStartTrim (line 674) | public float getStartingStartTrim() {
      method getStartingEndTrim (line 678) | public float getStartingEndTrim() {
      method getStartingColor (line 682) | public int getStartingColor() {
      method setEndTrim (line 686) | @SuppressWarnings("unused")
      method getEndTrim (line 692) | @SuppressWarnings("unused")
      method setRotation (line 697) | @SuppressWarnings("unused")
      method getRotation (line 703) | @SuppressWarnings("unused")
      method setInsets (line 708) | public void setInsets(int width, int height) {
      method getInsets (line 719) | @SuppressWarnings("unused")
      method setCenterRadius (line 728) | public void setCenterRadius(double centerRadius) {
      method getCenterRadius (line 732) | public double getCenterRadius() {
      method setShowArrow (line 739) | public void setShowArrow(boolean show) {
      method setArrowScale (line 749) | public void setArrowScale(float scale) {
      method getStartingRotation (line 759) | public float getStartingRotation() {
      method storeOriginals (line 767) | public void storeOriginals() {
      method resetOriginals (line 776) | public void resetOriginals() {
      method invalidateSelf (line 785) | private void invalidateSelf() {
Condensed preview — 41 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (97K chars).
[
  {
    "path": "README.md",
    "chars": 2453,
    "preview": ":running:HorizontalRefreshLayout-Android:running:\n============\n\n开发者使用 HorizontalRefreshLayout-Android 可以对RecycView、Listv"
  },
  {
    "path": "app/build.gradle",
    "chars": 840,
    "preview": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion ANDROID_BUILD_SDK_VERSION as int\n    buildTools"
  },
  {
    "path": "app/proguard-rules.pro",
    "chars": 645,
    "preview": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in C:"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "chars": 735,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package="
  },
  {
    "path": "app/src/main/java/com/example/robincxiao/horizontalrefreshlayout/LayoutAdapter.java",
    "chars": 3615,
    "preview": "/*\n * Copyright (C) 2014 Lucas Rocha\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may no"
  },
  {
    "path": "app/src/main/java/com/example/robincxiao/horizontalrefreshlayout/MainActivity.java",
    "chars": 2848,
    "preview": "package com.example.robincxiao.horizontalrefreshlayout;\n\nimport android.os.Bundle;\nimport android.support.v7.app.AppComp"
  },
  {
    "path": "app/src/main/res/drawable/item_background.xml",
    "chars": 1201,
    "preview": "<!--\n  ~ Copyright (C) 2014 Lucas Rocha\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you "
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "chars": 812,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xiao.free.horizontalrefreshlayout.HorizontalRefreshLayout xmlns:android=\"http://"
  },
  {
    "path": "app/src/main/res/layout/item.xml",
    "chars": 1156,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    andr"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "chars": 358,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"color"
  },
  {
    "path": "app/src/main/res/values/dimens.xml",
    "chars": 211,
    "preview": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "chars": 86,
    "preview": "<resources>\n    <string name=\"app_name\">HorizontalRefreshLayout</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "chars": 383,
    "preview": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar"
  },
  {
    "path": "app/src/main/res/values-w820dp/dimens.xml",
    "chars": 358,
    "preview": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as s"
  },
  {
    "path": "build.gradle",
    "chars": 799,
    "preview": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    r"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "chars": 233,
    "preview": "#Mon Dec 28 10:00:20 PST 2015\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_"
  },
  {
    "path": "gradle.properties",
    "chars": 1080,
    "preview": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will o"
  },
  {
    "path": "gradlew",
    "chars": 4971,
    "preview": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start "
  },
  {
    "path": "gradlew.bat",
    "chars": 2314,
    "preview": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem "
  },
  {
    "path": "jcenter-push.gradle",
    "chars": 2212,
    "preview": "apply plugin: 'com.jfrog.bintray'\napply plugin: 'com.github.dcendents.android-maven'\n\ndef siteUrl = \"https://github.com/"
  },
  {
    "path": "lib/build.gradle",
    "chars": 782,
    "preview": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion ANDROID_BUILD_SDK_VERSION as int\n    buildToolsVers"
  },
  {
    "path": "lib/proguard-rules.pro",
    "chars": 645,
    "preview": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in C:"
  },
  {
    "path": "lib/src/main/AndroidManifest.xml",
    "chars": 265,
    "preview": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"xiao.free.horizontalrefreshlayout\">\n\n "
  },
  {
    "path": "lib/src/main/java/xiao/free/horizontalrefreshlayout/HorizontalRefreshLayout.java",
    "chars": 16472,
    "preview": "package xiao.free.horizontalrefreshlayout;\n\nimport android.animation.Animator;\nimport android.animation.AnimatorListener"
  },
  {
    "path": "lib/src/main/java/xiao/free/horizontalrefreshlayout/RefreshCallBack.java",
    "chars": 184,
    "preview": "package xiao.free.horizontalrefreshlayout;\n\n/**\n * Created by wangqi on 2015/12/24.\n */\npublic interface RefreshCallBack"
  },
  {
    "path": "lib/src/main/java/xiao/free/horizontalrefreshlayout/RefreshHeader.java",
    "chars": 631,
    "preview": "package xiao.free.horizontalrefreshlayout;\n\nimport android.support.annotation.NonNull;\nimport android.view.View;\nimport "
  },
  {
    "path": "lib/src/main/java/xiao/free/horizontalrefreshlayout/refreshhead/LoadingRefreshHeader.java",
    "chars": 1706,
    "preview": "package xiao.free.horizontalrefreshlayout.refreshhead;\n\nimport android.content.Context;\nimport android.support.annotatio"
  },
  {
    "path": "lib/src/main/java/xiao/free/horizontalrefreshlayout/refreshhead/MaterialRefreshHeader.java",
    "chars": 2747,
    "preview": "package xiao.free.horizontalrefreshlayout.refreshhead;\n\nimport android.support.annotation.NonNull;\nimport android.view.G"
  },
  {
    "path": "lib/src/main/java/xiao/free/horizontalrefreshlayout/refreshhead/NiceRefreshHeader.java",
    "chars": 2196,
    "preview": "package xiao.free.horizontalrefreshlayout.refreshhead;\n\nimport android.content.Context;\nimport android.support.annotatio"
  },
  {
    "path": "lib/src/main/java/xiao/free/horizontalrefreshlayout/widget/CircleImageView.java",
    "chars": 5566,
    "preview": "/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"Lice"
  },
  {
    "path": "lib/src/main/java/xiao/free/horizontalrefreshlayout/widget/MaterialProgressDrawable.java",
    "chars": 27598,
    "preview": "/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"Lice"
  },
  {
    "path": "lib/src/main/res/drawable/animated_rotate.xml",
    "chars": 287,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<animated-rotate xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    a"
  },
  {
    "path": "lib/src/main/res/drawable/animated_rotate_1.xml",
    "chars": 392,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<animation-list android:oneshot=\"false\"\n  xmlns:android=\"http://schemas.android.c"
  },
  {
    "path": "lib/src/main/res/drawable/spinner.xml",
    "chars": 750,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<animation-list android:oneshot=\"false\"\n  xmlns:android=\"http://schemas.android.c"
  },
  {
    "path": "lib/src/main/res/layout/common_loading_refresh_header.xml",
    "chars": 726,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    andro"
  },
  {
    "path": "lib/src/main/res/layout/material_refresh_header.xml",
    "chars": 200,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    andro"
  },
  {
    "path": "lib/src/main/res/layout/nice_refresh_header.xml",
    "chars": 757,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n         "
  },
  {
    "path": "lib/src/main/res/values/strings.xml",
    "chars": 66,
    "preview": "<resources>\n    <string name=\"app_name\">lib</string>\n</resources>\n"
  },
  {
    "path": "settings.gradle",
    "chars": 23,
    "preview": "include ':app', ':lib'\n"
  }
]

// ... and 2 more files (download for full content)

About this extraction

This page contains the full source code of the linuxjava/HorizontalRefreshLayout GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 41 files (87.2 KB), approximately 21.3k tokens, and a symbol index with 144 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!