[
  {
    "path": "README.md",
    "content": ":running:HorizontalRefreshLayout-Android:running:\n============\n\n开发者使用 HorizontalRefreshLayout-Android 可以对RecycView、Listview、ScrollView等控件实现左右刷新\n\n##  APK下载\n[Download](https://github.com/linuxjava/HorizontalRefreshLayout/raw/master/apk/app-debug.apk)\n##  Demo使用\n运行demo需删除gradle.properties中的代理\n```xml\nsystemProp.http.proxyHost=dev-proxy.oa.com\nsystemProp.http.proxyPort=8080\nsystemProp.https.proxyHost=dev-proxy.oa.com\nsystemProp.https.proxyPort=8080\n```\n## Gradle配置\ncompile 'xiao.free.horizontalrefreshlayout:lib:v0.1.2'\n## XML配置\n```xml\n<xiao.free.horizontalrefreshlayout.HorizontalRefreshLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/refresh\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@color/blue\">\n\n    <com.lsjwzh.widget.recyclerviewpager.RecyclerViewPager\n        android:id=\"@+id/viewpager\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:clipToPadding=\"false\"\n        app:rvp_flingFactor=\"0.15\"\n        app:rvp_singlePageFling=\"false\"\n        app:rvp_triggerOffset=\"0.5\" />\n\n</xiao.free.horizontalrefreshlayout.HorizontalRefreshLayout>\n```\n## Java代码\n```java\nrefreshLayout = (HorizontalRefreshLayout) findViewById(R.id.refresh);\nrefreshLayout.setRefreshCallback(this);\nrefreshLayout.setRefreshHeader(new LoadingRefreshHeader(this), HorizontalRefreshLayout.LEFT);\nrefreshLayout.setRefreshHeader(new LoadingRefreshHeader(this), HorizontalRefreshLayout.RIGHT);\n```\n通过setRefreshHeader方法可以设置左右刷新头部，库中已支持三种刷新效果，如下图所示：\n\n![image](https://github.com/linuxjava/HorizontalRefreshLayout/raw/master/gif/1.gif) \n![image](https://github.com/linuxjava/HorizontalRefreshLayout/raw/master/gif/2.gif)\n![image](https://github.com/linuxjava/HorizontalRefreshLayout/raw/master/gif/3.gif)\n\n## 自定义Header\n可通过实现如下接口实现自定义header\n```java\npublic interface RefreshHeader {\n    /**\n     * @param dragPosition  HorizontalRefreshLayout.START or HorizontalRefreshLayout.END\n     */\n    void onStart(int dragPosition, View refreshHead);\n\n    /**\n     * @param distance\n     */\n    void onDragging(float distance, float percent, View refreshHead);\n\n    void onReadyToRelease(View refreshHead);\n\n    @NonNull View getView(ViewGroup container);\n\n    void onRefreshing(View refreshHead);\n}\n```\n具体可参考lib库中refreshhead目录中的实现\n"
  },
  {
    "path": "app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion ANDROID_BUILD_SDK_VERSION as int\n    buildToolsVersion ANDROID_BUILD_TOOLS_VERSION\n    defaultConfig {\n        applicationId \"com.example.robincxiao.horizontalrefreshlayout\"\n        minSdkVersion 14\n        targetSdkVersion ANDROID_BUILD_SDK_VERSION\n        versionCode 1\n        versionName \"1.0\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    compile 'com.github.lsjwzh.RecyclerViewPager:lib:v1.1.2'\n    //compile project(':lib')\n    compile 'xiao.free.horizontalrefreshlayout:lib:v0.1.2'\n    //compile 'xiao.free.horizontalrefreshlayout:lib:v1.0.0'\n}\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in C:\\android-sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.example.robincxiao.horizontalrefreshlayout\">\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\n        <activity android:name=\".MainActivity\"\n            android:screenOrientation=\"portrait\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n    </application>\n\n</manifest>"
  },
  {
    "path": "app/src/main/java/com/example/robincxiao/horizontalrefreshlayout/LayoutAdapter.java",
    "content": "/*\n * Copyright (C) 2014 Lucas Rocha\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage com.example.robincxiao.horizontalrefreshlayout;\n\nimport android.content.Context;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class LayoutAdapter extends RecyclerView.Adapter<LayoutAdapter.SimpleViewHolder> {\n    private static final int DEFAULT_ITEM_COUNT = 5;\n\n    private final Context mContext;\n    private final RecyclerView mRecyclerView;\n    private final List<Integer> mItems;\n    private int mCurrentItemId = 0;\n    private int[] imageIds = {R.mipmap.card_cover1, R.mipmap.card_cover2, R.mipmap.card_cover3,\n            R.mipmap.card_cover4, R.mipmap.card_cover5, R.mipmap.card_cover6,\n            R.mipmap.card_cover7, R.mipmap.card_cover8};\n\n    public static class SimpleViewHolder extends RecyclerView.ViewHolder {\n        public final TextView title;\n        public final ImageView myImage;\n\n        public SimpleViewHolder(View view) {\n            super(view);\n            title = (TextView) view.findViewById(R.id.title);\n            myImage = (ImageView) view.findViewById(R.id.image);\n        }\n    }\n\n    public LayoutAdapter(Context context, RecyclerView recyclerView) {\n        this(context, recyclerView, DEFAULT_ITEM_COUNT);\n    }\n\n    public LayoutAdapter(Context context, RecyclerView recyclerView, int itemCount) {\n        mContext = context;\n        mItems = new ArrayList<>(itemCount);\n        for (int i = 0; i < itemCount; i++) {\n            addItem(i);\n        }\n\n        mRecyclerView = recyclerView;\n    }\n\n    public void addItem(int position) {\n        final int id = mCurrentItemId++;\n        mItems.add(position, id);\n        notifyItemInserted(position);\n    }\n\n    public void removeItem(int position) {\n        mItems.remove(position);\n        notifyItemRemoved(position);\n    }\n\n    public void getMore() {\n        int size = getItemCount();\n        for (int i = size; i < size + 5; i++) {\n            addItem(i);\n        }\n    }\n\n    @Override\n    public SimpleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n        final View view = LayoutInflater.from(mContext).inflate(R.layout.item, parent, false);\n        return new SimpleViewHolder(view);\n    }\n\n    @Override\n    public void onBindViewHolder(SimpleViewHolder holder, int position) {\n        holder.title.setText(\"Index \" + mItems.get(position));\n        holder.myImage.setImageResource(imageIds[position % imageIds.length]);\n\n        final View itemView = holder.itemView;\n        itemView.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                Toast.makeText(mContext, \"\", Toast.LENGTH_SHORT).show();\n            }\n        });\n        final int itemId = mItems.get(position);\n    }\n\n    @Override\n    public int getItemCount() {\n        return mItems.size();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/example/robincxiao/horizontalrefreshlayout/MainActivity.java",
    "content": "package com.example.robincxiao.horizontalrefreshlayout;\n\nimport android.os.Bundle;\nimport android.support.v7.app.AppCompatActivity;\nimport android.support.v7.widget.LinearLayoutManager;\n\nimport com.lsjwzh.widget.recyclerviewpager.RecyclerViewPager;\n\nimport xiao.free.horizontalrefreshlayout.HorizontalRefreshLayout;\nimport xiao.free.horizontalrefreshlayout.RefreshCallBack;\nimport xiao.free.horizontalrefreshlayout.refreshhead.LoadingRefreshHeader;\nimport xiao.free.horizontalrefreshlayout.refreshhead.MaterialRefreshHeader;\nimport xiao.free.horizontalrefreshlayout.refreshhead.NiceRefreshHeader;\n\npublic class MainActivity extends AppCompatActivity implements RefreshCallBack {\n    private HorizontalRefreshLayout refreshLayout;\n    protected RecyclerViewPager mRecyclerView;\n    private LayoutAdapter mLayoutAdapter;\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n        refreshLayout = (HorizontalRefreshLayout) findViewById(R.id.refresh);\n        refreshLayout.setRefreshCallback(this);\n        refreshLayout.setRefreshHeader(new NiceRefreshHeader(this), HorizontalRefreshLayout.LEFT);\n        refreshLayout.setRefreshHeader(new NiceRefreshHeader(this), HorizontalRefreshLayout.RIGHT);\n\n        mRecyclerView = (RecyclerViewPager) findViewById(R.id.viewpager);\n        LinearLayoutManager layout = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false);\n        mRecyclerView.setLayoutManager(layout);\n        mLayoutAdapter = new LayoutAdapter(this, mRecyclerView);\n        mRecyclerView.setAdapter(mLayoutAdapter);\n        mRecyclerView.setHasFixedSize(true);\n        mRecyclerView.setLongClickable(true);\n\n        mRecyclerView.addOnPageChangedListener(new RecyclerViewPager.OnPageChangedListener() {\n            @Override\n            public void OnPageChanged(int oldPosition, int newPosition) {\n                int size = mLayoutAdapter.getItemCount();\n                if (size > 1 && newPosition == size - 1) {\n                    //mLayoutAdapter.getMore();\n                    //refreshLayout.startAutoRefresh(HorizontalRefreshLayout.RIGHT);\n                }\n            }\n        });\n\n        //refreshLayout.startAutoRefresh(HorizontalRefreshLayout.LEFT);\n    }\n\n    @Override\n    public void onLeftRefreshing() {\n        refreshLayout.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                refreshLayout.onRefreshComplete();\n            }\n        }, 2000);\n    }\n\n    @Override\n    public void onRightRefreshing() {\n        refreshLayout.postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                mLayoutAdapter.getMore();\n                refreshLayout.onRefreshComplete();\n            }\n        }, 2000);\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/res/drawable/item_background.xml",
    "content": "<!--\n  ~ Copyright (C) 2014 Lucas Rocha\n  ~\n  ~ Licensed under the Apache License, Version 2.0 (the \"License\");\n  ~ you may not use this file except in compliance with the License.\n  ~ You may obtain a copy of the License at\n  ~\n  ~     http://www.apache.org/licenses/LICENSE-2.0\n  ~\n  ~ Unless required by applicable law or agreed to in writing, software\n  ~ distributed under the License is distributed on an \"AS IS\" BASIS,\n  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n  ~ See the License for the specific language governing permissions and\n  ~ limitations under the License.\n  -->\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item android:state_activated=\"true\"\n          android:drawable=\"@color/item_activated_color\"/>\n\n    <item android:state_pressed=\"true\"\n          android:drawable=\"@color/item_pressed_color\"/>\n\n    <item>\n        <shape android:shape=\"rectangle\">\n            <solid android:color=\"@color/material_blue_grey_900\"></solid>\n            <stroke android:color=\"@color/item_activated_color\" android:width=\"2px\"></stroke>\n            <corners android:radius=\"5dp\"></corners>\n        </shape>\n    </item>\n\n</selector>"
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<xiao.free.horizontalrefreshlayout.HorizontalRefreshLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/refresh\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@color/blue\">\n\n    <com.lsjwzh.widget.recyclerviewpager.RecyclerViewPager\n        android:id=\"@+id/viewpager\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:clipToPadding=\"false\"\n        app:rvp_flingFactor=\"0.15\"\n        app:rvp_singlePageFling=\"false\"\n        app:rvp_triggerOffset=\"0.5\" />\n\n</xiao.free.horizontalrefreshlayout.HorizontalRefreshLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_marginBottom=\"40dp\"\n        android:layout_marginLeft=\"10dp\"\n        android:layout_marginRight=\"10dp\"\n        android:layout_marginTop=\"40dp\"\n        android:background=\"@mipmap/home_card_bg\">\n\n        <TextView\n            android:id=\"@+id/title\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textColor=\"#000000\"\n            android:textSize=\"22.0sp\"\n            android:textStyle=\"bold\"\n            android:layout_marginLeft=\"10dp\"\n            android:layout_marginTop=\"10dp\"/>\n\n        <ImageView\n            android:id=\"@+id/image\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"200dp\"\n            android:scaleType=\"centerCrop\"\n            android:layout_centerVertical=\"true\"/>\n    </RelativeLayout>\n\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"colorPrimaryDark\">#303F9F</color>\n    <color name=\"colorAccent\">#FF4081</color>\n\n    <color name=\"item_pressed_color\">#CCCCCC</color>\n    <color name=\"item_activated_color\">#77CEEE</color>\n    <color name=\"blue\">#ff33b5e5</color>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">HorizontalRefreshLayout</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-w820dp/dimens.xml",
    "content": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as screen margins) for screens with more than 820dp of available width. This\n         would include 7\" and 10\" devices in landscape (~960dp and ~1280dp respectively). -->\n    <dimen name=\"activity_horizontal_margin\">64dp</dimen>\n</resources>\n"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    repositories {\n        jcenter()\n    }\n    dependencies {\n        classpath \"com.android.tools.build:gradle:$GRADLE_VERSION\"\n\n        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'\n        classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\n\nallprojects {\n    repositories {\n        maven { url \"https://jitpack.io\" }\n        jcenter()\n    }\n\n    tasks.withType(Javadoc).all {\n        enabled = false\n        options.setEncoding('UTF-8')\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "#Mon Dec 28 10:00:20 PST 2015\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-2.14.1-all.zip\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\norg.gradle.jvmargs=-Xmx1536m\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true\n#gradle版本\nGRADLE_VERSION=2.1.0\n#目标SDK版本\nANDROID_BUILD_TARGET_SDK_VERSION=19\n#编译SDK版本\nANDROID_BUILD_SDK_VERSION=23\n#编译工具版本\nANDROID_BUILD_TOOLS_VERSION=23.0.2\n#V7包版本\nSUPPORT_LIBRARY_VERSION=23.4.0\n\n#代理\nsystemProp.http.proxyHost=dev-proxy.oa.com\nsystemProp.http.proxyPort=8080\nsystemProp.https.proxyHost=dev-proxy.oa.com\nsystemProp.https.proxyPort=8080\n"
  },
  {
    "path": "gradlew",
    "content": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start up script for UN*X\n##\n##############################################################################\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS=\"\"\n\nAPP_NAME=\"Gradle\"\nAPP_BASE_NAME=`basename \"$0\"`\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=\"maximum\"\n\nwarn ( ) {\n    echo \"$*\"\n}\n\ndie ( ) {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n}\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\ncase \"`uname`\" in\n  CYGWIN* )\n    cygwin=true\n    ;;\n  Darwin* )\n    darwin=true\n    ;;\n  MINGW* )\n    msys=true\n    ;;\nesac\n\n# Attempt to set APP_HOME\n# Resolve links: $0 may be a link\nPRG=\"$0\"\n# Need this for relative symlinks.\nwhile [ -h \"$PRG\" ] ; do\n    ls=`ls -ld \"$PRG\"`\n    link=`expr \"$ls\" : '.*-> \\(.*\\)$'`\n    if expr \"$link\" : '/.*' > /dev/null; then\n        PRG=\"$link\"\n    else\n        PRG=`dirname \"$PRG\"`\"/$link\"\n    fi\ndone\nSAVED=\"`pwd`\"\ncd \"`dirname \\\"$PRG\\\"`/\" >/dev/null\nAPP_HOME=\"`pwd -P`\"\ncd \"$SAVED\" >/dev/null\n\nCLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=\"$JAVA_HOME/jre/sh/java\"\n    else\n        JAVACMD=\"$JAVA_HOME/bin/java\"\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=\"java\"\n    which java >/dev/null 2>&1 || die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\nfi\n\n# Increase the maximum file descriptors if we can.\nif [ \"$cygwin\" = \"false\" -a \"$darwin\" = \"false\" ] ; then\n    MAX_FD_LIMIT=`ulimit -H -n`\n    if [ $? -eq 0 ] ; then\n        if [ \"$MAX_FD\" = \"maximum\" -o \"$MAX_FD\" = \"max\" ] ; then\n            MAX_FD=\"$MAX_FD_LIMIT\"\n        fi\n        ulimit -n $MAX_FD\n        if [ $? -ne 0 ] ; then\n            warn \"Could not set maximum file descriptor limit: $MAX_FD\"\n        fi\n    else\n        warn \"Could not query maximum file descriptor limit: $MAX_FD_LIMIT\"\n    fi\nfi\n\n# For Darwin, add options to specify how the application appears in the dock\nif $darwin; then\n    GRADLE_OPTS=\"$GRADLE_OPTS \\\"-Xdock:name=$APP_NAME\\\" \\\"-Xdock:icon=$APP_HOME/media/gradle.icns\\\"\"\nfi\n\n# For Cygwin, switch paths to Windows format before running java\nif $cygwin ; then\n    APP_HOME=`cygpath --path --mixed \"$APP_HOME\"`\n    CLASSPATH=`cygpath --path --mixed \"$CLASSPATH\"`\n    JAVACMD=`cygpath --unix \"$JAVACMD\"`\n\n    # We build the pattern for arguments to be converted via cygpath\n    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`\n    SEP=\"\"\n    for dir in $ROOTDIRSRAW ; do\n        ROOTDIRS=\"$ROOTDIRS$SEP$dir\"\n        SEP=\"|\"\n    done\n    OURCYGPATTERN=\"(^($ROOTDIRS))\"\n    # Add a user-defined pattern to the cygpath arguments\n    if [ \"$GRADLE_CYGPATTERN\" != \"\" ] ; then\n        OURCYGPATTERN=\"$OURCYGPATTERN|($GRADLE_CYGPATTERN)\"\n    fi\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    i=0\n    for arg in \"$@\" ; do\n        CHECK=`echo \"$arg\"|egrep -c \"$OURCYGPATTERN\" -`\n        CHECK2=`echo \"$arg\"|egrep -c \"^-\"`                                 ### Determine if an option\n\n        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition\n            eval `echo args$i`=`cygpath --path --ignore --mixed \"$arg\"`\n        else\n            eval `echo args$i`=\"\\\"$arg\\\"\"\n        fi\n        i=$((i+1))\n    done\n    case $i in\n        (0) set -- ;;\n        (1) set -- \"$args0\" ;;\n        (2) set -- \"$args0\" \"$args1\" ;;\n        (3) set -- \"$args0\" \"$args1\" \"$args2\" ;;\n        (4) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" ;;\n        (5) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" ;;\n        (6) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" ;;\n        (7) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" ;;\n        (8) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" ;;\n        (9) set -- \"$args0\" \"$args1\" \"$args2\" \"$args3\" \"$args4\" \"$args5\" \"$args6\" \"$args7\" \"$args8\" ;;\n    esac\nfi\n\n# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules\nfunction splitJvmOpts() {\n    JVM_OPTS=(\"$@\")\n}\neval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\nJVM_OPTS[${#JVM_OPTS[*]}]=\"-Dorg.gradle.appname=$APP_BASE_NAME\"\n\nexec \"$JAVACMD\" \"${JVM_OPTS[@]}\" -classpath \"$CLASSPATH\" org.gradle.wrapper.GradleWrapperMain \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem  Gradle startup script for Windows\n@rem\n@rem ##########################################################################\n\n@rem Set local scope for the variables with windows NT shell\nif \"%OS%\"==\"Windows_NT\" setlocal\n\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nset DEFAULT_JVM_OPTS=\n\nset DIRNAME=%~dp0\nif \"%DIRNAME%\" == \"\" set DIRNAME=.\nset APP_BASE_NAME=%~n0\nset APP_HOME=%DIRNAME%\n\n@rem Find java.exe\nif defined JAVA_HOME goto findJavaFromJavaHome\n\nset JAVA_EXE=java.exe\n%JAVA_EXE% -version >NUL 2>&1\nif \"%ERRORLEVEL%\" == \"0\" goto init\n\necho.\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:findJavaFromJavaHome\nset JAVA_HOME=%JAVA_HOME:\"=%\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\n\nif exist \"%JAVA_EXE%\" goto init\n\necho.\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%\necho.\necho Please set the JAVA_HOME variable in your environment to match the\necho location of your Java installation.\n\ngoto fail\n\n:init\n@rem Get command-line arguments, handling Windowz variants\n\nif not \"%OS%\" == \"Windows_NT\" goto win9xME_args\nif \"%@eval[2+2]\" == \"4\" goto 4NT_args\n\n:win9xME_args\n@rem Slurp the command line arguments.\nset CMD_LINE_ARGS=\nset _SKIP=2\n\n:win9xME_args_slurp\nif \"x%~1\" == \"x\" goto execute\n\nset CMD_LINE_ARGS=%*\ngoto execute\n\n:4NT_args\n@rem Get arguments from the 4NT Shell from JP Software\nset CMD_LINE_ARGS=%$\n\n:execute\n@rem Setup the command line\n\nset CLASSPATH=%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\n\n@rem Execute Gradle\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%\n\n:end\n@rem End local scope for the variables with windows NT shell\nif \"%ERRORLEVEL%\"==\"0\" goto mainEnd\n\n:fail\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\nrem the _cmd.exe /c_ return code!\nif  not \"\" == \"%GRADLE_EXIT_CONSOLE%\" exit 1\nexit /b 1\n\n:mainEnd\nif \"%OS%\"==\"Windows_NT\" endlocal\n\n:omega\n"
  },
  {
    "path": "jcenter-push.gradle",
    "content": "apply plugin: 'com.jfrog.bintray'\napply plugin: 'com.github.dcendents.android-maven'\n\ndef siteUrl = \"https://github.com/linuxjava/HorizontalRefreshLayout\"\ndef gitUrl = \"https://github.com/linuxjava/HorizontalRefreshLayout.git\"\n\ngroup = 'xiao.free.horizontalrefreshlayout'// library name\nversion = 'v0.1.2'// version\n\ninstall {\n    repositories.mavenInstaller {\n        // This generates POM.xml with proper paramters\n        pom {\n            project {\n                packaging 'aar'\n\n                name 'HorizontalRefreshLayout for Android'//添加项目描述\n                url siteUrl\n\n                licenses {\n                    license {\n                        name 'The Apache Software License, Version 2.0'\n                        url 'http://www.apache.org/licenses/LICENSE-2.0.txt'\n                    }\n                }\n\n                developers {\n                    developer {\n                        id 'guochangxiao'\n                        name 'guochangxiao'\n                        email 'guochangxiao@gmail.com'\n                    }\n                }\n\n                scm {\n                    connection gitUrl\n                    developerConnection gitUrl\n                    url siteUrl\n                }\n            }\n        }\n    }\n}\n\ntask sourcesJar(type: Jar) {\n    from android.sourceSets.main.java.srcDirs\n    classifier = 'sources'\n}\n\ntask javadoc(type: Javadoc) {\n    source = android.sourceSets.main.java.srcDirs\n    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))\n}\n\ntask javadocJar(type: Jar, dependsOn: javadoc) {\n    classifier = 'javadoc'\n    from javadoc.destinationDir\n}\n\nartifacts {\n    archives javadocJar\n    archives sourcesJar\n}\n\nProperties properties = new Properties()\nproperties.load(project.rootProject.file('local.properties').newDataInputStream())\n\nbintray {\n    user = properties.getProperty(\"bintray.user\")\n    key = properties.getProperty(\"bintray.apikey\")\n\n    configurations = ['archives']\n\n    pkg {\n        repo = \"maven\" //JCenter上仓储名\n        name = \"horizontalrefreshlayout\" //JCenter上的项目中的packageName\n        websiteUrl = siteUrl\n        vcsUrl = gitUrl\n        licenses = [\"Apache-2.0\"]\n        publish = true\n    }\n}"
  },
  {
    "path": "lib/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion ANDROID_BUILD_SDK_VERSION as int\n    buildToolsVersion ANDROID_BUILD_TOOLS_VERSION\n    resourcePrefix \"horizontalrefreshlayout_\"\n\n    defaultConfig {\n        minSdkVersion 14\n        targetSdkVersion ANDROID_BUILD_SDK_VERSION\n        versionCode 1\n        versionName \"1.0\"\n\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    compile 'com.android.support:appcompat-v7:23.4.0'\n}\n\n\napply from: '../jcenter-push.gradle'\n\n\n\n"
  },
  {
    "path": "lib/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in C:\\android-sdk/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "lib/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"xiao.free.horizontalrefreshlayout\">\n\n    <application android:allowBackup=\"true\" android:label=\"@string/app_name\"\n        android:supportsRtl=\"true\">\n\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "lib/src/main/java/xiao/free/horizontalrefreshlayout/HorizontalRefreshLayout.java",
    "content": "package xiao.free.horizontalrefreshlayout;\n\nimport android.animation.Animator;\nimport android.animation.AnimatorListenerAdapter;\nimport android.content.Context;\nimport android.support.v4.view.ViewCompat;\nimport android.util.AttributeSet;\nimport android.util.Log;\nimport android.util.TypedValue;\nimport android.view.Gravity;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.ViewConfiguration;\nimport android.widget.FrameLayout;\n\n/**\n * Created by robincxiao on 2017/2/6.\n * 1.View布局问题，onMeasure、onLayout\n * 2.滑动冲突问题\n * 2.1事件拦截\n * 2.2拖动效果\n * 3.释放时自动归位问题\n * 值得注意的问题：\n * 1.onlayout中header初始化\n * 2.onTouchEvent的返回值\n */\n\npublic class HorizontalRefreshLayout extends FrameLayout {\n    private static final int DURATION = 150;\n    private Context context;\n    private RefreshHeader leftRefreshHeader;\n    private RefreshHeader rightRefreshHeader;\n    private View mTargetView;\n    private View leftHeaderView;\n    private View rightHeaderView;\n    private RefreshCallBack refreshCallback;\n    private int touchSlop;\n    private int dragMarginPx;\n    private int leftHeaderWidth;\n    private int rightHeaderWidth;\n    //最大拖动距离\n    private int dragMaxHeaderWidth;\n    private int mLastInterceptX;\n    private int mLastInterceptY;\n    private int mLastX;\n    private int mLastY;\n\n    private float mTargetTranslationX = 0;\n    //header状态，当前显示是左边header、右边header\n    private int headerState = -1;\n    public static final int LEFT = 0;\n    public static final int RIGHT = 1;\n    //刷新状态\n    private static final int REFRESH_STATE_IDLE = 0;\n    private static final int REFRESH_STATE_START = 1;\n    private static final int REFRESH_STATE_DRAGGING = 2;\n    private static final int REFRESH_STATE_READY_TO_RELEASE = 3;\n    private static final int REFRESH_STATE_REFRESHING = 4;\n    private int refreshState = REFRESH_STATE_IDLE;\n\n\n    public HorizontalRefreshLayout(Context context) {\n        super(context);\n\n        init();\n    }\n\n    public HorizontalRefreshLayout(Context context, AttributeSet attrs) {\n        super(context, attrs);\n\n        init();\n    }\n\n    public HorizontalRefreshLayout(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n\n        init();\n    }\n\n    public void setRefreshCallback(RefreshCallBack callback) {\n        refreshCallback = callback;\n    }\n\n    private void init() {\n        context = getContext();\n        touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n\n        if(leftHeaderView != null) {\n            leftHeaderWidth = leftHeaderView.getMeasuredWidth();\n            dragMarginPx = (int) (leftHeaderWidth * 0.6);\n            dragMaxHeaderWidth = leftHeaderWidth + dragMarginPx;\n        }\n\n        if(rightHeaderView != null) {\n            rightHeaderWidth = rightHeaderView.getMeasuredWidth();\n            if(dragMarginPx == 0){\n                dragMarginPx = (int) (rightHeaderWidth * 0.6);\n                dragMaxHeaderWidth = rightHeaderWidth + dragMarginPx;\n            }\n        }\n    }\n\n    @Override\n    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {\n        if (getChildCount() == 0) {\n            return;\n        }\n\n        if (mTargetView == null) {\n            findTargetView();\n            if (mTargetView == null) {\n                return;\n            }\n        }\n\n        /**\n         * 注意：只有状态是IDLE时才初始化刷新header的TranslationX；因为在滑动mTargetView时onLayout会被重新调用，\n         * 如果不是在REFRESH_STATE_IDLE状态下设置setTranslationX，则会产生问题\n         */\n        if (refreshState == REFRESH_STATE_IDLE) {\n            if (leftHeaderView != null) {\n                leftHeaderView.setTranslationX(-leftHeaderWidth);\n            }\n\n            if (rightHeaderView != null) {\n                rightHeaderView.setTranslationX(rightHeaderWidth);\n            }\n        }\n\n        super.onLayout(changed, left, top, right, bottom);\n    }\n\n    private void findTargetView() {\n        if (mTargetView == null) {\n            for (int i = 0; i < getChildCount(); i++) {\n                View child = getChildAt(i);\n                if (!child.equals(leftHeaderView) && !child.equals(rightHeaderView)) {\n                    mTargetView = child;\n                    break;\n                }\n            }\n        }\n    }\n\n    @Override\n    public boolean onInterceptTouchEvent(MotionEvent ev) {\n        int x = (int) ev.getX();\n        int y = (int) ev.getY();\n\n        switch (ev.getAction()) {\n            case MotionEvent.ACTION_DOWN:\n                mLastX = mLastInterceptX = x;\n                mLastY = mLastInterceptY = y;\n                break;\n            case MotionEvent.ACTION_MOVE:\n                int deltaX = x - mLastInterceptX;\n                int deltaY = y - mLastInterceptY;\n\n                mLastX = mLastInterceptX = x;\n                mLastY = mLastInterceptY = y;\n\n                /**\n                 * 注意：需要判断refreshState != REFRESH_STATE_REFRESHING，否则当处于REFRESH_STATE_REFRESHING状态\n                 * 再次拖动滑动时，会有些许小瑕疵\n                 */\n                if (Math.abs(deltaX) > Math.abs(deltaY)) {//判断是否是水平滑动\n                    if (leftHeaderView != null && deltaX > 0 && !canChildScrollRight() && refreshState != REFRESH_STATE_REFRESHING) {//手指向右滑动\n                        headerState = LEFT;\n                        refreshState = REFRESH_STATE_START;\n                        leftRefreshHeader.onStart(LEFT, leftHeaderView);\n\n                        return true;\n                    } else if (rightHeaderView != null && deltaX < 0 && !canChildScrollLeft() && refreshState != REFRESH_STATE_REFRESHING) {//手指向左滑动\n                        headerState = RIGHT;\n                        refreshState = REFRESH_STATE_START;\n                        rightRefreshHeader.onStart(RIGHT, rightHeaderView);\n\n                        return true;\n                    }\n                }\n                break;\n            case MotionEvent.ACTION_UP:\n            case MotionEvent.ACTION_CANCEL:\n                mLastInterceptX = 0;\n                mLastInterceptY = 0;\n                break;\n        }\n\n        return super.onInterceptTouchEvent(ev);\n    }\n\n    @Override\n    public boolean onTouchEvent(MotionEvent event) {\n        int x = (int) event.getX();\n        int y = (int) event.getY();\n\n        /**\n         * 为什么不在onTouchEvent中直接返回true，而是在ACTION_MOVE/ACTION_UP/ACTION_CANCEL返回true，ACTION_DOWN不返回true?\n         * 在如下场景下需要这样设计：header正在刷新的时候，用户点击在header上开始drag，但是当header正在刷新的时候，我们并不希望\n         * headerview和mTargetView被拖动，因此需要这样去处理。\n         */\n        switch (event.getAction()) {\n            case MotionEvent.ACTION_DOWN:\n                mLastX = x;\n                mLastY = y;\n                break;\n            case MotionEvent.ACTION_MOVE:\n                int deltaX = x - mLastX;\n\n                mLastX = x;\n                mLastY = y;\n\n                float dampingDX = deltaX * (1 - Math.abs((mTargetTranslationX / dragMaxHeaderWidth)));  //let drag action has resistance\n                mTargetTranslationX += dampingDX;\n\n                if (headerState == LEFT) {\n                    if (mTargetTranslationX <= 0) {\n                        Log.d(\"xiao1\", \"test1\");\n                        mTargetTranslationX = 0;\n                        mTargetView.setTranslationX(0);\n                    } else if (mTargetTranslationX >= dragMaxHeaderWidth) {\n                        Log.d(\"xiao1\", \"test2\");\n                        mTargetTranslationX = dragMaxHeaderWidth;\n                        mTargetView.setTranslationX(mTargetTranslationX);\n                    } else {\n                        Log.d(\"xiao1\", \"test3\");\n\n                        mTargetView.setTranslationX(mTargetTranslationX);\n\n                        if (refreshState != REFRESH_STATE_READY_TO_RELEASE && mTargetTranslationX >= leftHeaderWidth) {\n                            refreshState = REFRESH_STATE_READY_TO_RELEASE;\n\n                            leftRefreshHeader.onReadyToRelease(leftHeaderView);\n                        } else {\n                            refreshState = REFRESH_STATE_DRAGGING;\n                            //计算出拖动的比率\n                            float percent = Math.abs(mTargetTranslationX / leftHeaderWidth);\n                            leftRefreshHeader.onDragging(mTargetTranslationX, percent, leftHeaderView);\n                        }\n                    }\n\n                    leftHeaderView.setTranslationX(-leftHeaderWidth + mTargetTranslationX);\n                } else if ((headerState == RIGHT)) {\n                    if (mTargetTranslationX >= 0) {\n                        Log.d(\"xiao1\", \"test4\");\n                        mTargetTranslationX = 0;\n                        mTargetView.setTranslationX(0);\n                    } else if (mTargetTranslationX <= -dragMaxHeaderWidth) {\n                        Log.d(\"xiao1\", \"test5\");\n                        mTargetTranslationX = -dragMaxHeaderWidth;\n                        mTargetView.setTranslationX(mTargetTranslationX);\n                    } else {\n                        Log.d(\"xiao1\", \"test6\");\n                        mTargetView.setTranslationX(mTargetTranslationX);\n\n                        if (refreshState != REFRESH_STATE_READY_TO_RELEASE && mTargetTranslationX <= -rightHeaderWidth) {\n                            refreshState = REFRESH_STATE_READY_TO_RELEASE;\n                            rightRefreshHeader.onReadyToRelease(rightHeaderView);\n                        } else {\n                            refreshState = REFRESH_STATE_DRAGGING;\n                            //计算出拖动的比率\n                            float percent = Math.abs(mTargetTranslationX / rightHeaderWidth);\n                            rightRefreshHeader.onDragging(mTargetTranslationX, percent, rightHeaderView);\n                        }\n                    }\n\n                    rightHeaderView.setTranslationX(rightHeaderWidth + mTargetTranslationX);\n                }\n                return true;\n            case MotionEvent.ACTION_UP:\n            case MotionEvent.ACTION_CANCEL:\n                mLastX = mLastInterceptX = 0;\n                mLastY = mLastInterceptY = 0;\n\n                if (headerState == LEFT) {\n                    if (mTargetTranslationX < leftHeaderWidth) {\n                        Log.d(\"xiao1\", \"test7\");\n                        smoothRelease();\n                    } else {\n                        Log.d(\"xiao1\", \"test8\");\n                        smoothLocateToRefresh();\n                    }\n                } else if (headerState == RIGHT) {\n                    if (mTargetTranslationX > -rightHeaderWidth) {\n                        Log.d(\"xiao1\", \"test9\");\n                        smoothRelease();\n                    } else {\n                        Log.d(\"xiao1\", \"test10\");\n                        smoothLocateToRefresh();\n                    }\n                }\n                return true;\n        }\n\n        return super.onTouchEvent(event);\n    }\n\n    /**\n     * 释放滑动\n     */\n    private void smoothRelease() {\n        mTargetView.animate().translationX(0).setDuration(DURATION)\n                .setListener(new AnimatorListenerAdapter() {\n                    @Override\n                    public void onAnimationEnd(Animator animation) {\n                        //动画结束后reset状态\n                        refreshState = REFRESH_STATE_IDLE;\n                        headerState = -1;\n                        mTargetTranslationX = 0;\n                    }\n                })\n                .start();\n\n        if (headerState == LEFT) {\n            if (leftHeaderView != null) {\n                leftRefreshHeader.onStart(LEFT, leftHeaderView);//恢复到开始状态\n                leftHeaderView.animate().translationX(-leftHeaderWidth).setDuration(DURATION).start();\n            }\n        } else if (headerState == RIGHT) {\n            if (rightHeaderView != null) {\n                rightRefreshHeader.onStart(LEFT, rightHeaderView);//恢复到开始状态\n                rightHeaderView.animate().translationX(rightHeaderWidth).setDuration(DURATION).start();\n            }\n        }\n    }\n\n    /**\n     * 滑动到刷新位置\n     */\n    private void smoothLocateToRefresh() {\n        if (headerState == LEFT && leftHeaderView != null) {\n            refreshState = REFRESH_STATE_REFRESHING;\n\n            leftHeaderView.animate().translationX(0).setDuration(DURATION).start();\n\n            leftRefreshHeader.onRefreshing(leftHeaderView);//正在刷新\n\n            mTargetView.animate().translationX(leftHeaderWidth).setDuration(DURATION)\n                    .setListener(new AnimatorListenerAdapter() {\n                        @Override\n                        public void onAnimationEnd(Animator animation) {\n                            mTargetTranslationX = leftHeaderWidth;\n\n                            if (refreshCallback != null) {\n                                if (headerState == LEFT) {\n                                    refreshCallback.onLeftRefreshing();\n                                } else {\n                                    refreshCallback.onRightRefreshing();\n                                }\n                            }\n                        }\n                    })\n                    .start();\n        } else if (headerState == RIGHT && rightHeaderView != null) {\n            refreshState = REFRESH_STATE_REFRESHING;\n            //注意，这里使用的translationXBy\n            rightHeaderView.animate().translationXBy(-mTargetTranslationX - rightHeaderWidth).setDuration(DURATION).start();\n\n            rightRefreshHeader.onRefreshing(rightHeaderView);//正在刷新\n\n            mTargetView.animate().translationX(-rightHeaderWidth).setDuration(DURATION)\n                    .setListener(new AnimatorListenerAdapter() {\n                        @Override\n                        public void onAnimationEnd(Animator animation) {\n                            if (refreshCallback != null) {\n                                if (headerState == LEFT) {\n                                    refreshCallback.onLeftRefreshing();\n                                } else {\n                                    refreshCallback.onRightRefreshing();\n                                }\n                            }\n\n                            mTargetTranslationX = -rightHeaderWidth;\n                        }\n                    })\n                    .start();\n        }\n    }\n\n    /**\n     * 刷新完成\n     */\n    public void onRefreshComplete() {\n        smoothRelease();\n    }\n\n    /**\n     * 自动刷新\n     *\n     * @param leftOrRight HorizontalRefreshLayout.LEFT or HorizontalRefreshLayout.RIGHT\n     */\n    public void startAutoRefresh(final int leftOrRight) {\n        // delay to let the animation smoothly\n        //此处需要采用postDelayed将消息方式view的消息队列中，如果直接调用smoothLocateToRefresh可能view还没能完全初始化好，导致mTarget为null\n        postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                headerState = leftOrRight;\n                smoothLocateToRefresh();\n            }\n        }, 100);\n    }\n\n    private void setLeftHeadView(View view) {\n        leftHeaderView = view;\n        ((LayoutParams) leftHeaderView.getLayoutParams()).gravity = Gravity.START;\n        addView(leftHeaderView, 0);\n    }\n\n    private void setRightHeadView(View view) {\n        rightHeaderView = view;\n        ((LayoutParams) rightHeaderView.getLayoutParams()).gravity = Gravity.END;\n        addView(rightHeaderView, 0);\n    }\n\n    /**\n     * 设置刷新header\n     * @param header\n     * @param startOrEnd\n     */\n    public void setRefreshHeader(RefreshHeader header, int startOrEnd) {\n        if (startOrEnd == LEFT) {\n            leftRefreshHeader = header;\n            setLeftHeadView(leftRefreshHeader.getView(this));\n        } else if (startOrEnd == RIGHT) {\n            rightRefreshHeader = header;\n            setRightHeadView(rightRefreshHeader.getView(this));\n        }\n    }\n\n    /**\n     * mTargetView是否还能向右滑动\n     *\n     * @return\n     */\n    public boolean canChildScrollRight() {\n        return ViewCompat.canScrollHorizontally(mTargetView, -1);\n    }\n\n    /**\n     * mTargetView是否还能向左滑动\n     *\n     * @return\n     */\n    public boolean canChildScrollLeft() {\n        return ViewCompat.canScrollHorizontally(mTargetView, 1);\n    }\n\n\n    public static int dp2px(Context context, float dpVal) {\n        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpVal, context.getResources().getDisplayMetrics());\n    }\n}\n"
  },
  {
    "path": "lib/src/main/java/xiao/free/horizontalrefreshlayout/RefreshCallBack.java",
    "content": "package xiao.free.horizontalrefreshlayout;\n\n/**\n * Created by wangqi on 2015/12/24.\n */\npublic interface RefreshCallBack {\n    void onLeftRefreshing();\n    void onRightRefreshing();\n}\n"
  },
  {
    "path": "lib/src/main/java/xiao/free/horizontalrefreshlayout/RefreshHeader.java",
    "content": "package xiao.free.horizontalrefreshlayout;\n\nimport android.support.annotation.NonNull;\nimport android.view.View;\nimport android.view.ViewGroup;\n\n/**\n * Created by wangqi on 2015/12/24.\n */\npublic interface RefreshHeader {\n\n    /**\n     * @param dragPosition  HorizontalRefreshLayout.START or HorizontalRefreshLayout.END\n     */\n    void onStart(int dragPosition, View refreshHead);\n\n    /**\n     * @param distance\n     */\n    void onDragging(float distance, float percent, View refreshHead);\n\n    void onReadyToRelease(View refreshHead);\n\n    @NonNull View getView(ViewGroup container);\n\n    void onRefreshing(View refreshHead);\n}\n"
  },
  {
    "path": "lib/src/main/java/xiao/free/horizontalrefreshlayout/refreshhead/LoadingRefreshHeader.java",
    "content": "package xiao.free.horizontalrefreshlayout.refreshhead;\n\nimport android.content.Context;\nimport android.support.annotation.NonNull;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.ProgressBar;\n\nimport xiao.free.horizontalrefreshlayout.R;\nimport xiao.free.horizontalrefreshlayout.RefreshHeader;\n\n/**\n * Created by xiaoguochang on 2015/12/24.\n */\npublic class LoadingRefreshHeader implements RefreshHeader {\n    private final Context context;\n    private ProgressBar progressBar;\n    private ImageView staticLoading;\n\n    public LoadingRefreshHeader(Context context) {\n        this.context = context;\n    }\n\n    @NonNull\n    @Override\n    public View getView(ViewGroup container) {\n        View view = LayoutInflater.from(context).inflate(R.layout.common_loading_refresh_header, container, false);\n        progressBar = (ProgressBar) view.findViewById(R.id.progressbar);\n        staticLoading = (ImageView) view.findViewById(R.id.static_loading);\n        progressBar.setVisibility(View.INVISIBLE);\n\n        return view;\n    }\n\n    @Override\n    public void onStart(int dragPosition, View refreshHead) {\n        staticLoading.setVisibility(View.VISIBLE);\n        progressBar.setVisibility(View.INVISIBLE);\n    }\n\n    @Override\n    public void onDragging(float distance, float percent, View refreshHead) {\n        staticLoading.setRotation(percent * 360);\n    }\n\n    @Override\n    public void onReadyToRelease(View refreshHead) {\n\n    }\n\n    @Override\n    public void onRefreshing(View refreshHead) {\n        staticLoading.setVisibility(View.INVISIBLE);\n        progressBar.setVisibility(View.VISIBLE);\n    }\n}\n"
  },
  {
    "path": "lib/src/main/java/xiao/free/horizontalrefreshlayout/refreshhead/MaterialRefreshHeader.java",
    "content": "package xiao.free.horizontalrefreshlayout.refreshhead;\n\nimport android.support.annotation.NonNull;\nimport android.view.Gravity;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.FrameLayout;\n\nimport xiao.free.horizontalrefreshlayout.HorizontalRefreshLayout;\nimport xiao.free.horizontalrefreshlayout.R;\nimport xiao.free.horizontalrefreshlayout.RefreshHeader;\nimport xiao.free.horizontalrefreshlayout.widget.CircleImageView;\nimport xiao.free.horizontalrefreshlayout.widget.MaterialProgressDrawable;\n\n\n/**\n * Created by wangqi on 2016/7/21.\n */\npublic class MaterialRefreshHeader implements RefreshHeader {\n\n    private final int startOrEnd;\n    private CircleImageView mCircleView;\n    private MaterialProgressDrawable mProgress;\n    private ViewGroup parent;\n\n    public MaterialRefreshHeader(int startOrEnd) {\n        this.startOrEnd = startOrEnd;\n    }\n\n    @Override\n    public void onStart(int dragPosition, View refreshHead) {\n        mProgress.stop();\n        mProgress.showArrow(false);\n        mProgress.setAlpha(0);\n        mProgress.setStartEndTrim(0f, 0f);\n    }\n\n    @Override\n    public void onDragging(float distance, float percent, View refreshHead) {\n        mProgress.showArrow(true);\n        mProgress.setAlpha((int) (percent * 255));\n        mProgress.setProgressRotation(percent);\n        mProgress.setStartEndTrim(0f, Math.min(.8f, percent));\n    }\n\n    @Override\n    public void onReadyToRelease(View refreshHead) {\n    }\n\n    @NonNull\n    @Override\n    public View getView(ViewGroup container) {\n        this.parent = container;\n        ViewGroup view = (ViewGroup) LayoutInflater.from(container.getContext()).inflate(R.layout.material_refresh_header, container, false);\n        mCircleView = new CircleImageView(container.getContext(), 0xFFFAFAFA, 40 / 2);\n        mProgress = new MaterialProgressDrawable(container.getContext(), container);\n        mProgress.setBackgroundColor(0xFFFAFAFA);\n        mCircleView.setImageDrawable(mProgress);\n        FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);\n        if (startOrEnd == HorizontalRefreshLayout.LEFT) {\n            layoutParams.gravity = Gravity.CENTER;\n        } else {\n            layoutParams.gravity = Gravity.CENTER;\n        }\n        mCircleView.setLayoutParams(layoutParams);\n        view.addView(mCircleView);\n        return view;\n    }\n\n    @Override\n    public void onRefreshing(View refreshHead) {\n        mProgress.showArrow(true);\n        mProgress.setAlpha(255);\n        mProgress.setProgressRotation(1);\n        mProgress.setStartEndTrim(0f, Math.min(.8f, 1));\n        mProgress.start();\n    }\n}\n"
  },
  {
    "path": "lib/src/main/java/xiao/free/horizontalrefreshlayout/refreshhead/NiceRefreshHeader.java",
    "content": "package xiao.free.horizontalrefreshlayout.refreshhead;\n\nimport android.content.Context;\nimport android.support.annotation.NonNull;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.ProgressBar;\n\nimport xiao.free.horizontalrefreshlayout.R;\nimport xiao.free.horizontalrefreshlayout.RefreshHeader;\n\n/**\n * Created by xiaoguochang on 2015/12/24.\n */\npublic class NiceRefreshHeader implements RefreshHeader {\n    private final Context context;\n    private ProgressBar progressBar;\n    private ImageView staticLoading;\n\n    public NiceRefreshHeader(Context context) {\n        this.context = context;\n    }\n\n    @NonNull\n    @Override\n    public View getView(ViewGroup container) {\n        View view = LayoutInflater.from(context).inflate(R.layout.nice_refresh_header, container, false);\n        progressBar = (ProgressBar) view.findViewById(R.id.progressbar);\n        staticLoading = (ImageView) view.findViewById(R.id.static_loading);\n        progressBar.setVisibility(View.INVISIBLE);\n\n        return view;\n    }\n\n    @Override\n    public void onStart(int dragPosition, View refreshHead) {\n        staticLoading.setVisibility(View.VISIBLE);\n        progressBar.setVisibility(View.INVISIBLE);\n    }\n\n    @Override\n    public void onDragging(float distance, float percent, View refreshHead) {\n        int num = (int) (percent * 10);\n\n        switch (num){\n            case 1:\n            case 4:\n            case 7:\n                staticLoading.setBackgroundResource(R.drawable.ic_loading_1);\n                break;\n            case 2:\n            case 5:\n            case 8:\n                staticLoading.setBackgroundResource(R.drawable.ic_loading_2);\n                break;\n            case 3:\n            case 6:\n            case 9:\n                staticLoading.setBackgroundResource(R.drawable.ic_loading_3);\n                break;\n        }\n    }\n\n    @Override\n    public void onReadyToRelease(View refreshHead) {\n\n    }\n\n    @Override\n    public void onRefreshing(View refreshHead) {\n        staticLoading.setVisibility(View.INVISIBLE);\n        progressBar.setVisibility(View.VISIBLE);\n    }\n}\n"
  },
  {
    "path": "lib/src/main/java/xiao/free/horizontalrefreshlayout/widget/CircleImageView.java",
    "content": "/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage xiao.free.horizontalrefreshlayout.widget;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.RadialGradient;\nimport android.graphics.Shader;\nimport android.graphics.drawable.ShapeDrawable;\nimport android.graphics.drawable.shapes.OvalShape;\nimport android.support.v4.view.ViewCompat;\nimport android.view.animation.Animation;\nimport android.widget.ImageView;\n\n/**\n * Private class created to work around issues with AnimationListeners being\n * called before the animation is actually complete and support shadows on older\n * platforms.\n */\npublic class CircleImageView extends ImageView {\n\n    private static final int KEY_SHADOW_COLOR = 0x1E000000;\n    private static final int FILL_SHADOW_COLOR = 0x3D000000;\n    // PX\n    private static final float X_OFFSET = 0f;\n    private static final float Y_OFFSET = 1.75f;\n    private static final float SHADOW_RADIUS = 3.5f;\n    private static final int SHADOW_ELEVATION = 4;\n\n    private Animation.AnimationListener mListener;\n    private int mShadowRadius;\n\n    public CircleImageView(Context context, int color, final float radius) {\n        super(context);\n        final float density = getContext().getResources().getDisplayMetrics().density;\n        final int diameter = (int) (radius * density * 2);\n        final int shadowYOffset = (int) (density * Y_OFFSET);\n        final int shadowXOffset = (int) (density * X_OFFSET);\n\n        mShadowRadius = (int) (density * SHADOW_RADIUS);\n\n        ShapeDrawable circle;\n        if (elevationSupported()) {\n            circle = new ShapeDrawable(new OvalShape());\n            ViewCompat.setElevation(this, SHADOW_ELEVATION * density);\n        } else {\n            OvalShape oval = new OvalShadow(mShadowRadius, diameter);\n            circle = new ShapeDrawable(oval);\n            ViewCompat.setLayerType(this, ViewCompat.LAYER_TYPE_SOFTWARE, circle.getPaint());\n            circle.getPaint().setShadowLayer(mShadowRadius, shadowXOffset, shadowYOffset,\n                    KEY_SHADOW_COLOR);\n            final int padding = mShadowRadius;\n            // set padding so the inner image sits correctly within the shadow.\n            setPadding(padding, padding, padding, padding);\n        }\n        circle.getPaint().setColor(color);\n        setBackgroundDrawable(circle);\n    }\n\n    private boolean elevationSupported() {\n        return android.os.Build.VERSION.SDK_INT >= 21;\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n        if (!elevationSupported()) {\n            setMeasuredDimension(getMeasuredWidth() + mShadowRadius*2, getMeasuredHeight()\n                    + mShadowRadius*2);\n        }\n    }\n\n    public void setAnimationListener(Animation.AnimationListener listener) {\n        mListener = listener;\n    }\n\n    @Override\n    public void onAnimationStart() {\n        super.onAnimationStart();\n        if (mListener != null) {\n            mListener.onAnimationStart(getAnimation());\n        }\n    }\n\n    @Override\n    public void onAnimationEnd() {\n        super.onAnimationEnd();\n        if (mListener != null) {\n            mListener.onAnimationEnd(getAnimation());\n        }\n    }\n\n    /**\n     * Update the background color of the circle image view.\n     *\n     * @param colorRes Id of a color resource.\n     */\n    public void setBackgroundColorRes(int colorRes) {\n        setBackgroundColor(getContext().getResources().getColor(colorRes));\n    }\n\n    @Override\n    public void setBackgroundColor(int color) {\n        if (getBackground() instanceof ShapeDrawable) {\n            ((ShapeDrawable) getBackground()).getPaint().setColor(color);\n        }\n    }\n\n    private class OvalShadow extends OvalShape {\n        private RadialGradient mRadialGradient;\n        private Paint mShadowPaint;\n        private int mCircleDiameter;\n\n        public OvalShadow(int shadowRadius, int circleDiameter) {\n            super();\n            mShadowPaint = new Paint();\n            mShadowRadius = shadowRadius;\n            mCircleDiameter = circleDiameter;\n            mRadialGradient = new RadialGradient(mCircleDiameter / 2, mCircleDiameter / 2,\n                    mShadowRadius, new int[] {\n                            FILL_SHADOW_COLOR, Color.TRANSPARENT\n                    }, null, Shader.TileMode.CLAMP);\n            mShadowPaint.setShader(mRadialGradient);\n        }\n\n        @Override\n        public void draw(Canvas canvas, Paint paint) {\n            final int viewWidth = CircleImageView.this.getWidth();\n            final int viewHeight = CircleImageView.this.getHeight();\n            canvas.drawCircle(viewWidth / 2, viewHeight / 2, (mCircleDiameter / 2 + mShadowRadius),\n                    mShadowPaint);\n            canvas.drawCircle(viewWidth / 2, viewHeight / 2, (mCircleDiameter / 2), paint);\n        }\n    }\n}\n"
  },
  {
    "path": "lib/src/main/java/xiao/free/horizontalrefreshlayout/widget/MaterialProgressDrawable.java",
    "content": "/*\n * Copyright (C) 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *      http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage xiao.free.horizontalrefreshlayout.widget;\n\nimport android.content.Context;\nimport android.content.res.Resources;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.ColorFilter;\nimport android.graphics.Paint;\nimport android.graphics.Paint.Style;\nimport android.graphics.Path;\nimport android.graphics.PixelFormat;\nimport android.graphics.Rect;\nimport android.graphics.RectF;\nimport android.graphics.drawable.Animatable;\nimport android.graphics.drawable.Drawable;\nimport android.support.annotation.IntDef;\nimport android.support.annotation.NonNull;\nimport android.support.v4.view.animation.FastOutSlowInInterpolator;\nimport android.util.DisplayMetrics;\nimport android.view.View;\nimport android.view.animation.Animation;\nimport android.view.animation.Interpolator;\nimport android.view.animation.LinearInterpolator;\nimport android.view.animation.Transformation;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.ArrayList;\n\n/**\n * Fancy progress indicator for Material theme.\n */\npublic class MaterialProgressDrawable extends Drawable implements Animatable {\n    private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();\n    private static final Interpolator MATERIAL_INTERPOLATOR = new FastOutSlowInInterpolator();\n\n    private static final float FULL_ROTATION = 1080.0f;\n    @Retention(RetentionPolicy.CLASS)\n    @IntDef({LARGE, DEFAULT})\n    public @interface ProgressDrawableSize {}\n    // Maps to ProgressBar.Large style\n    static final int LARGE = 0;\n    // Maps to ProgressBar default style\n    static final int DEFAULT = 1;\n\n    // Maps to ProgressBar default style\n    private static final int CIRCLE_DIAMETER = 40;\n    private static final float CENTER_RADIUS = 8.75f; //should add up to 10 when + stroke_width\n    private static final float STROKE_WIDTH = 2.5f;\n\n    // Maps to ProgressBar.Large style\n    private static final int CIRCLE_DIAMETER_LARGE = 56;\n    private static final float CENTER_RADIUS_LARGE = 12.5f;\n    private static final float STROKE_WIDTH_LARGE = 3f;\n\n    private final int[] COLORS = new int[] {\n        Color.BLACK\n    };\n\n    /**\n     * The value in the linear interpolator for animating the drawable at which\n     * the color transition should start\n     */\n    private static final float COLOR_START_DELAY_OFFSET = 0.75f;\n    private static final float END_TRIM_START_DELAY_OFFSET = 0.5f;\n    private static final float START_TRIM_DURATION_OFFSET = 0.5f;\n\n    /** The duration of a single progress spin in milliseconds. */\n    private static final int ANIMATION_DURATION = 1332;\n\n    /** The number of points in the progress \"star\". */\n    private static final float NUM_POINTS = 5f;\n    /** The list of animators operating on this drawable. */\n    private final ArrayList<Animation> mAnimators = new ArrayList<Animation>();\n\n    /** The indicator ring, used to manage animation state. */\n    private final Ring mRing;\n\n    /** Canvas rotation in degrees. */\n    private float mRotation;\n\n    /** Layout info for the arrowhead in dp */\n    private static final int ARROW_WIDTH = 10;\n    private static final int ARROW_HEIGHT = 5;\n    private static final float ARROW_OFFSET_ANGLE = 5;\n\n    /** Layout info for the arrowhead for the large spinner in dp */\n    private static final int ARROW_WIDTH_LARGE = 12;\n    private static final int ARROW_HEIGHT_LARGE = 6;\n    private static final float MAX_PROGRESS_ARC = .8f;\n\n    private Resources mResources;\n    private View mParent;\n    private Animation mAnimation;\n    private float mRotationCount;\n    private double mWidth;\n    private double mHeight;\n    boolean mFinishing;\n\n    public MaterialProgressDrawable(Context context, View parent) {\n        mParent = parent;\n        mResources = context.getResources();\n\n        mRing = new Ring(mCallback);\n        mRing.setColors(COLORS);\n\n        updateSizes(DEFAULT);\n        setupAnimators();\n    }\n\n    private void setSizeParameters(double progressCircleWidth, double progressCircleHeight,\n            double centerRadius, double strokeWidth, float arrowWidth, float arrowHeight) {\n        final Ring ring = mRing;\n        final DisplayMetrics metrics = mResources.getDisplayMetrics();\n        final float screenDensity = metrics.density;\n\n        mWidth = progressCircleWidth * screenDensity;\n        mHeight = progressCircleHeight * screenDensity;\n        ring.setStrokeWidth((float) strokeWidth * screenDensity);\n        ring.setCenterRadius(centerRadius * screenDensity);\n        ring.setColorIndex(0);\n        ring.setArrowDimensions(arrowWidth * screenDensity, arrowHeight * screenDensity);\n        ring.setInsets((int) mWidth, (int) mHeight);\n    }\n\n    /**\n     * Set the overall size for the progress spinner. This updates the radius\n     * and stroke width of the ring.\n     *\n     * @param size One of {@link MaterialProgressDrawable.LARGE} or\n     *            {@link MaterialProgressDrawable.DEFAULT}\n     */\n    public void updateSizes(@ProgressDrawableSize int size) {\n        if (size == LARGE) {\n            setSizeParameters(CIRCLE_DIAMETER_LARGE, CIRCLE_DIAMETER_LARGE, CENTER_RADIUS_LARGE,\n                    STROKE_WIDTH_LARGE, ARROW_WIDTH_LARGE, ARROW_HEIGHT_LARGE);\n        } else {\n            setSizeParameters(CIRCLE_DIAMETER, CIRCLE_DIAMETER, CENTER_RADIUS, STROKE_WIDTH,\n                    ARROW_WIDTH, ARROW_HEIGHT);\n        }\n    }\n\n    /**\n     * @param show Set to true to display the arrowhead on the progress spinner.\n     */\n    public void showArrow(boolean show) {\n        mRing.setShowArrow(show);\n    }\n\n    /**\n     * @param scale Set the scale of the arrowhead for the spinner.\n     */\n    public void setArrowScale(float scale) {\n        mRing.setArrowScale(scale);\n    }\n\n    /**\n     * Set the start and end trim for the progress spinner arc.\n     *\n     * @param startAngle start angle\n     * @param endAngle end angle\n     */\n    public void setStartEndTrim(float startAngle, float endAngle) {\n        mRing.setStartTrim(startAngle);\n        mRing.setEndTrim(endAngle);\n    }\n\n    /**\n     * Set the amount of rotation to apply to the progress spinner.\n     *\n     * @param rotation Rotation is from [0..1]\n     */\n    public void setProgressRotation(float rotation) {\n        mRing.setRotation(rotation);\n    }\n\n    /**\n     * Update the background color of the circle image view.\n     */\n    public void setBackgroundColor(int color) {\n        mRing.setBackgroundColor(color);\n     }\n\n    /**\n     * Set the colors used in the progress animation from color resources.\n     * The first color will also be the color of the bar that grows in response\n     * to a user swipe gesture.\n     *\n     * @param colors\n     */\n    public void setColorSchemeColors(int... colors) {\n        mRing.setColors(colors);\n        mRing.setColorIndex(0);\n    }\n\n    @Override\n    public int getIntrinsicHeight() {\n        return (int) mHeight;\n    }\n\n    @Override\n    public int getIntrinsicWidth() {\n        return (int) mWidth;\n    }\n\n    @Override\n    public void draw(Canvas c) {\n        final Rect bounds = getBounds();\n        final int saveCount = c.save();\n        c.rotate(mRotation, bounds.exactCenterX(), bounds.exactCenterY());\n        mRing.draw(c, bounds);\n        c.restoreToCount(saveCount);\n    }\n\n    @Override\n    public void setAlpha(int alpha) {\n        mRing.setAlpha(alpha);\n    }\n\n    public int getAlpha() {\n        return mRing.getAlpha();\n    }\n\n    @Override\n    public void setColorFilter(ColorFilter colorFilter) {\n        mRing.setColorFilter(colorFilter);\n    }\n\n    @SuppressWarnings(\"unused\")\n    void setRotation(float rotation) {\n        mRotation = rotation;\n        invalidateSelf();\n    }\n\n    @SuppressWarnings(\"unused\")\n    private float getRotation() {\n        return mRotation;\n    }\n\n    @Override\n    public int getOpacity() {\n        return PixelFormat.TRANSLUCENT;\n    }\n\n    @Override\n    public boolean isRunning() {\n        final ArrayList<Animation> animators = mAnimators;\n        final int N = animators.size();\n        for (int i = 0; i < N; i++) {\n            final Animation animator = animators.get(i);\n            if (animator.hasStarted() && !animator.hasEnded()) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public void start() {\n        mAnimation.reset();\n        mRing.storeOriginals();\n        // Already showing some part of the ring\n        if (mRing.getEndTrim() != mRing.getStartTrim()) {\n            mFinishing = true;\n            mAnimation.setDuration(ANIMATION_DURATION/2);\n            mParent.startAnimation(mAnimation);\n        } else {\n            mRing.setColorIndex(0);\n            mRing.resetOriginals();\n            mAnimation.setDuration(ANIMATION_DURATION);\n            mParent.startAnimation(mAnimation);\n        }\n    }\n\n    @Override\n    public void stop() {\n        mParent.clearAnimation();\n        setRotation(0);\n        mRing.setShowArrow(false);\n        mRing.setColorIndex(0);\n        mRing.resetOriginals();\n    }\n\n    private float getMinProgressArc(Ring ring) {\n        return (float) Math.toRadians(\n                ring.getStrokeWidth() / (2 * Math.PI * ring.getCenterRadius()));\n    }\n\n    // Adapted from ArgbEvaluator.java\n    private int evaluateColorChange(float fraction, int startValue, int endValue) {\n        int startInt = (Integer) startValue;\n        int startA = (startInt >> 24) & 0xff;\n        int startR = (startInt >> 16) & 0xff;\n        int startG = (startInt >> 8) & 0xff;\n        int startB = startInt & 0xff;\n\n        int endInt = (Integer) endValue;\n        int endA = (endInt >> 24) & 0xff;\n        int endR = (endInt >> 16) & 0xff;\n        int endG = (endInt >> 8) & 0xff;\n        int endB = endInt & 0xff;\n\n        return (int)((startA + (int)(fraction * (endA - startA))) << 24) |\n                (int)((startR + (int)(fraction * (endR - startR))) << 16) |\n                (int)((startG + (int)(fraction * (endG - startG))) << 8) |\n                (int)((startB + (int)(fraction * (endB - startB))));\n    }\n\n    /**\n     * Update the ring color if this is within the last 25% of the animation.\n     * The new ring color will be a translation from the starting ring color to\n     * the next color.\n     */\n    private void updateRingColor(float interpolatedTime, Ring ring) {\n        if (interpolatedTime > COLOR_START_DELAY_OFFSET) {\n            // scale the interpolatedTime so that the full\n            // transformation from 0 - 1 takes place in the\n            // remaining time\n            ring.setColor(evaluateColorChange((interpolatedTime - COLOR_START_DELAY_OFFSET)\n                    / (1.0f - COLOR_START_DELAY_OFFSET), ring.getStartingColor(),\n                    ring.getNextColor()));\n        }\n    }\n\n    private void applyFinishTranslation(float interpolatedTime, Ring ring) {\n        // shrink back down and complete a full rotation before\n        // starting other circles\n        // Rotation goes between [0..1].\n        updateRingColor(interpolatedTime, ring);\n        float targetRotation = (float) (Math.floor(ring.getStartingRotation() / MAX_PROGRESS_ARC)\n                + 1f);\n        final float minProgressArc = getMinProgressArc(ring);\n        final float startTrim = ring.getStartingStartTrim()\n                + (ring.getStartingEndTrim() - minProgressArc - ring.getStartingStartTrim())\n                * interpolatedTime;\n        ring.setStartTrim(startTrim);\n        ring.setEndTrim(ring.getStartingEndTrim());\n        final float rotation = ring.getStartingRotation()\n                + ((targetRotation - ring.getStartingRotation()) * interpolatedTime);\n        ring.setRotation(rotation);\n    }\n\n    private void setupAnimators() {\n        final Ring ring = mRing;\n        final Animation animation = new Animation() {\n                @Override\n            public void applyTransformation(float interpolatedTime, Transformation t) {\n                if (mFinishing) {\n                    applyFinishTranslation(interpolatedTime, ring);\n                } else {\n                    // The minProgressArc is calculated from 0 to create an\n                    // angle that matches the stroke width.\n                    final float minProgressArc = getMinProgressArc(ring);\n                    final float startingEndTrim = ring.getStartingEndTrim();\n                    final float startingTrim = ring.getStartingStartTrim();\n                    final float startingRotation = ring.getStartingRotation();\n\n                    updateRingColor(interpolatedTime, ring);\n\n                    // Moving the start trim only occurs in the first 50% of a\n                    // single ring animation\n                    if (interpolatedTime <= START_TRIM_DURATION_OFFSET) {\n                        // scale the interpolatedTime so that the full\n                        // transformation from 0 - 1 takes place in the\n                        // remaining time\n                        final float scaledTime = (interpolatedTime)\n                                / (1.0f - START_TRIM_DURATION_OFFSET);\n                        final float startTrim = startingTrim\n                                + ((MAX_PROGRESS_ARC - minProgressArc) * MATERIAL_INTERPOLATOR\n                                        .getInterpolation(scaledTime));\n                        ring.setStartTrim(startTrim);\n                    }\n\n                    // Moving the end trim starts after 50% of a single ring\n                    // animation completes\n                    if (interpolatedTime > END_TRIM_START_DELAY_OFFSET) {\n                        // scale the interpolatedTime so that the full\n                        // transformation from 0 - 1 takes place in the\n                        // remaining time\n                        final float minArc = MAX_PROGRESS_ARC - minProgressArc;\n                        float scaledTime = (interpolatedTime - START_TRIM_DURATION_OFFSET)\n                                / (1.0f - START_TRIM_DURATION_OFFSET);\n                        final float endTrim = startingEndTrim\n                                + (minArc * MATERIAL_INTERPOLATOR.getInterpolation(scaledTime));\n                        ring.setEndTrim(endTrim);\n                    }\n\n                    final float rotation = startingRotation + (0.25f * interpolatedTime);\n                    ring.setRotation(rotation);\n\n                    float groupRotation = ((FULL_ROTATION / NUM_POINTS) * interpolatedTime)\n                            + (FULL_ROTATION * (mRotationCount / NUM_POINTS));\n                    setRotation(groupRotation);\n                }\n            }\n        };\n        animation.setRepeatCount(Animation.INFINITE);\n        animation.setRepeatMode(Animation.RESTART);\n        animation.setInterpolator(LINEAR_INTERPOLATOR);\n        animation.setAnimationListener(new Animation.AnimationListener() {\n\n                @Override\n            public void onAnimationStart(Animation animation) {\n                mRotationCount = 0;\n            }\n\n                @Override\n            public void onAnimationEnd(Animation animation) {\n                // do nothing\n            }\n\n                @Override\n            public void onAnimationRepeat(Animation animation) {\n                ring.storeOriginals();\n                ring.goToNextColor();\n                ring.setStartTrim(ring.getEndTrim());\n                if (mFinishing) {\n                    // finished closing the last ring from the swipe gesture; go\n                    // into progress mode\n                    mFinishing = false;\n                    animation.setDuration(ANIMATION_DURATION);\n                    ring.setShowArrow(false);\n                } else {\n                    mRotationCount = (mRotationCount + 1) % (NUM_POINTS);\n                }\n            }\n        });\n        mAnimation = animation;\n    }\n\n    private final Callback mCallback = new Callback() {\n        @Override\n        public void invalidateDrawable(Drawable d) {\n            invalidateSelf();\n        }\n\n        @Override\n        public void scheduleDrawable(Drawable d, Runnable what, long when) {\n            scheduleSelf(what, when);\n        }\n\n        @Override\n        public void unscheduleDrawable(Drawable d, Runnable what) {\n            unscheduleSelf(what);\n        }\n    };\n\n    private static class Ring {\n        private final RectF mTempBounds = new RectF();\n        private final Paint mPaint = new Paint();\n        private final Paint mArrowPaint = new Paint();\n\n        private final Callback mCallback;\n\n        private float mStartTrim = 0.0f;\n        private float mEndTrim = 0.0f;\n        private float mRotation = 0.0f;\n        private float mStrokeWidth = 5.0f;\n        private float mStrokeInset = 2.5f;\n\n        private int[] mColors;\n        // mColorIndex represents the offset into the available mColors that the\n        // progress circle should currently display. As the progress circle is\n        // animating, the mColorIndex moves by one to the next available color.\n        private int mColorIndex;\n        private float mStartingStartTrim;\n        private float mStartingEndTrim;\n        private float mStartingRotation;\n        private boolean mShowArrow;\n        private Path mArrow;\n        private float mArrowScale;\n        private double mRingCenterRadius;\n        private int mArrowWidth;\n        private int mArrowHeight;\n        private int mAlpha;\n        private final Paint mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n        private int mBackgroundColor;\n        private int mCurrentColor;\n\n        public Ring(Callback callback) {\n            mCallback = callback;\n\n            mPaint.setStrokeCap(Paint.Cap.SQUARE);\n            mPaint.setAntiAlias(true);\n            mPaint.setStyle(Style.STROKE);\n\n            mArrowPaint.setStyle(Style.FILL);\n            mArrowPaint.setAntiAlias(true);\n        }\n\n        public void setBackgroundColor(int color) {\n            mBackgroundColor = color;\n        }\n\n        /**\n         * Set the dimensions of the arrowhead.\n         *\n         * @param width Width of the hypotenuse of the arrow head\n         * @param height Height of the arrow point\n         */\n        public void setArrowDimensions(float width, float height) {\n            mArrowWidth = (int) width;\n            mArrowHeight = (int) height;\n        }\n\n        /**\n         * Draw the progress spinner\n         */\n        public void draw(Canvas c, Rect bounds) {\n            final RectF arcBounds = mTempBounds;\n            arcBounds.set(bounds);\n            arcBounds.inset(mStrokeInset, mStrokeInset);\n\n            final float startAngle = (mStartTrim + mRotation) * 360;\n            final float endAngle = (mEndTrim + mRotation) * 360;\n            float sweepAngle = endAngle - startAngle;\n\n            mPaint.setColor(mCurrentColor);\n            c.drawArc(arcBounds, startAngle, sweepAngle, false, mPaint);\n\n            drawTriangle(c, startAngle, sweepAngle, bounds);\n\n            if (mAlpha < 255) {\n                mCirclePaint.setColor(mBackgroundColor);\n                mCirclePaint.setAlpha(255 - mAlpha);\n                c.drawCircle(bounds.exactCenterX(), bounds.exactCenterY(), bounds.width() / 2,\n                        mCirclePaint);\n            }\n        }\n\n        private void drawTriangle(Canvas c, float startAngle, float sweepAngle, Rect bounds) {\n            if (mShowArrow) {\n                if (mArrow == null) {\n                    mArrow = new Path();\n                    mArrow.setFillType(Path.FillType.EVEN_ODD);\n                } else {\n                    mArrow.reset();\n                }\n\n                // Adjust the position of the triangle so that it is inset as\n                // much as the arc, but also centered on the arc.\n                float inset = (int) mStrokeInset / 2 * mArrowScale;\n                float x = (float) (mRingCenterRadius * Math.cos(0) + bounds.exactCenterX());\n                float y = (float) (mRingCenterRadius * Math.sin(0) + bounds.exactCenterY());\n\n                // Update the path each time. This works around an issue in SKIA\n                // where concatenating a rotation matrix to a scale matrix\n                // ignored a starting negative rotation. This appears to have\n                // been fixed as of API 21.\n                mArrow.moveTo(0, 0);\n                mArrow.lineTo(mArrowWidth * mArrowScale, 0);\n                mArrow.lineTo((mArrowWidth * mArrowScale / 2), (mArrowHeight\n                        * mArrowScale));\n                mArrow.offset(x - inset, y);\n                mArrow.close();\n                // draw a triangle\n                mArrowPaint.setColor(mCurrentColor);\n                c.rotate(startAngle + sweepAngle - ARROW_OFFSET_ANGLE, bounds.exactCenterX(),\n                        bounds.exactCenterY());\n                c.drawPath(mArrow, mArrowPaint);\n            }\n        }\n\n        /**\n         * Set the colors the progress spinner alternates between.\n         *\n         * @param colors Array of integers describing the colors. Must be non-<code>null</code>.\n         */\n        public void setColors(@NonNull int[] colors) {\n            mColors = colors;\n            // if colors are reset, make sure to reset the color index as well\n            setColorIndex(0);\n        }\n\n        /**\n         * Set the absolute color of the progress spinner. This is should only\n         * be used when animating between current and next color when the\n         * spinner is rotating.\n         *\n         * @param color int describing the color.\n         */\n        public void setColor(int color) {\n            mCurrentColor = color;\n        }\n\n        /**\n         * @param index Index into the color array of the color to display in\n         *            the progress spinner.\n         */\n        public void setColorIndex(int index) {\n            mColorIndex = index;\n            mCurrentColor = mColors[mColorIndex];\n        }\n\n        /**\n         * @return int describing the next color the progress spinner should use when drawing.\n         */\n        public int getNextColor() {\n            return mColors[getNextColorIndex()];\n        }\n\n        private int getNextColorIndex() {\n            return (mColorIndex + 1) % (mColors.length);\n        }\n\n        /**\n         * Proceed to the next available ring color. This will automatically\n         * wrap back to the beginning of colors.\n         */\n        public void goToNextColor() {\n            setColorIndex(getNextColorIndex());\n        }\n\n        public void setColorFilter(ColorFilter filter) {\n            mPaint.setColorFilter(filter);\n            invalidateSelf();\n        }\n\n        /**\n         * @param alpha Set the alpha of the progress spinner and associated arrowhead.\n         */\n        public void setAlpha(int alpha) {\n            mAlpha = alpha;\n        }\n\n        /**\n         * @return Current alpha of the progress spinner and arrowhead.\n         */\n        public int getAlpha() {\n            return mAlpha;\n        }\n\n        /**\n         * @param strokeWidth Set the stroke width of the progress spinner in pixels.\n         */\n        public void setStrokeWidth(float strokeWidth) {\n            mStrokeWidth = strokeWidth;\n            mPaint.setStrokeWidth(strokeWidth);\n            invalidateSelf();\n        }\n\n        @SuppressWarnings(\"unused\")\n        public float getStrokeWidth() {\n            return mStrokeWidth;\n        }\n\n        @SuppressWarnings(\"unused\")\n        public void setStartTrim(float startTrim) {\n            mStartTrim = startTrim;\n            invalidateSelf();\n        }\n\n        @SuppressWarnings(\"unused\")\n        public float getStartTrim() {\n            return mStartTrim;\n        }\n\n        public float getStartingStartTrim() {\n            return mStartingStartTrim;\n        }\n\n        public float getStartingEndTrim() {\n            return mStartingEndTrim;\n        }\n\n        public int getStartingColor() {\n            return mColors[mColorIndex];\n        }\n\n        @SuppressWarnings(\"unused\")\n        public void setEndTrim(float endTrim) {\n            mEndTrim = endTrim;\n            invalidateSelf();\n        }\n\n        @SuppressWarnings(\"unused\")\n        public float getEndTrim() {\n            return mEndTrim;\n        }\n\n        @SuppressWarnings(\"unused\")\n        public void setRotation(float rotation) {\n            mRotation = rotation;\n            invalidateSelf();\n        }\n\n        @SuppressWarnings(\"unused\")\n        public float getRotation() {\n            return mRotation;\n        }\n\n        public void setInsets(int width, int height) {\n            final float minEdge = (float) Math.min(width, height);\n            float insets;\n            if (mRingCenterRadius <= 0 || minEdge < 0) {\n                insets = (float) Math.ceil(mStrokeWidth / 2.0f);\n            } else {\n                insets = (float) (minEdge / 2.0f - mRingCenterRadius);\n            }\n            mStrokeInset = insets;\n        }\n\n        @SuppressWarnings(\"unused\")\n        public float getInsets() {\n            return mStrokeInset;\n        }\n\n        /**\n         * @param centerRadius Inner radius in px of the circle the progress\n         *            spinner arc traces.\n         */\n        public void setCenterRadius(double centerRadius) {\n            mRingCenterRadius = centerRadius;\n        }\n\n        public double getCenterRadius() {\n            return mRingCenterRadius;\n        }\n\n        /**\n         * @param show Set to true to show the arrow head on the progress spinner.\n         */\n        public void setShowArrow(boolean show) {\n            if (mShowArrow != show) {\n                mShowArrow = show;\n                invalidateSelf();\n            }\n        }\n\n        /**\n         * @param scale Set the scale of the arrowhead for the spinner.\n         */\n        public void setArrowScale(float scale) {\n            if (scale != mArrowScale) {\n                mArrowScale = scale;\n                invalidateSelf();\n            }\n        }\n\n        /**\n         * @return The amount the progress spinner is currently rotated, between [0..1].\n         */\n        public float getStartingRotation() {\n            return mStartingRotation;\n        }\n\n        /**\n         * If the start / end trim are offset to begin with, store them so that\n         * animation starts from that offset.\n         */\n        public void storeOriginals() {\n            mStartingStartTrim = mStartTrim;\n            mStartingEndTrim = mEndTrim;\n            mStartingRotation = mRotation;\n        }\n\n        /**\n         * Reset the progress spinner to default rotation, start and end angles.\n         */\n        public void resetOriginals() {\n            mStartingStartTrim = 0;\n            mStartingEndTrim = 0;\n            mStartingRotation = 0;\n            setStartTrim(0);\n            setEndTrim(0);\n            setRotation(0);\n        }\n\n        private void invalidateSelf() {\n            mCallback.invalidateDrawable(null);\n        }\n    }\n}\n"
  },
  {
    "path": "lib/src/main/res/drawable/animated_rotate.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<animated-rotate xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:drawable=\"@drawable/loading_1\"\n    android:duration=\"5\"\n    android:indeterminate=\"true\"\n    android:pivotX=\"50%\"\n    android:pivotY=\"50%\">\n\n</animated-rotate>\n"
  },
  {
    "path": "lib/src/main/res/drawable/animated_rotate_1.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<animation-list android:oneshot=\"false\"\n  xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:duration=\"120\" android:drawable=\"@drawable/ic_loading_1\" />\n    <item android:duration=\"120\" android:drawable=\"@drawable/ic_loading_2\" />\n    <item android:duration=\"120\" android:drawable=\"@drawable/ic_loading_3\" />\n</animation-list>"
  },
  {
    "path": "lib/src/main/res/drawable/spinner.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<animation-list android:oneshot=\"false\"\n  xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:duration=\"60\" android:drawable=\"@drawable/loading_1\" />\n    <item android:duration=\"60\" android:drawable=\"@drawable/loading_2\" />\n    <item android:duration=\"60\" android:drawable=\"@drawable/loading_3\" />\n    <item android:duration=\"60\" android:drawable=\"@drawable/loading_4\" />\n    <item android:duration=\"60\" android:drawable=\"@drawable/loading_5\" />\n    <item android:duration=\"60\" android:drawable=\"@drawable/loading_6\" />\n    <item android:duration=\"60\" android:drawable=\"@drawable/loading_7\" />\n    <item android:duration=\"60\" android:drawable=\"@drawable/loading_8\" />\n</animation-list>"
  },
  {
    "path": "lib/src/main/res/layout/common_loading_refresh_header.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"88dp\"\n    android:layout_height=\"match_parent\">\n\n    <ImageView\n        android:id=\"@+id/static_loading\"\n        android:layout_width=\"35dp\"\n        android:layout_height=\"35dp\"\n        android:layout_gravity=\"center\"\n        android:background=\"@drawable/loading_1\"\n        android:indeterminate=\"true\" />\n\n    <ProgressBar\n        android:id=\"@+id/progressbar\"\n        android:layout_width=\"35dp\"\n        android:layout_height=\"35dp\"\n        android:layout_gravity=\"center\"\n        android:indeterminate=\"true\"\n        android:indeterminateDrawable=\"@drawable/spinner\" />\n\n</FrameLayout>"
  },
  {
    "path": "lib/src/main/res/layout/material_refresh_header.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"88dp\"\n    android:layout_height=\"match_parent\">\n\n</FrameLayout>"
  },
  {
    "path": "lib/src/main/res/layout/nice_refresh_header.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n              android:layout_width=\"88dp\"\n              android:layout_height=\"match_parent\">\n\n    <ImageView\n        android:id=\"@+id/static_loading\"\n        android:layout_width=\"52dp\"\n        android:layout_height=\"58dp\"\n        android:indeterminate=\"true\"\n        android:background=\"@drawable/ic_loading_1\"\n        android:layout_gravity=\"center\"/>\n\n    <ProgressBar\n        android:id=\"@+id/progressbar\"\n        android:layout_width=\"52dp\"\n        android:layout_height=\"58dp\"\n        android:indeterminate=\"true\"\n        android:indeterminateDrawable=\"@drawable/animated_rotate_1\"\n        android:layout_gravity=\"center\"/>\n\n</FrameLayout>"
  },
  {
    "path": "lib/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">lib</string>\n</resources>\n"
  },
  {
    "path": "settings.gradle",
    "content": "include ':app', ':lib'\n"
  }
]