[
  {
    "path": ".gitattributes",
    "content": "*.java linguist-language=kotlin"
  },
  {
    "path": ".gitignore",
    "content": "# Built application files\n*.apk\n*.ap_\n\n# Files for the ART/Dalvik VM\n*.dex\n\n# Java class files\n*.class\n\n# Generated files\nbin/\ngen/\nout/\n\n# Gradle files\n.gradle/\ngradle/\nbuild/\ngradle.properties\n\n# Local configuration file (sdk path, etc)\nlocal.properties\n\n# Proguard folder generated by Eclipse\nproguard/\n\n# Log Files\n*.log\n\n# Android Studio Navigation editor temp files\n.navigation/\n\n# Android Studio captures folder\ncaptures/\n\n# Intellij\n*.idea/\n.idea/workspace.xml\n.idea/tasks.xml\n.idea/gradle.xml\n.idea/dictionaries\n.idea/libraries\n.idea/copyright\n\n.idea/vcs.xml\n\n# Keystore files\n*.jks\n\n# External native build folder generated in Android Studio 2.2 and later\n.externalNativeBuild\n\n# Google Services (e.g. APIs or Firebase)\ngoogle-services.json\n\n# Freeline\nfreeline.py\nfreeline/\nfreeline_project_description.json\n\ngradlew\ngradlew.bat\n*.iml\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright {yyyy} {name of copyright owner}\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"
  },
  {
    "path": "LoadMore.md",
    "content": "#### 为什么不将LoadMore功能集成进RefreshLayout\n* 实现效果不友好,loadMoreView加载完成后,会有个回弹效果（个人不喜欢）\n* 加载更多的触发时机不好控制（比如滚动到内容倒数几条的时候自动加载）\n---\n[可以参考Demo基于RecyclerView实现的加载更多](https://github.com/XiaoQiWen/KRefreshLayout/tree/master/app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/widget/recyclerview)   [LoadMoreFragment](https://github.com/XiaoQiWen/KRefreshLayout/blob/master/app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleJFragment.kt)</br></br>\n![img](https://github.com/XiaoQiWen/Resources/raw/master/KRefreshLayout/gif6.gif)</br>\nDemo中[KLoadMoreView](https://github.com/XiaoQiWen/KRefreshLayout/blob/master/app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/widget/recyclerview/KLoadMoreView.kt)说明\n```\ninterface KLoadMoreView {\n    /**\n     * 自定义适当的加载时机\n     * @return true 自定义生效 false默认的加载时机\n     */\n    fun shouldLoadMore(recyclerView: KRecyclerView):Boolean\n\n    /**\n     * 正在加载\n     */\n    fun onLoadMore(recyclerView: KRecyclerView)\n\n    /**\n     * 加载完成\n     * @param hasMore 是否还有更多数据\n     */\n    fun onComplete(recyclerView: KRecyclerView, hasMore:Boolean)\n\n    /**\n     * 加载失败\n     * @param errorCode 错误码，由用户定义\n     */\n    fun onError(recyclerView: KRecyclerView, errorCode:Int)\n}\n```\n[LoadMoreDemo.APK下载](https://github.com/XiaoQiWen/Resources/raw/master/KRefreshLayout/demo_new.apk)\n"
  },
  {
    "path": "README.md",
    "content": "# KRefreshLayout (JRefreshLayout)\nkotlin和java两个版本的下拉刷新框架,支持任意View、支持定制任意header\n## Download[![Version](https://img.shields.io/badge/version-1.3-brightgreen.svg)](https://github.com/XiaoQiWen/KRefreshLayout/releases)\n#### KRefreshLayout\ngradle\n```\ncompile 'gorden.refresh:refresh-kotlin:1.3'\n```\nmaven\n```\n<dependency>\n  <groupId>gorden.refresh</groupId>\n  <artifactId>refresh-kotlin</artifactId>\n  <version>1.3</version>\n  <type>pom</type>\n</dependency>\n```\n``注意:kotlin版本目前需要下载插件或者使用AndroidStudio3.0+``</br>\n#### JRefreshLayout\ngradle\n```\ncompile 'gorden.refresh:refresh-java:1.3'\n```\nmaven\n```\n<dependency>\n  <groupId>gorden.refresh</groupId>\n  <artifactId>refresh-java</artifactId>\n  <version>1.3</version>\n  <type>pom</type>\n</dependency\n```\n## example\n[DEMO下载](https://github.com/XiaoQiWen/Resources/raw/master/KRefreshLayout/demo1.2.apk)</br></br>\n![](https://github.com/XiaoQiWen/Resources/raw/master/KRefreshLayout/gif0.gif)\n![](https://github.com/XiaoQiWen/Resources/raw/master/KRefreshLayout/gif1.gif)\n</br></br>\n![](https://github.com/XiaoQiWen/Resources/raw/master/KRefreshLayout/gif2.gif)\n![](https://github.com/XiaoQiWen/Resources/raw/master/KRefreshLayout/gif3.gif)\n</br></br>\n![](https://github.com/XiaoQiWen/Resources/raw/master/KRefreshLayout/gif4.gif)\n![](https://github.com/XiaoQiWen/Resources/raw/master/KRefreshLayout/gif5.gif)\n## Usage\n``KRefreshLayou详细使用说明:``\n>* [RefreshHeader接口说明](https://github.com/XiaoQiWen/KRefreshLayout/wiki/RefreshHeader%E6%96%B9%E6%B3%95%E8%AF%B4%E6%98%8E)\n>* [RefreshLayout开放Api](https://github.com/XiaoQiWen/KRefreshLayout/wiki/RefreshLayout%E5%BC%80%E6%94%BEApi)\n>* [XML参数配置](https://github.com/XiaoQiWen/KRefreshLayout/wiki/RefreshHeader-XML%E5%8F%AF%E9%85%8D%E7%BD%AE%E5%8F%82%E6%95%B0)\n>* [IOS边缘滚动效果实现](https://github.com/XiaoQiWen/KRefreshLayout/wiki/%E4%BB%BFIos%E8%BE%B9%E7%BC%98%E6%BB%9A%E5%8A%A8%E6%95%88%E6%9E%9C)\n>* [微信刷新Header实现](https://github.com/XiaoQiWen/KRefreshLayout/wiki/%E5%BE%AE%E4%BF%A1%E5%88%B7%E6%96%B0Header%E5%AE%9E%E7%8E%B0)\n\n设置刷新监听\n```\nrefreshLayout.setKRefreshListener {\n    refreshLayout.postDelayed({\n    //这里的true是指刷新成功，在header接口中complete能接收到这参数\n    refreshLayout.refreshComplete(true)\n    }, 2000)\n}\n```\n---\n[关于加载更多](https://github.com/XiaoQiWen/KRefreshLayout/blob/master/LoadMore.md)</br></br>\n更多请参考Demo\n### 联系方式\n* QQ:   354419188\n* Email:    gordenxqw@gmail.com\n\n### License\n    Copyright (C) 2017 XiaoQiWen\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"
  },
  {
    "path": "app_java/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app_java/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 27\n    buildToolsVersion \"27.0.1\"\n\n    defaultConfig {\n        applicationId \"gorden.jrefresh.demo\"\n        minSdkVersion 15\n        versionCode 1\n        versionName \"1.1\"\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.android.support:design:27.0.0'\n    compile 'com.android.support:appcompat-v7:27.0.0'\n    compile project(':refresh-java')\n}\n"
  },
  {
    "path": "app_java/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 F:\\AndroidSdk/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\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "app_java/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" package=\"gorden.jrefresh.demo\">\n\n    <application android:allowBackup=\"true\" android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\" android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\" android:theme=\"@style/AppTheme\">\n        <activity android:name=\".MainActivity\">\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_java/src/main/java/gorden/jrefresh/demo/MainActivity.java",
    "content": "package gorden.jrefresh.demo;\n\nimport android.support.v7.app.AppCompatActivity;\nimport android.os.Bundle;\nimport android.support.v7.widget.RecyclerView;\nimport android.view.LayoutInflater;\nimport android.view.ViewGroup;\n\nimport gorden.refresh.JRefreshLayout;\n\npublic class MainActivity extends AppCompatActivity {\n    JRefreshLayout refreshLayout;\n    RecyclerView recyclerView;\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_main);\n\n        refreshLayout = (JRefreshLayout) findViewById(R.id.refreshLayout);\n        recyclerView = (RecyclerView) findViewById(R.id.recyclerView);\n\n        recyclerView.setAdapter(new RecyclerView.Adapter() {\n            @Override\n            public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {\n                return new RecyclerView.ViewHolder(LayoutInflater.from(getBaseContext()).inflate(R.layout.item_sample,null)) {\n                };\n            }\n\n            @Override\n            public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {\n\n            }\n\n            @Override\n            public int getItemCount() {\n                return 20;\n            }\n        });\n\n        refreshLayout.setJRefreshListener(new JRefreshLayout.JRefreshListener() {\n            @Override\n            public void onRefresh(final JRefreshLayout refreshLayout) {\n                refreshLayout.postDelayed(new Runnable() {\n                    @Override\n                    public void run() {\n                        refreshLayout.refreshComplete(true);\n                    }\n                },3000);\n            }\n        });\n\n    }\n}\n"
  },
  {
    "path": "app_java/src/main/java/gorden/jrefresh/demo/header/ClassicalHeader.java",
    "content": "package gorden.jrefresh.demo.header;\n\nimport android.content.Context;\nimport android.graphics.Color;\nimport android.support.annotation.AttrRes;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.util.AttributeSet;\nimport android.util.Log;\nimport android.view.Gravity;\nimport android.view.View;\nimport android.view.animation.Animation;\nimport android.view.animation.LinearInterpolator;\nimport android.view.animation.RotateAnimation;\nimport android.widget.FrameLayout;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\n\nimport gorden.jrefresh.demo.R;\nimport gorden.jrefresh.demo.util.DensityUtil;\nimport gorden.refresh.JRefreshHeader;\nimport gorden.refresh.JRefreshLayout;\n\n\n/**\n * 经典下拉刷新\n * Created by Gorden on 2017/6/17.\n */\n\npublic class ClassicalHeader extends FrameLayout implements JRefreshHeader {\n    private static final String TAG = \"ClassicalHeader\";\n\n    private ImageView arrawImg;\n    private TextView textTitle;\n\n    private RotateAnimation rotateAnimation = new RotateAnimation(0,360,Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);\n\n    public ClassicalHeader(@NonNull Context context) {\n        this(context,null);\n    }\n\n    public ClassicalHeader(@NonNull Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs,0);\n    }\n\n    public ClassicalHeader(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n\n        LinearLayout root = new LinearLayout(context);\n        root.setOrientation(LinearLayout.HORIZONTAL);\n        root.setGravity(Gravity.CENTER_VERTICAL);\n        addView(root,LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);\n        ((LayoutParams)root.getLayoutParams()).gravity = Gravity.CENTER;\n\n        arrawImg = new ImageView(context);\n        arrawImg.setImageResource(R.drawable.ic_arrow_down);\n        arrawImg.setScaleType(ImageView.ScaleType.CENTER);\n        root.addView(arrawImg);\n\n        textTitle = new TextView(context);\n        textTitle.setTextSize(13);\n        textTitle.setText(\"下拉刷新...\");\n        textTitle.setTextColor(Color.parseColor(\"#999999\"));\n        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);\n        params.leftMargin = 20;\n        root.addView(textTitle,params);\n\n        rotateAnimation.setDuration(800);\n        rotateAnimation.setInterpolator(new LinearInterpolator());\n        rotateAnimation.setRepeatCount(Animation.INFINITE);\n        rotateAnimation.setRepeatMode(Animation.RESTART);\n        setPadding(0, DensityUtil.dip2px(15),0,DensityUtil.dip2px(15));\n    }\n\n    @Override\n    public long succeedRetention() {\n        return 200;\n    }\n\n    @Override\n    public long failingRetention() {\n        return 0;\n    }\n\n    @Override\n    public int refreshHeight() {\n        return getHeight();\n    }\n\n    @Override\n    public int maxOffsetHeight() {\n        return 4*getHeight();\n    }\n\n\n    boolean isReset = true;\n\n    @Override\n    public void onReset( JRefreshLayout refreshLayout) {\n        Log.e(TAG,\"----------------> onReset\");\n        arrawImg.setImageResource(R.drawable.ic_arrow_down);\n        textTitle.setText(\"下拉刷新...\");\n        isReset = true;\n        arrawImg.setVisibility(VISIBLE);\n    }\n\n    @Override\n    public void onPrepare( JRefreshLayout refreshLayout) {\n        Log.e(TAG,\"----------------> onPrepare\");\n        arrawImg.setImageResource(R.drawable.ic_arrow_down);\n        textTitle.setText(\"下拉刷新...\");\n    }\n\n    @Override\n    public void onRefresh( JRefreshLayout refreshLayout) {\n        Log.e(TAG,\"----------------> onRefresh\");\n        arrawImg.setImageResource(R.drawable.ic_loading);\n        arrawImg.startAnimation(rotateAnimation);\n        textTitle.setText(\"加载中...\");\n        isReset = false;\n    }\n\n    @Override\n    public void onComplete( JRefreshLayout refreshLayout,boolean isSuccess) {\n        Log.e(TAG,\"----------------> onComplete\");\n        arrawImg.clearAnimation();\n        arrawImg.setVisibility(GONE);\n        if (isSuccess){\n            textTitle.setText(\"刷新完成...\");\n        }else{\n            textTitle.setText(\"刷新失败...\");\n        }\n    }\n\n    boolean attain = false;\n\n    @Override\n    public void onScroll( JRefreshLayout refreshLayout, int distance, float percent,boolean refreshing) {\n        Log.e(TAG,\"----------------> onScroll  \"+percent);\n\n        if (!refreshing&&isReset){\n            if(percent>=1&&!attain){\n                attain = true;\n                textTitle.setText(\"释放刷新...\");\n                arrawImg.animate().rotation(-180).start();\n            }else if (percent<1&&attain){\n                attain = false;\n                arrawImg.animate().rotation(0).start();\n                textTitle.setText(\"下拉刷新...\");\n            }\n        }\n    }\n\n\n\n}\n"
  },
  {
    "path": "app_java/src/main/java/gorden/jrefresh/demo/util/DensityUtil.java",
    "content": "package gorden.jrefresh.demo.util;\n\nimport android.content.res.Resources;\n\n/**\n * document\n * Created by Gordn on 2017/6/19.\n */\n\npublic class DensityUtil {\n    private static float density = Resources.getSystem().getDisplayMetrics().density;\n\n    public static int dip2px(int dp){\n        return (int) (dp*density);\n    }\n    public static int dip2px(float dp){\n        return (int) (dp*density);\n    }\n    public static int appWidth(){\n        return Resources.getSystem().getDisplayMetrics().widthPixels;\n    }\n}\n"
  },
  {
    "path": "app_java/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    tools:context=\"gorden.jrefresh.demo.MainActivity\">\n    <gorden.refresh.JRefreshLayout\n        android:id=\"@+id/refreshLayout\"\n        android:layout_width=\"match_parent\"\n        android:background=\"#2f5181\"\n        android:layout_height=\"match_parent\">\n        <gorden.jrefresh.demo.header.ClassicalHeader\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"/>\n        <android.support.v7.widget.RecyclerView\n            android:id=\"@+id/recyclerView\"\n            android:layout_width=\"match_parent\"\n            app:layoutManager=\"LinearLayoutManager\"\n            android:layout_height=\"match_parent\"/>\n    </gorden.refresh.JRefreshLayout>\n\n</FrameLayout>\n"
  },
  {
    "path": "app_java/src/main/res/layout/item_sample.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"100dp\">\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"100dp\"\n        android:paddingLeft=\"10dp\"\n        android:paddingRight=\"10dp\"\n        android:background=\"#ffffff\"\n        android:gravity=\"center_vertical\"\n\n        android:orientation=\"horizontal\">\n        <ImageView\n            android:layout_width=\"100dp\"\n            android:layout_height=\"100dp\"\n            android:src=\"@drawable/img_java\"\n            />\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n            <TextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"This is Sample Item\"\n                android:textColor=\"#333\"\n                android:textSize=\"16sp\"\n                />\n            <TextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"5dp\"\n                android:text=\"This is Sample Item description\"\n                />\n        </LinearLayout>\n    </LinearLayout>\n</RelativeLayout>"
  },
  {
    "path": "app_java/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</resources>\n"
  },
  {
    "path": "app_java/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">JRefreshLayout</string>\n</resources>\n"
  },
  {
    "path": "app_java/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_kotlin/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app_kotlin/build.gradle",
    "content": "apply plugin: 'com.android.application'\napply plugin: 'kotlin-android'\napply plugin: 'kotlin-android-extensions'\n\nandroid {\n    compileSdkVersion 27\n    buildToolsVersion \"27.0.1\"\n    defaultConfig {\n        applicationId \"gorden.krefreshlayout.demo\"\n        minSdkVersion 15\n        versionCode 1\n        versionName \"1.1\"\n        testInstrumentationRunner \"android.support.test.runner.AndroidJUnitRunner\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n}\n\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {\n        exclude group: 'com.android.support', module: 'support-annotations'\n    })\n//    compile 'gorden.refresh:refresh-kotlin:1.0'\n    compile project(path: ':refresh-kotlin')\n    compile \"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version\"\n    compile 'com.android.support:appcompat-v7:27.0.0'\n    compile 'com.android.support:design:27.0.0'\n    testCompile 'junit:junit:4.12'\n}\nrepositories {\n    mavenCentral()\n}\n"
  },
  {
    "path": "app_kotlin/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 D:\\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\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "app_kotlin/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=\"gorden.krefreshlayout.demo\">\n\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n\n    <application\n        android:name=\".App\"\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\">\n        <activity android:name=\".ui.MainActivity\">\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        <activity android:name=\".ui.SampleActivity\">\n            <intent-filter>\n                <action android:name=\"SampleActivity\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity>\n        <activity android:name=\".ui.SettingActivity\">\n            <intent-filter>\n                <action android:name=\"SettingActivity\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity>\n    </application>\n\n</manifest>"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/App.java",
    "content": "package gorden.krefreshlayout.demo;\n\nimport android.app.Application;\nimport android.content.Intent;\n\nimport gorden.krefreshlayout.demo.ui.SampleActivity;\nimport gorden.krefreshlayout.demo.util.CrashHandler;\n\n/**\n * Created by Gorden on 2017/6/20.\n */\n\npublic class App extends Application{\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        CrashHandler.getInstance().init(this,true);\n    }\n}\n"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/footer/ClassicalFooter.java",
    "content": "package gorden.krefreshlayout.demo.footer;\n\nimport android.content.Context;\nimport android.graphics.Color;\nimport android.support.annotation.AttrRes;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.util.AttributeSet;\nimport android.view.Gravity;\nimport android.view.View;\nimport android.view.animation.Animation;\nimport android.view.animation.LinearInterpolator;\nimport android.view.animation.RotateAnimation;\nimport android.widget.FrameLayout;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport org.jetbrains.annotations.NotNull;\n\nimport gorden.krefreshlayout.demo.R;\nimport gorden.krefreshlayout.demo.util.DensityUtil;\nimport gorden.krefreshlayout.demo.widget.recyclerview.KLoadMoreView;\nimport gorden.krefreshlayout.demo.widget.recyclerview.KRecyclerView;\n\n\n/**\n * 经典下拉刷新\n * Created by Gorden on 2017/6/17.\n */\n\npublic class ClassicalFooter extends FrameLayout implements KLoadMoreView {\n    private KRecyclerView recyclerView;\n    private ImageView arrawImg;\n    private TextView textTitle;\n\n    private RotateAnimation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);\n\n    public ClassicalFooter(@NonNull Context context) {\n        this(context, null);\n    }\n\n    public ClassicalFooter(@NonNull Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public ClassicalFooter(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n\n        LinearLayout root = new LinearLayout(context);\n        root.setOrientation(LinearLayout.HORIZONTAL);\n        root.setGravity(Gravity.CENTER_VERTICAL);\n        addView(root, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);\n        ((LayoutParams) root.getLayoutParams()).gravity = Gravity.CENTER;\n\n        arrawImg = new ImageView(context);\n        arrawImg.setImageResource(R.drawable.ic_loading);\n        arrawImg.setScaleType(ImageView.ScaleType.CENTER);\n        root.addView(arrawImg);\n\n        textTitle = new TextView(context);\n        textTitle.setTextSize(13);\n        textTitle.setText(\"上拉或点击加载更多...\");\n        textTitle.setTextColor(Color.parseColor(\"#999999\"));\n        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);\n        params.leftMargin = 20;\n        root.addView(textTitle, params);\n\n        rotateAnimation.setDuration(800);\n        rotateAnimation.setInterpolator(new LinearInterpolator());\n        rotateAnimation.setRepeatCount(Animation.INFINITE);\n        rotateAnimation.setRepeatMode(Animation.RESTART);\n        setPadding(0, DensityUtil.dip2px(15), 0, DensityUtil.dip2px(15));\n\n        setOnClickListener(new OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                recyclerView.startLoadMore();\n            }\n        });\n    }\n\n    @Override\n    public boolean shouldLoadMore(@NotNull KRecyclerView recyclerView) {\n        this.recyclerView = recyclerView;\n        return false;\n    }\n\n    @Override\n    public void onLoadMore(@NotNull KRecyclerView recyclerView) {\n        arrawImg.setVisibility(VISIBLE);\n        arrawImg.startAnimation(rotateAnimation);\n        textTitle.setText(\"正在加载...\");\n    }\n\n    @Override\n    public void onComplete(@NotNull KRecyclerView recyclerView, boolean hasMore) {\n        arrawImg.clearAnimation();\n        textTitle.setText(hasMore ? \"上拉或点击加载更多...\" : \"没有更多数据\");\n        arrawImg.setVisibility(GONE);\n    }\n\n    @Override\n    public void onError(@NotNull KRecyclerView recyclerView, int errorCode) {\n        arrawImg.clearAnimation();\n        textTitle.setText(\"加载失败,点击重新加载\");\n        arrawImg.setVisibility(GONE);\n    }\n}\n"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/ClassicalHeader.java",
    "content": "package gorden.krefreshlayout.demo.header;\n\nimport android.content.Context;\nimport android.graphics.Color;\nimport android.support.annotation.AttrRes;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.util.AttributeSet;\nimport android.util.Log;\nimport android.view.Gravity;\nimport android.view.View;\nimport android.view.animation.Animation;\nimport android.view.animation.LinearInterpolator;\nimport android.view.animation.RotateAnimation;\nimport android.widget.FrameLayout;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport org.jetbrains.annotations.NotNull;\n\nimport gorden.krefreshlayout.demo.R;\nimport gorden.krefreshlayout.demo.util.DensityUtil;\nimport gorden.refresh.KRefreshHeader;\nimport gorden.refresh.KRefreshLayout;\n\n\n/**\n * 经典下拉刷新\n * Created by Gorden on 2017/6/17.\n */\n\npublic class ClassicalHeader extends FrameLayout implements KRefreshHeader {\n    private static final String TAG = \"ClassicalHeader\";\n\n    private ImageView arrawImg;\n    private TextView textTitle;\n\n    private RotateAnimation rotateAnimation = new RotateAnimation(0,360,Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);\n\n    public ClassicalHeader(@NonNull Context context) {\n        this(context,null);\n    }\n\n    public ClassicalHeader(@NonNull Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs,0);\n    }\n\n    public ClassicalHeader(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n\n        LinearLayout root = new LinearLayout(context);\n        root.setOrientation(LinearLayout.HORIZONTAL);\n        root.setGravity(Gravity.CENTER_VERTICAL);\n        addView(root,LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);\n        ((LayoutParams)root.getLayoutParams()).gravity = Gravity.CENTER;\n\n        arrawImg = new ImageView(context);\n        arrawImg.setImageResource(R.drawable.ic_arrow_down);\n        arrawImg.setScaleType(ImageView.ScaleType.CENTER);\n        root.addView(arrawImg);\n\n        textTitle = new TextView(context);\n        textTitle.setTextSize(13);\n        textTitle.setText(\"下拉刷新...\");\n        textTitle.setTextColor(Color.parseColor(\"#999999\"));\n        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);\n        params.leftMargin = 20;\n        root.addView(textTitle,params);\n\n        rotateAnimation.setDuration(800);\n        rotateAnimation.setInterpolator(new LinearInterpolator());\n        rotateAnimation.setRepeatCount(Animation.INFINITE);\n        rotateAnimation.setRepeatMode(Animation.RESTART);\n        setPadding(0, DensityUtil.dip2px(15),0,DensityUtil.dip2px(15));\n    }\n\n    @Override\n    public long succeedRetention() {\n        return 200;\n    }\n\n    @Override\n    public long failingRetention() {\n        return 0;\n    }\n\n    @Override\n    public int refreshHeight() {\n        return getHeight();\n    }\n\n    @Override\n    public int maxOffsetHeight() {\n        return 4*getHeight();\n    }\n\n\n    boolean isReset = true;\n\n    @Override\n    public void onReset(@NotNull KRefreshLayout refreshLayout) {\n        Log.e(TAG,\"----------------> onReset\");\n        arrawImg.setImageResource(R.drawable.ic_arrow_down);\n        textTitle.setText(\"下拉刷新...\");\n        isReset = true;\n        arrawImg.setVisibility(VISIBLE);\n    }\n\n    @Override\n    public void onPrepare(@NotNull KRefreshLayout refreshLayout) {\n        Log.e(TAG,\"----------------> onPrepare\");\n        arrawImg.setImageResource(R.drawable.ic_arrow_down);\n        textTitle.setText(\"下拉刷新...\");\n    }\n\n    @Override\n    public void onRefresh(@NotNull KRefreshLayout refreshLayout) {\n        Log.e(TAG,\"----------------> onRefresh\");\n        arrawImg.setImageResource(R.drawable.ic_loading);\n        arrawImg.startAnimation(rotateAnimation);\n        textTitle.setText(\"加载中...\");\n        isReset = false;\n    }\n\n    @Override\n    public void onComplete(@NotNull KRefreshLayout refreshLayout,boolean isSuccess) {\n        Log.e(TAG,\"----------------> onComplete\");\n        arrawImg.clearAnimation();\n        arrawImg.setVisibility(GONE);\n        if (isSuccess){\n            textTitle.setText(\"刷新完成...\");\n        }else{\n            textTitle.setText(\"刷新失败...\");\n        }\n    }\n\n    boolean attain = false;\n\n    @Override\n    public void onScroll(@NotNull KRefreshLayout refreshLayout, int distance, float percent,boolean refreshing) {\n        Log.e(TAG,\"----------------> onScroll  \"+percent);\n\n        if (!refreshing&&isReset){\n            if(percent>=1&&!attain){\n                attain = true;\n                textTitle.setText(\"释放刷新...\");\n                arrawImg.animate().rotation(-180).start();\n            }else if (percent<1&&attain){\n                attain = false;\n                arrawImg.animate().rotation(0).start();\n                textTitle.setText(\"下拉刷新...\");\n            }\n        }\n    }\n\n\n\n}\n"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/WechatHeader.java",
    "content": "package gorden.krefreshlayout.demo.header;\n\nimport android.animation.ValueAnimator;\nimport android.content.Context;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.view.animation.Animation;\nimport android.view.animation.LinearInterpolator;\nimport android.view.animation.RotateAnimation;\nimport android.widget.FrameLayout;\nimport android.widget.ImageView;\n\nimport org.jetbrains.annotations.NotNull;\n\nimport gorden.krefreshlayout.demo.R;\nimport gorden.krefreshlayout.demo.util.DensityUtil;\nimport gorden.refresh.KRefreshHeader;\nimport gorden.refresh.KRefreshLayout;\n\n/**\n * document\n * Created by Gordn on 2017/6/26.\n */\n\npublic class WechatHeader extends FrameLayout implements KRefreshHeader {\n    private ImageView imgChat;\n    private RotateAnimation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);\n    private ValueAnimator returnAnima = new ValueAnimator();\n\n    public WechatHeader(@NonNull Context context) {\n        this(context, null);\n    }\n\n    public WechatHeader(@NonNull Context context, @Nullable AttributeSet attrs) {\n        super(context, attrs);\n\n        imgChat = new ImageView(context);\n        imgChat.setImageResource(R.drawable.ic_wechat);\n        LayoutParams params = new LayoutParams(DensityUtil.dip2px(30), DensityUtil.dip2px(30));\n        params.leftMargin = DensityUtil.dip2px(20);\n        addView(imgChat, params);\n\n        rotateAnimation.setDuration(800);\n        rotateAnimation.setInterpolator(new LinearInterpolator());\n        rotateAnimation.setRepeatCount(Animation.INFINITE);\n        rotateAnimation.setRepeatMode(Animation.RESTART);\n\n        returnAnima.setDuration(800);\n        returnAnima.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {\n            @Override\n            public void onAnimationUpdate(ValueAnimator animation) {\n                int progress = (int) animation.getAnimatedValue();\n                offsetTopAndBottom(progress - mDistance);\n                imgChat.setRotation(progress);\n                mDistance = progress;\n                if (getParent() instanceof KRefreshLayout) {\n                    ((KRefreshLayout) getParent()).setHeaderOffset(mDistance - lastDistance);\n                }\n            }\n        });\n    }\n\n    @Override\n    public long succeedRetention() {\n        return 0;\n    }\n\n    @Override\n    public long failingRetention() {\n        return 0;\n    }\n\n    @Override\n    public int refreshHeight() {\n        return DensityUtil.dip2px(50);\n    }\n\n    @Override\n    public int maxOffsetHeight() {\n        return ((View) getParent()).getHeight();\n    }\n\n    @Override\n    public void onReset(@NotNull KRefreshLayout refreshLayout) {\n\n    }\n\n    @Override\n    public void onPrepare(@NotNull KRefreshLayout refreshLayout) {\n    }\n\n    @Override\n    public void onRefresh(@NotNull KRefreshLayout refreshLayout) {\n        imgChat.startAnimation(rotateAnimation);\n    }\n\n    @Override\n    public void onComplete(@NotNull KRefreshLayout refreshLayout, boolean isSuccess) {\n        imgChat.clearAnimation();\n        returnAnima.setIntValues(mDistance, 0);\n        returnAnima.start();\n    }\n\n    public int mDistance = 0;\n    private int lastDistance;\n\n    @Override\n    public void onScroll(@NotNull KRefreshLayout refreshLayout, int distance, float percent, boolean refreshing) {\n        int offset = distance - lastDistance;\n        if (returnAnima.isRunning())\n            returnAnima.cancel();\n        lastDistance = distance;\n\n        if (!refreshing) {\n            imgChat.setRotation(-distance);\n            if (percent > 1) {\n                offsetTopAndBottom(-offset);\n                if (mDistance != refreshHeight()) {\n                    offset = refreshHeight() - mDistance;\n                    offsetTopAndBottom(offset);\n                    mDistance += offset;\n                }\n            } else {\n                if (mDistance + offset != distance) {\n                    offset = distance - (mDistance + offset);\n                    offsetTopAndBottom(offset);\n                }\n                mDistance = distance;\n            }\n        } else {\n            offsetTopAndBottom(-offset);\n        }\n        refreshLayout.setHeaderOffset(mDistance - distance);\n    }\n}\n"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/circle/AnimationView.java",
    "content": "package gorden.krefreshlayout.demo.header.circle;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.Path;\nimport android.graphics.PointF;\nimport android.graphics.RectF;\nimport android.util.AttributeSet;\nimport android.util.TypedValue;\nimport android.view.View;\nimport android.view.ViewGroup;\n\n/**\n * Created by zhanglei on 15/7/18.\n */\npublic class AnimationView extends View {\n\n    private static final String TAG = \"AnimationView\";\n\n    private int PULL_HEIGHT;\n    private int PULL_DELTA;\n    private float mWidthOffset;\n\n\n\n    private AnimatorStatus mAniStatus = AnimatorStatus.PULL_DOWN;\n\n    enum AnimatorStatus {\n        PULL_DOWN,\n        DRAG_DOWN,\n        REL_DRAG,\n        SPRING_UP, // rebound to up, the position is less than PULL_HEIGHT\n        POP_BALL,\n        OUTER_CIR,\n        REFRESHING,\n        DONE,\n        STOP;\n\n        @Override\n        public String toString() {\n            switch (this) {\n                case PULL_DOWN:\n                    return \"pull down\";\n                case DRAG_DOWN:\n                    return \"drag down\";\n                case REL_DRAG:\n                    return \"release drag\";\n                case SPRING_UP:\n                    return \"spring up\";\n                case POP_BALL:\n                    return \"pop ball\";\n                case OUTER_CIR:\n                    return \"outer circle\";\n                case REFRESHING:\n                    return \"refreshing...\";\n                case DONE:\n                    return \"done!\";\n                case STOP:\n                    return \"stop\";\n                default:\n                    return \"unknown state\";\n            }\n        }\n    }\n\n\n    private Paint mBackPaint;\n    private Paint mBallPaint;\n    private Paint mOutPaint;\n    private Path mPath;\n\n\n    public AnimationView(Context context) {\n        this(context, null, 0);\n    }\n\n    public AnimationView(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public AnimationView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        initView(context, attrs, defStyleAttr);\n    }\n\n    private void initView(Context context, AttributeSet attrs, int defStyleAttr) {\n\n        PULL_HEIGHT = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100, context.getResources().getDisplayMetrics());\n        PULL_DELTA = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics());\n        mWidthOffset = 0.5f;\n        mBackPaint = new Paint();\n        mBackPaint.setAntiAlias(true);\n        mBackPaint.setStyle(Paint.Style.FILL);\n        mBackPaint.setColor(0xff8b90af);\n\n        mBallPaint = new Paint();\n        mBallPaint.setAntiAlias(true);\n        mBallPaint.setColor(0xffffffff);\n        mBallPaint.setStyle(Paint.Style.FILL);\n\n        mOutPaint = new Paint();\n        mOutPaint.setAntiAlias(true);\n        mOutPaint.setColor(0xffffffff);\n        mOutPaint.setStyle(Paint.Style.STROKE);\n        mOutPaint.setStrokeWidth(5);\n\n\n        mPath = new Path();\n\n    }\n\n    private int mRadius;\n    private int mWidth;\n    private int mHeight;\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        int height = MeasureSpec.getSize(heightMeasureSpec);\n        if (height > PULL_DELTA + PULL_HEIGHT) {\n            heightMeasureSpec = MeasureSpec.makeMeasureSpec(PULL_DELTA + PULL_HEIGHT, MeasureSpec.getMode(heightMeasureSpec));\n        }\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n    }\n\n    @Override\n    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {\n        super.onLayout(changed, left, top, right, bottom);\n        if (changed) {\n            mRadius = getHeight() / 6;\n            mWidth = getWidth();\n            mHeight = getHeight();\n\n            if (mHeight < PULL_HEIGHT) {\n                mAniStatus = AnimatorStatus.PULL_DOWN;\n            }\n\n\n            switch (mAniStatus) {\n                case PULL_DOWN:\n                    if (mHeight >= PULL_HEIGHT) {\n                        mAniStatus = AnimatorStatus.DRAG_DOWN;\n                    }\n                    break;\n                case REL_DRAG:\n                    break;\n            }\n\n        }\n    }\n\n    @Override\n    protected void onDraw(Canvas canvas) {\n        super.onDraw(canvas);\n\n        switch (mAniStatus) {\n            case PULL_DOWN:\n                canvas.drawRect(0, 0, mWidth, mHeight, mBackPaint);\n                break;\n            case REL_DRAG:\n            case DRAG_DOWN:\n                drawDrag(canvas);\n                break;\n            case SPRING_UP:\n                drawSpring(canvas, getSpringDelta());\n                invalidate();\n                break;\n            case POP_BALL:\n                drawPopBall(canvas);\n                invalidate();\n                break;\n            case OUTER_CIR:\n                drawOutCir(canvas);\n                invalidate();\n                break;\n            case REFRESHING:\n                drawRefreshing(canvas);\n                invalidate();\n                break;\n            case DONE:\n                drawDone(canvas);\n                invalidate();\n                break;\n            case STOP:\n                drawDone(canvas);\n                break;\n\n        }\n\n        if (mAniStatus == AnimatorStatus.REL_DRAG) {\n            ViewGroup.LayoutParams params = getLayoutParams();\n            int height;\n            // NOTICE: If the height equals mLastHeight, then the requestLayout() will not work correctly\n            do {\n                height = getRelHeight();\n            } while (height == mLastHeight && getRelRatio() != 1);\n            mLastHeight = height;\n            params.height = PULL_HEIGHT + height;\n            requestLayout();\n        }\n\n\n    }\n\n    private void drawDrag(Canvas canvas) {\n        canvas.drawRect(0, 0, mWidth, PULL_HEIGHT, mBackPaint);\n\n        mPath.reset();\n        mPath.moveTo(0, PULL_HEIGHT);\n        mPath.quadTo(mWidthOffset * mWidth, PULL_HEIGHT + (mHeight - PULL_HEIGHT) * 2,\n                mWidth, PULL_HEIGHT);\n        canvas.drawPath(mPath, mBackPaint);\n    }\n\n    private void drawSpring(Canvas canvas, int springDelta) {\n        mPath.reset();\n        mPath.moveTo(0, 0);\n        mPath.lineTo(0, PULL_HEIGHT);\n        mPath.quadTo(mWidth / 2, PULL_HEIGHT - springDelta,\n                mWidth, PULL_HEIGHT);\n        mPath.lineTo(mWidth, 0);\n        canvas.drawPath(mPath, mBackPaint);\n\n        int curH = PULL_HEIGHT - springDelta / 2;\n\n        if (curH > PULL_HEIGHT - PULL_DELTA / 2) {\n            int leftX = (int) (mWidth / 2 - 2 * mRadius + getSprRatio() * mRadius);\n            mPath.reset();\n            mPath.moveTo(leftX, curH);\n            mPath.quadTo(mWidth / 2, curH - mRadius * getSprRatio() * 2,\n                    mWidth - leftX, curH);\n            canvas.drawPath(mPath, mBallPaint);\n        } else {\n            canvas.drawArc(new RectF(mWidth / 2 - mRadius, curH - mRadius, mWidth / 2 + mRadius, curH + mRadius),\n                    180, 180, true, mBallPaint);\n        }\n\n    }\n\n    private void drawPopBall(Canvas canvas) {\n        mPath.reset();\n        mPath.moveTo(0, 0);\n        mPath.lineTo(0, PULL_HEIGHT);\n        mPath.quadTo(mWidth / 2, PULL_HEIGHT - PULL_DELTA,\n                mWidth, PULL_HEIGHT);\n        mPath.lineTo(mWidth, 0);\n        canvas.drawPath(mPath, mBackPaint);\n\n        int cirCentStart = PULL_HEIGHT - PULL_DELTA / 2;\n        int cirCenY = (int) (cirCentStart - mRadius * 2 * getPopRatio());\n\n        canvas.drawArc(new RectF(mWidth / 2 - mRadius, cirCenY - mRadius, mWidth / 2 + mRadius, cirCenY + mRadius),\n                180, 360, true, mBallPaint);\n\n        if (getPopRatio() < 1) {\n            drawTail(canvas, cirCenY, cirCentStart + 1, getPopRatio());\n        } else {\n            canvas.drawCircle(mWidth / 2, cirCenY, mRadius, mBallPaint);\n        }\n\n\n    }\n\n    private void drawTail(Canvas canvas, int centerY, int bottom, float fraction) {\n        int bezier1w = (int) (mWidth / 2 + (mRadius * 3 / 4) * (1 - fraction));\n        PointF start = new PointF(mWidth / 2 + mRadius, centerY);\n        PointF bezier1 = new PointF(bezier1w, bottom);\n        PointF bezier2 = new PointF(bezier1w + mRadius / 2, bottom);\n\n        mPath.reset();\n        mPath.moveTo(start.x, start.y);\n        mPath.quadTo(bezier1.x, bezier1.y,\n                bezier2.x, bezier2.y);\n        mPath.lineTo(mWidth - bezier2.x, bezier2.y);\n        mPath.quadTo(mWidth - bezier1.x, bezier1.y,\n                mWidth - start.x, start.y);\n        canvas.drawPath(mPath, mBallPaint);\n    }\n\n    private void drawOutCir(Canvas canvas) {\n        mPath.reset();\n        mPath.moveTo(0, 0);\n        mPath.lineTo(0, PULL_HEIGHT);\n        mPath.quadTo(mWidth / 2, PULL_HEIGHT - (1 - getOutRatio()) * PULL_DELTA,\n                mWidth, PULL_HEIGHT);\n        mPath.lineTo(mWidth, 0);\n        canvas.drawPath(mPath, mBackPaint);\n        int innerY = PULL_HEIGHT - PULL_DELTA / 2 - mRadius * 2;\n        canvas.drawCircle(mWidth / 2, innerY, mRadius, mBallPaint);\n    }\n\n    private int mRefreshStart = 90;\n    private int mRefreshStop = 90;\n    private int TARGET_DEGREE = 270;\n    private boolean mIsStart = true;\n    private boolean mIsRefreshing = true;\n\n    private void drawRefreshing(Canvas canvas) {\n        canvas.drawRect(0, 0, mWidth, mHeight, mBackPaint);\n        int innerY = PULL_HEIGHT - PULL_DELTA / 2 - mRadius * 2;\n        canvas.drawCircle(mWidth / 2, innerY, mRadius, mBallPaint);\n        int outerR = mRadius + 10;\n\n        mRefreshStart += mIsStart ? 3 : 10;\n        mRefreshStop += mIsStart ? 10 : 3;\n        mRefreshStart = mRefreshStart % 360;\n        mRefreshStop = mRefreshStop % 360;\n\n        int swipe = mRefreshStop - mRefreshStart;\n        swipe = swipe < 0 ? swipe + 360 : swipe;\n\n        canvas.drawArc(new RectF(mWidth / 2 - outerR, innerY - outerR, mWidth / 2 + outerR, innerY + outerR),\n                mRefreshStart, swipe, false, mOutPaint);\n        if (swipe >= TARGET_DEGREE) {\n            mIsStart = false;\n        } else if (swipe <= 10) {\n            mIsStart = true;\n        }\n        if (!mIsRefreshing) {\n            applyDone();\n\n        }\n\n    }\n\n    // stop refreshing\n    public void setRefreshing(boolean isFresh) {\n        mIsRefreshing = isFresh;\n    }\n\n    private void drawDone(Canvas canvas) {\n\n\n        int beforeColor = mOutPaint.getColor();\n        if (getDoneRatio() < 0.3) {\n            canvas.drawRect(0, 0, mWidth, mHeight, mBackPaint);\n            int innerY = PULL_HEIGHT - PULL_DELTA / 2 - mRadius * 2;\n            canvas.drawCircle(mWidth / 2, innerY, mRadius, mBallPaint);\n            int outerR = (int) (mRadius + 10 + 10 * getDoneRatio() / 0.3f);\n            int afterColor = Color.argb((int) (0xff * (1 - getDoneRatio() / 0.3f)), Color.red(beforeColor),\n                    Color.green(beforeColor), Color.blue(beforeColor));\n            mOutPaint.setColor(afterColor);\n            canvas.drawArc(new RectF(mWidth / 2 - outerR, innerY - outerR, mWidth / 2 + outerR, innerY + outerR),\n                    0, 360, false, mOutPaint);\n        }\n        mOutPaint.setColor(beforeColor);\n\n\n        if (getDoneRatio() >= 0.3 && getDoneRatio() < 0.7) {\n            canvas.drawRect(0, 0, mWidth, mHeight, mBackPaint);\n            float fraction = (getDoneRatio() - 0.3f) / 0.4f;\n            int startCentY = PULL_HEIGHT - PULL_DELTA / 2 - mRadius * 2;\n            int curCentY = (int) (startCentY + (PULL_DELTA / 2 + mRadius * 2) * fraction);\n            canvas.drawCircle(mWidth / 2, curCentY, mRadius, mBallPaint);\n            if (curCentY >= PULL_HEIGHT - mRadius * 2) {\n                drawTail(canvas, curCentY, PULL_HEIGHT, (1 - fraction));\n            }\n        }\n\n        if (getDoneRatio() >= 0.7 && getDoneRatio() <= 1) {\n            float fraction = (getDoneRatio() - 0.7f) / 0.3f;\n            canvas.drawRect(0, 0, mWidth, mHeight, mBackPaint);\n            int leftX = (int) (mWidth / 2 - mRadius - 2 * mRadius * fraction);\n            mPath.reset();\n            mPath.moveTo(leftX, PULL_HEIGHT);\n            mPath.quadTo(mWidth / 2, PULL_HEIGHT - (mRadius * (1 - fraction)),\n                    mWidth - leftX, PULL_HEIGHT);\n            canvas.drawPath(mPath, mBallPaint);\n        }\n\n    }\n\n    private int mLastHeight;\n\n    private int getRelHeight() {\n        return (int) (mSpriDeta * (1 - getRelRatio()));\n    }\n\n    private int getSpringDelta() {\n        return (int) (PULL_DELTA * getSprRatio());\n    }\n\n\n    private static long REL_DRAG_DUR = 200;\n\n    private long mStart;\n    private long mStop;\n    private int mSpriDeta;\n\n    public void releaseDrag() {\n        mStart = System.currentTimeMillis();\n        mStop = mStart + REL_DRAG_DUR;\n        mAniStatus = AnimatorStatus.REL_DRAG;\n        mSpriDeta = mHeight - PULL_HEIGHT;\n        requestLayout();\n    }\n\n    private float getRelRatio() {\n        if (System.currentTimeMillis() >= mStop) {\n            springUp();\n            return 1;\n        }\n        float ratio = (System.currentTimeMillis() - mStart) / (float) REL_DRAG_DUR;\n        return Math.min(ratio, 1);\n    }\n\n    private static long SPRING_DUR = 200;\n    private long mSprStart;\n    private long mSprStop;\n\n\n    private void springUp() {\n        mSprStart = System.currentTimeMillis();\n        mSprStop = mSprStart + SPRING_DUR;\n        mAniStatus = AnimatorStatus.SPRING_UP;\n        invalidate();\n    }\n\n\n    private float getSprRatio() {\n        if (System.currentTimeMillis() >= mSprStop) {\n            popBall();\n            return 1;\n        }\n        float ratio = (System.currentTimeMillis() - mSprStart) / (float) SPRING_DUR;\n        return Math.min(1, ratio);\n    }\n\n    private static final long POP_BALL_DUR = 300;\n    private long mPopStart;\n    private long mPopStop;\n\n    private void popBall() {\n        mPopStart = System.currentTimeMillis();\n        mPopStop = mPopStart + POP_BALL_DUR;\n        mAniStatus = AnimatorStatus.POP_BALL;\n        invalidate();\n    }\n\n    private float getPopRatio() {\n        if (System.currentTimeMillis() >= mPopStop) {\n            startOutCir();\n            return 1;\n        }\n\n        float ratio = (System.currentTimeMillis() - mPopStart) / (float) POP_BALL_DUR;\n        return Math.min(ratio, 1);\n    }\n\n    private static final long OUTER_DUR = 200;\n    private long mOutStart;\n    private long mOutStop;\n\n    private void startOutCir() {\n        mOutStart = System.currentTimeMillis();\n        mOutStop = mOutStart + OUTER_DUR;\n        mAniStatus = AnimatorStatus.OUTER_CIR;\n        mRefreshStart = 90;\n        mRefreshStop = 90;\n        TARGET_DEGREE = 270;\n        mIsStart = true;\n        mIsRefreshing = true;\n        invalidate();\n    }\n\n    private float getOutRatio() {\n        if (System.currentTimeMillis() >= mOutStop) {\n            mAniStatus = AnimatorStatus.REFRESHING;\n            mIsRefreshing = true;\n            return 1;\n        }\n        float ratio = (System.currentTimeMillis() - mOutStart) / (float) OUTER_DUR;\n        return Math.min(ratio, 1);\n    }\n\n    private static final long DONE_DUR = 1000;\n    private long mDoneStart;\n    private long mDoneStop;\n\n    private void applyDone() {\n        mDoneStart = System.currentTimeMillis();\n        mDoneStop = mDoneStart + DONE_DUR;\n        mAniStatus = AnimatorStatus.DONE;\n    }\n\n    private float getDoneRatio() {\n        if (System.currentTimeMillis() >= mDoneStop) {\n            mAniStatus = AnimatorStatus.STOP;\n            if (onViewAniDone != null) {\n                onViewAniDone.viewAniDone();\n            }\n            return 1;\n        }\n\n        float ratio = (System.currentTimeMillis() - mDoneStart) / (float) DONE_DUR;\n        return Math.min(ratio, 1);\n    }\n\n\n    private OnViewAniDone onViewAniDone;\n\n    public void setOnViewAniDone(OnViewAniDone onViewAniDone) {\n        this.onViewAniDone = onViewAniDone;\n    }\n\n    interface OnViewAniDone {\n        void viewAniDone();\n    }\n\n\n    public void setAniBackColor(int color) {\n        mBackPaint.setColor(color);\n    }\n\n    public void setAniForeColor(int color) {\n        mBallPaint.setColor(color);\n        mOutPaint.setColor(color);\n        setBackgroundColor(color);\n    }\n\n    // the height of view is smallTimes times of circle radius\n    public void setRadius(int smallTimes) {\n        mRadius = mHeight / smallTimes;\n    }\n\n\n}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/circle/CircleHeader.java",
    "content": "package gorden.krefreshlayout.demo.header.circle;\n\nimport android.animation.ValueAnimator;\nimport android.content.Context;\nimport android.support.annotation.NonNull;\nimport android.view.Gravity;\nimport android.view.View;\nimport android.widget.FrameLayout;\n\nimport org.jetbrains.annotations.NotNull;\n\nimport gorden.krefreshlayout.demo.util.DensityUtil;\nimport gorden.refresh.KRefreshHeader;\nimport gorden.refresh.KRefreshLayout;\n\n/**\n * document\n * Created by Gordn on 2017/6/22.\n */\n\npublic class CircleHeader extends FrameLayout implements KRefreshHeader {\n    AnimationView mHeader;\n    private ValueAnimator mUpTopAnimator;\n    public CircleHeader(@NonNull Context context) {\n        super(context);\n        mHeader = new AnimationView(context);\n        LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, 0);\n        params.gravity = Gravity.TOP;\n        mHeader.setLayoutParams(params);\n        addView(mHeader);\n\n        mHeader.setAniBackColor(0xff8b90af);\n        mHeader.setAniForeColor(0xffffffff);\n        mHeader.setRadius(7);\n\n        mHeader.setOnViewAniDone(new AnimationView.OnViewAniDone() {\n            @Override\n            public void viewAniDone() {\n                mUpTopAnimator.start();\n            }\n        });\n\n        mUpTopAnimator = ValueAnimator.ofFloat(refreshHeight(), 0);\n        mUpTopAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {\n            @Override\n            public void onAnimationUpdate(ValueAnimator animation) {\n                float val = (float) animation.getAnimatedValue();\n                mHeader.getLayoutParams().height = (int) val;\n                mHeader.requestLayout();\n            }\n        });\n        mUpTopAnimator.setDuration(200);\n    }\n    @Override\n    public long succeedRetention() {\n        return 1000;\n    }\n\n    @Override\n    public long failingRetention() {\n        return 0;\n    }\n\n    @Override\n    public int refreshHeight() {\n        return DensityUtil.dip2px(100);\n    }\n\n    @Override\n    public int maxOffsetHeight() {\n        return DensityUtil.dip2px(150);\n    }\n\n    @Override\n    public void onReset(@NotNull KRefreshLayout refreshLayout) {\n\n    }\n\n    @Override\n    public void onPrepare(@NotNull KRefreshLayout refreshLayout) {\n    }\n\n    @Override\n    public void onRefresh(@NotNull KRefreshLayout refreshLayout) {\n        mHeader.releaseDrag();\n    }\n\n    @Override\n    public void onComplete(@NotNull KRefreshLayout refreshLayout, boolean isSuccess) {\n        mHeader.setRefreshing(false);\n    }\n\n    @Override\n    public void onScroll(@NotNull KRefreshLayout refreshLayout, int distance, float percent, boolean refreshing) {\n        if (!refreshing){\n            mHeader.getLayoutParams().height = distance;\n            mHeader.requestLayout();\n        }\n    }\n}\n"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/fungame/BattleCityView.java",
    "content": "package gorden.krefreshlayout.demo.header.fungame;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.Point;\nimport android.graphics.RectF;\nimport android.util.AttributeSet;\nimport android.util.SparseArray;\n\nimport java.util.LinkedList;\nimport java.util.Queue;\nimport java.util.Random;\n\n/**\n * Created by Hitomis on 2016/3/09.\n * email:196425254@qq.com\n */\npublic class BattleCityView extends FunGameView {\n\n    /**\n     * 轨道数量\n     */\n    private static int TANK_ROW_NUM = 3;\n\n    /**\n     * 炮管尺寸所在tank尺寸的比率\n     */\n    private static final float TANK_BARREL_RATIO = 1/3.f;\n\n    /**\n     * 默认子弹之间空隙间距\n     */\n    private static final int DEFAULT_BULLET_NUM_SPACING = 360;\n\n    /**\n     * 默认敌方坦克之间间距\n     */\n    private static final int DEFAULT_ENEMY_TANK_NUM_SPACING = 60;\n\n    /**\n     * 表示运行漏掉的敌方坦克总数量 和 升级后消灭坦克总数量的增量\n     */\n    private static final int DEFAULT_TANK_MAGIC_TOTAL_NUM = 8;\n\n    /**\n     * 所有轨道上敌方坦克矩阵集合\n     */\n    private SparseArray<Queue<RectF>> eTankSparseArray;\n\n    /**\n     * 屏幕上所有子弹坐标点集合\n     */\n    private Queue<Point> mBulletList;\n\n    /**\n     * 击中敌方坦克的子弹坐标点\n     */\n    private Point usedBullet;\n\n    /**\n     * 用于随机定位一个轨道下标值\n     */\n    private Random random;\n\n    /**\n     * 子弹半径\n     */\n    private float bulletRadius;\n\n    /**\n     * 敌方坦克间距、子弹间距\n     */\n    private int enemyTankSpace, bulletSpace;\n\n    /**\n     * 炮筒尺寸\n     */\n    private int barrelSize;\n\n    /**\n     * 敌方坦克速度、子弹速度\n     */\n    private int enemySpeed = 2, bulletSpeed = 7;\n\n    /**\n     * 当前前一辆敌方坦克和后一辆已经存在的间距值\n     * 用于确定是否要派出新的一辆敌方坦克\n     */\n    private int offsetETankX;\n\n    /**\n     * 当前前一颗子弹和后一颗子弹的间距值\n     * 用于确定是否要发射新的一颗子弹\n     */\n    private int  offsetMBulletX;\n\n    /**\n     * 当前漏掉的坦克数量\n     */\n    private int overstepNum;\n\n    /**\n     * 当前难度等级需要消灭坦克数量\n     */\n    private int levelNum;\n\n    /**\n     * 当前难度等级内消灭的敌方坦克数量\n     */\n    private int wipeOutNum;\n\n    /**\n     * 表示第一次标示值，用于添加第一辆敌方坦克逻辑\n     */\n    private boolean once = true;\n\n    public BattleCityView(Context context) {\n        this(context, null);\n    }\n\n    public BattleCityView(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public BattleCityView(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n    }\n\n    @Override\n    protected void initConcreteView() {\n        random = new Random();\n\n        controllerSize = (int) (Math.floor((screenHeight * VIEW_HEIGHT_RATIO - (TANK_ROW_NUM + 1) * DIVIDING_LINE_SIZE) / TANK_ROW_NUM + .5f));\n        barrelSize = (int) Math.floor(controllerSize * TANK_BARREL_RATIO + .5f);\n        bulletRadius = (barrelSize - 2 * DIVIDING_LINE_SIZE) * .5f;\n\n        resetConfigParams();\n    }\n\n    @Override\n    protected void drawGame(Canvas canvas) {\n        drawSelfTank(canvas);\n\n        if (status == STATUS_GAME_PLAY || status == STATUS_GAME_FINISHED) {\n            drawEnemyTank(canvas);\n            makeBulletPath(canvas);\n        }\n    }\n\n    @Override\n    protected void resetConfigParams() {\n        controllerPosition = DIVIDING_LINE_SIZE;\n\n        status = FunGameView.STATUS_GAME_PREPAR;\n\n        enemySpeed = 2;\n        bulletSpeed = 7;\n\n        levelNum = DEFAULT_TANK_MAGIC_TOTAL_NUM;\n        wipeOutNum = 0;\n\n        once = true;\n\n        enemyTankSpace = controllerSize + barrelSize + DEFAULT_ENEMY_TANK_NUM_SPACING;\n        bulletSpace = DEFAULT_BULLET_NUM_SPACING;\n\n        eTankSparseArray = new SparseArray<>();\n        for (int i = 0; i < TANK_ROW_NUM; i++) {\n            Queue<RectF> rectFQueue = new LinkedList<>();\n            eTankSparseArray.put(i, rectFQueue);\n        }\n\n        mBulletList = new LinkedList<>();\n    }\n\n    /**\n     * 由index轨道下标从左边起始位置生成一个用于绘制敌方坦克的Rect\n     * @param index 轨道下标\n     * @return 敌方坦克矩阵\n     */\n    private RectF generateEnemyTank(int index) {\n        float left = - (controllerSize + barrelSize);\n        float top = index * (controllerSize + DIVIDING_LINE_SIZE) + DIVIDING_LINE_SIZE;\n        return new RectF(left, top, left + barrelSize * 2.5f, top + controllerSize);\n    }\n\n    /**\n     * 绘制子弹路径\n     * @param canvas 默认画布\n     */\n    private void makeBulletPath(Canvas canvas) {\n        mPaint.setColor(mModelColor);\n        offsetMBulletX += bulletSpeed;\n        if (offsetMBulletX / bulletSpace == 1) {\n            offsetMBulletX = 0;\n        }\n\n        if (offsetMBulletX == 0) {\n            Point bulletPoint = new Point();\n            bulletPoint.x = screenWidth - controllerSize - barrelSize;\n            bulletPoint.y = (int) (controllerPosition + controllerSize * .5f);\n            mBulletList.offer(bulletPoint);\n        }\n\n        boolean isOversetp = false;\n        for (Point point : mBulletList) {\n            if (checkWipeOutETank(point)) {\n                usedBullet = point;\n                continue;\n            }\n            if (point.x + bulletRadius <= 0) {\n                isOversetp = true;\n            }\n            drawBullet(canvas, point);\n        }\n\n        if (isOversetp) {\n            mBulletList.poll();\n        }\n\n        mBulletList.remove(usedBullet);\n        usedBullet = null;\n    }\n\n    /**\n     * 由Y坐标获取该坐标所在轨道的下标\n     * @param y 坐标Y值\n     * @return 轨道下标\n     */\n    private int getTrackIndex(int y) {\n        int index = y / (getMeasuredHeight() / TANK_ROW_NUM);\n        index = index >= TANK_ROW_NUM ? TANK_ROW_NUM - 1 : index;\n        index = index < 0 ? 0 : index;\n        return  index;\n    }\n\n    /**\n     * 判断是否消灭敌方坦克\n     * @param point 单签子弹坐标点\n     * @return 消灭：true, 反之：false\n     */\n    private boolean checkWipeOutETank(Point point) {\n        boolean beHit = false;\n        int trackIndex = getTrackIndex(point.y);\n        RectF rectF = eTankSparseArray.get(trackIndex).peek();\n        if (rectF != null && rectF.contains(point.x, point.y)) { // 击中\n            if (++wipeOutNum == levelNum) {\n                upLevel();\n            }\n            eTankSparseArray.get(trackIndex).poll();\n            beHit = true;\n        }\n        return beHit;\n    }\n\n    /**\n     * 难度升级\n     */\n    private void upLevel() {\n        levelNum += DEFAULT_TANK_MAGIC_TOTAL_NUM;\n        enemySpeed++;\n        bulletSpeed += 2;\n        wipeOutNum = 0;\n\n        if (enemyTankSpace > 12)\n            enemyTankSpace -= 12;\n\n        if (bulletSpace > 30)\n            bulletSpace -= 30;\n    }\n\n    /**\n     * 绘制子弹\n     * @param canvas 默认画布\n     * @param point 子弹圆心坐标点\n     */\n    private void drawBullet(Canvas canvas, Point point) {\n        point.x -= bulletSpeed;\n        canvas.drawCircle(point.x, point.y, bulletRadius, mPaint);\n    }\n\n    /**\n     * 判断我方坦克是否与敌方坦克相撞\n     * @param index 轨道下标\n     * @param selfX 我方坦克所在坐标X值\n     * @param selfY 我方坦克矩阵的top 或者 bottom 值\n     * @return true：相撞，反之：false\n     */\n    private boolean checkTankCrash(int index, float selfX, float selfY) {\n        boolean isCrash = false;\n        RectF rectF = eTankSparseArray.get(index).peek();\n        if (rectF != null && rectF.contains(selfX, selfY)) {\n            isCrash = true;\n        }\n        return isCrash;\n    }\n\n    /**\n     * 绘制我方坦克\n     * @param canvas 默认画布\n     */\n    private void drawSelfTank(Canvas canvas) {\n        mPaint.setColor(rModelColor);\n        boolean isAboveCrash = checkTankCrash(getTrackIndex((int) controllerPosition),\n                screenWidth - controllerSize,\n                controllerPosition);\n        boolean isBelowCrash = checkTankCrash(getTrackIndex((int) (controllerPosition + controllerSize)),\n                screenWidth - controllerSize,\n                controllerPosition + controllerSize);\n\n        if (isAboveCrash || isBelowCrash) {\n            status = STATUS_GAME_OVER;\n        }\n\n        canvas.drawRect(screenWidth - controllerSize,\n                controllerPosition,\n                screenWidth,\n                controllerPosition + controllerSize,\n                mPaint);\n        canvas.drawRect(screenWidth - controllerSize - barrelSize,\n                controllerPosition + (controllerSize - barrelSize) * .5f,\n                screenWidth - controllerSize,\n                controllerPosition + (controllerSize - barrelSize) * .5f + barrelSize,\n                mPaint);\n    }\n\n    /**\n     * 绘制三条轨道上的敌方坦克\n     * @param canvas 默认画布\n     */\n    private void drawEnemyTank(Canvas canvas) {\n        mPaint.setColor(lModelColor);\n        offsetETankX += enemySpeed;\n        if (offsetETankX / enemyTankSpace == 1 || once) {\n            offsetETankX = 0;\n            once = false;\n        }\n\n        boolean isOverstep = false;\n        int option = apperanceOption();\n        for (int i = 0; i < TANK_ROW_NUM; i++) {\n            Queue<RectF> rectFQueue = eTankSparseArray.get(i);\n\n            if (offsetETankX == 0 && i == option) {\n                rectFQueue.offer(generateEnemyTank(i));\n            }\n\n            for (RectF rectF : rectFQueue) {\n                if (rectF.left >= screenWidth) {\n                    isOverstep = true;\n                    if (++overstepNum >= DEFAULT_TANK_MAGIC_TOTAL_NUM) {\n                        status = STATUS_GAME_OVER;\n                        break;\n                    }\n                    continue;\n                }\n                drawTank(canvas, rectF);\n            }\n\n            if (status == STATUS_GAME_OVER) break;\n            if (isOverstep) {\n                rectFQueue.poll();\n                isOverstep = false;\n            }\n        }\n        invalidate();\n    }\n\n    /**\n     * 绘制一辆敌方坦克\n     * @param canvas 默认画布\n     * @param rectF 坦克矩阵\n     */\n    private void drawTank(Canvas canvas, RectF rectF) {\n        rectF.set(rectF.left + enemySpeed, rectF.top, rectF.right + enemySpeed, rectF.bottom);\n        canvas.drawRect(rectF, mPaint);\n        float barrelTop = rectF.top + (controllerSize - barrelSize) * .5f;\n        canvas.drawRect(rectF.right, barrelTop, rectF.right + barrelSize, barrelTop + barrelSize, mPaint);\n\n    }\n\n    /**\n     * 随机定位一个轨道下标值\n     * @return 轨道下标\n     */\n    private int apperanceOption() {\n        return random.nextInt(TANK_ROW_NUM);\n    }\n\n}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/fungame/FunGameFactory.java",
    "content": "package gorden.krefreshlayout.demo.header.fungame;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\n\n/**\n * Created by Hitomis on 2016/3/10.\n * email:196425254@qq.com\n */\npublic class FunGameFactory {\n\n    // Refused to use enum\n\n    static final int HITBLOCK = 0;\n\n    static final int BATTLECITY = 1;\n\n    static FunGameView createFunGameView(Context context, AttributeSet attributeSet, int type) {\n        FunGameView funGameView = null;\n        switch (type) {\n            case HITBLOCK:\n                funGameView = new HitBlockView(context, attributeSet);\n                break;\n            case BATTLECITY:\n                funGameView = new BattleCityView(context, attributeSet);\n                break;\n            default:\n                funGameView = new HitBlockView(context, attributeSet);\n        }\n        return funGameView;\n    }\n}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/fungame/FunGameHeader.java",
    "content": "package gorden.krefreshlayout.demo.header.fungame;\n\nimport android.animation.Animator;\nimport android.animation.AnimatorListenerAdapter;\nimport android.animation.AnimatorSet;\nimport android.animation.ObjectAnimator;\nimport android.content.Context;\nimport android.graphics.Color;\nimport android.util.AttributeSet;\nimport android.view.Gravity;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.ViewTreeObserver;\nimport android.widget.FrameLayout;\nimport android.widget.RelativeLayout;\nimport android.widget.TextView;\n\nimport org.jetbrains.annotations.NotNull;\n\nimport gorden.refresh.KRefreshHeader;\nimport gorden.refresh.KRefreshLayout;\n\n\n/**\n * Created by Hitomis on 2016/3/1.\n */\npublic class FunGameHeader extends FrameLayout implements KRefreshHeader {\n\n    private Context mContext;\n\n    private int headerType;\n\n    private FunGameView funGameView;\n\n    private RelativeLayout curtainReLayout, maskReLayout;\n\n    private TextView topMaskView, bottomMaskView;\n\n    private int halfHitBlockHeight;\n\n    private boolean isStart = false;\n\n    private String topMaskViewText = \"Pull To Break Out!\";\n    private String bottomMaskViewText = \"Scrooll to move handle\";\n    private String loadingText = \"Loading...\";\n    private String loadingFinishedText = \"Loading Finished\";\n    private String gameOverText = \"Game Over\";\n\n    private int topMaskTextSize = 16;\n\n    private int bottomMaskTextSize = 16;\n\n    public FunGameHeader(Context context) {\n        this(context, null);\n    }\n\n    public FunGameHeader(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public FunGameHeader(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        mContext = context;\n        headerType = FunGameFactory.HITBLOCK;\n        initView(attrs);\n    }\n\n    private void initView(AttributeSet attrs) {\n        funGameView = FunGameFactory.createFunGameView(mContext, attrs, headerType);\n        setHeaderLodingStr(loadingText);\n        setHeaderLoadingFinishedStr(loadingFinishedText);\n        setHeaderGameOverStr(gameOverText);\n        funGameView.postStatus(FunGameView.STATUS_GAME_PREPAR);\n        addView(funGameView);\n\n        curtainReLayout = new RelativeLayout(mContext);\n        maskReLayout = new RelativeLayout(mContext);\n        maskReLayout.setBackgroundColor(Color.parseColor(\"#3A3A3A\"));\n\n        topMaskView = createMaskTextView(topMaskViewText, topMaskTextSize, Gravity.BOTTOM);\n        bottomMaskView = createMaskTextView(bottomMaskViewText, bottomMaskTextSize, Gravity.TOP);\n\n        coverMaskView();\n\n        funGameView.getViewTreeObserver().addOnGlobalLayoutListener(new MeasureListener());\n    }\n\n    private TextView createMaskTextView(String text, int textSize, int gravity) {\n        TextView maskTextView = new TextView(mContext);\n        maskTextView.setTextColor(Color.BLACK);\n        maskTextView.setBackgroundColor(Color.WHITE);\n        maskTextView.setGravity(gravity | Gravity.CENTER_HORIZONTAL);\n        maskTextView.setTextSize(textSize);\n        maskTextView.setText(text);\n        return maskTextView;\n    }\n\n    private void coverMaskView() {\n        LayoutParams maskLp = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);\n        maskLp.topMargin = (int) FunGameView.DIVIDING_LINE_SIZE;\n        maskLp.bottomMargin = (int) FunGameView.DIVIDING_LINE_SIZE;\n\n        addView(maskReLayout, maskLp);\n        addView(curtainReLayout, maskLp);\n    }\n\n    @Override\n    public long succeedRetention() {\n        return 200;\n    }\n\n    @Override\n    public long failingRetention() {\n        return 0;\n    }\n\n    @Override\n    public int refreshHeight() {\n        return getHeight();\n    }\n\n    @Override\n    public int maxOffsetHeight() {\n        return 2 * getHeight();\n    }\n\n    @Override\n    public void onReset(@NotNull KRefreshLayout refreshLayout) {\n        postEnd();\n    }\n\n    @Override\n    public void onPrepare(@NotNull KRefreshLayout refreshLayout) {\n\n    }\n\n    @Override\n    public void onRefresh(@NotNull KRefreshLayout refreshLayout) {\n        postStart();\n    }\n\n    @Override\n    public void onComplete(@NotNull KRefreshLayout refreshLayout, boolean isSuccess) {\n        postComplete();\n    }\n\n    @Override\n    public void onScroll(@NotNull KRefreshLayout refreshLayout, int distance, float percent, boolean refreshing) {\n        if (refreshing) {\n            moveRacket(distance - refreshHeight());\n        }\n    }\n\n    private class MeasureListener implements ViewTreeObserver.OnGlobalLayoutListener {\n\n        @Override\n        public void onGlobalLayout() {\n            halfHitBlockHeight = (int) ((funGameView.getHeight() - 2 * FunGameView.DIVIDING_LINE_SIZE) * .5f);\n            RelativeLayout.LayoutParams topRelayLayoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, halfHitBlockHeight);\n            RelativeLayout.LayoutParams bottomRelayLayoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, halfHitBlockHeight);\n            bottomRelayLayoutParams.topMargin = halfHitBlockHeight;\n\n            curtainReLayout.removeAllViews();\n            curtainReLayout.addView(topMaskView, 0, topRelayLayoutParams);\n            curtainReLayout.addView(bottomMaskView, 1, bottomRelayLayoutParams);\n\n            getViewTreeObserver().removeGlobalOnLayoutListener(this);\n        }\n    }\n\n    private void doStart(long delay) {\n        ObjectAnimator topMaskAnimator = ObjectAnimator.ofFloat(topMaskView, \"translationY\", topMaskView.getTranslationY(), -halfHitBlockHeight);\n        ObjectAnimator bottomMaskAnimator = ObjectAnimator.ofFloat(bottomMaskView, \"translationY\", bottomMaskView.getTranslationY(), halfHitBlockHeight);\n        ObjectAnimator maskShadowAnimator = ObjectAnimator.ofFloat(maskReLayout, \"alpha\", maskReLayout.getAlpha(), 0);\n\n        AnimatorSet animatorSet = new AnimatorSet();\n        animatorSet.play(topMaskAnimator).with(bottomMaskAnimator).with(maskShadowAnimator);\n        animatorSet.setDuration(800);\n        animatorSet.setStartDelay(delay);\n        animatorSet.start();\n\n        animatorSet.addListener(new AnimatorListenerAdapter() {\n            @Override\n            public void onAnimationEnd(Animator animation) {\n                topMaskView.setVisibility(View.GONE);\n                bottomMaskView.setVisibility(View.GONE);\n                maskReLayout.setVisibility(View.GONE);\n\n                funGameView.postStatus(FunGameView.STATUS_GAME_PLAY);\n            }\n        });\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);\n        int width = 0, height = 0;\n\n        int count = getChildCount();\n        for (int i = 0; i < count; i++) {\n            View childView = getChildAt(i);\n            measureChild(childView, widthMeasureSpec, heightMeasureSpec);\n            if (childView instanceof FunGameView) {\n                width = childView.getMeasuredWidth();\n                height = childView.getMeasuredHeight();\n            }\n        }\n\n        if (heightMode == MeasureSpec.UNSPECIFIED || heightMode == MeasureSpec.EXACTLY) {\n            widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);\n            heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);\n        }\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n    }\n\n    public void postStart() {\n        if (!isStart) {\n            doStart(200);\n            isStart = true;\n        }\n    }\n\n    public void postEnd() {\n        isStart = false;\n        funGameView.postStatus(FunGameView.STATUS_GAME_PREPAR);\n\n        topMaskView.setTranslationY(topMaskView.getTranslationY() + halfHitBlockHeight);\n        bottomMaskView.setTranslationY(bottomMaskView.getTranslationY() - halfHitBlockHeight);\n        maskReLayout.setAlpha(1.f);\n\n        topMaskView.setVisibility(View.VISIBLE);\n        bottomMaskView.setVisibility(View.VISIBLE);\n        maskReLayout.setVisibility(View.VISIBLE);\n    }\n\n    public void postComplete() {\n        funGameView.postStatus(FunGameView.STATUS_GAME_FINISHED);\n    }\n\n    public void moveRacket(float distance) {\n        if (isStart)\n            funGameView.moveController(distance);\n    }\n\n    public void back2StartPoint(long duration) {\n        funGameView.moveController2StartPoint(duration);\n    }\n\n    public int getGameStatus() {\n        return funGameView.getCurrStatus();\n    }\n\n    public void setTopMaskViewText(String topMaskViewText) {\n        this.topMaskViewText = topMaskViewText;\n        topMaskView.setText(topMaskViewText);\n    }\n\n    public void setBottomMaskViewText(String bottomMaskViewText) {\n        this.bottomMaskViewText = bottomMaskViewText;\n        bottomMaskView.setText(bottomMaskViewText);\n    }\n\n    public void setHeaderLodingStr(String loadingStr) {\n        funGameView.setTextLoading(loadingStr);\n    }\n\n    public void setHeaderGameOverStr(String gameOverStr) {\n        funGameView.setTextGameOver(gameOverStr);\n    }\n\n    public void setHeaderLoadingFinishedStr(String loadingFinishedStr) {\n        funGameView.setTextLoadingFinished(loadingFinishedStr);\n    }\n\n}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/fungame/FunGameView.java",
    "content": "package gorden.krefreshlayout.demo.header.fungame;\n\nimport android.animation.ValueAnimator;\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.text.TextPaint;\nimport android.util.AttributeSet;\nimport android.util.DisplayMetrics;\nimport android.view.View;\nimport android.view.WindowManager;\nimport android.view.animation.AccelerateDecelerateInterpolator;\n\n\n/**\n * Created by Hitomis on 2016/3/9.\n * email:196425254@qq.com\n */\nabstract class FunGameView extends View {\n\n    static final int STATUS_GAME_PREPAR = 0;\n\n    static final int STATUS_GAME_PLAY = 1;\n\n    static final int STATUS_GAME_OVER = 2;\n\n    static final int STATUS_GAME_FINISHED = 3;\n\n    /**\n     * 分割线默认宽度大小\n     */\n    static final float DIVIDING_LINE_SIZE = 1.f;\n\n    /**\n     * 控件高度占屏幕高度比率\n     */\n    static final float VIEW_HEIGHT_RATIO = .161f;\n\n    private String textGameOver;\n    private String textLoading;\n    private String textLoadingFinished;\n\n    protected Paint mPaint;\n\n    protected TextPaint textPaint;\n\n    protected float controllerPosition;\n\n    protected int controllerSize;\n\n    protected int screenWidth, screenHeight;\n\n    protected int status = STATUS_GAME_PREPAR;\n\n    protected int lModelColor, rModelColor, mModelColor;\n\n    public FunGameView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n\n        lModelColor =Color.rgb(0, 0, 0);\n        mModelColor =Color.BLACK;\n        rModelColor =Color.parseColor(\"#A5A5A5\");\n\n        initBaseTools();\n        initBaseConfigParams(context);\n        initConcreteView();\n    }\n\n    protected void initBaseTools() {\n        textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);\n        textPaint.setColor(Color.parseColor(\"#C1C2C2\"));\n\n        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n        mPaint.setStrokeWidth(1.f);\n    }\n\n    protected void initBaseConfigParams(Context context) {\n        controllerPosition = DIVIDING_LINE_SIZE;\n\n        screenWidth = getScreenMetrics(context).widthPixels;\n        screenHeight = getScreenMetrics(context).heightPixels;\n    }\n\n    protected abstract void initConcreteView();\n\n    protected abstract void drawGame(Canvas canvas);\n\n    protected abstract void resetConfigParams();\n\n    /**\n     * 绘制分割线\n     * @param canvas 默认画布\n     */\n    private void drawBoundary(Canvas canvas) {\n        mPaint.setColor(Color.parseColor(\"#606060\"));\n        canvas.drawLine(0, 0, screenWidth, 0, mPaint);\n        canvas.drawLine(0, getMeasuredHeight(), screenWidth, getMeasuredHeight(), mPaint);\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        setMeasuredDimension(screenWidth, (int) (screenHeight * VIEW_HEIGHT_RATIO));\n    }\n\n    @Override\n    protected void onDraw(Canvas canvas) {\n        drawBoundary(canvas);\n        drawText(canvas);\n        drawGame(canvas);\n    }\n\n    /**\n     * 绘制文字内容\n     * @param canvas 默认画布\n     */\n    private void drawText(Canvas canvas) {\n        switch (status) {\n            case STATUS_GAME_PREPAR:\n            case STATUS_GAME_PLAY:\n                textPaint.setTextSize(50);\n                promptText(canvas, textLoading);\n                break;\n            case STATUS_GAME_FINISHED:\n                textPaint.setTextSize(40);\n                promptText(canvas, textLoadingFinished);\n                break;\n            case STATUS_GAME_OVER:\n                textPaint.setTextSize(50);\n                promptText(canvas, textGameOver);\n                break;\n        }\n    }\n\n    /**\n     * 提示文字信息\n     * @param canvas 默认画布\n     * @param text 相关文字字符串\n     */\n    private void promptText(Canvas canvas, String text) {\n        float textX = (canvas.getWidth() - textPaint.measureText(text)) * .5f;\n        float textY = canvas.getHeight()  * .5f - (textPaint.ascent() + textPaint.descent()) * .5f;\n        canvas.drawText(text, textX, textY, textPaint);\n    }\n\n\n    /**\n     * 移动控制器（控制器对象为具体控件中的右边图像模型）\n     * @param distance 移动的距离\n     */\n    public void moveController(float distance) {\n        float maxDistance = (getMeasuredHeight() -  2 * DIVIDING_LINE_SIZE - controllerSize);\n\n        if (distance > maxDistance) {\n            distance = maxDistance;\n        }\n\n        controllerPosition = distance;\n        postInvalidate();\n    }\n\n    /**\n     * 移动控制器到起点位置\n     * @param duration\n     */\n    public void moveController2StartPoint(long duration) {\n        ValueAnimator moveAnimator = ValueAnimator.ofFloat(controllerPosition, DIVIDING_LINE_SIZE);\n        moveAnimator.setDuration(duration);\n        moveAnimator.setInterpolator(new AccelerateDecelerateInterpolator());\n        moveAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {\n            @Override\n            public void onAnimationUpdate(ValueAnimator animation) {\n                controllerPosition = Float.parseFloat(animation.getAnimatedValue().toString());\n                postInvalidate();\n            }\n        });\n        moveAnimator.start();\n    }\n\n    /**\n     * 更新当前控件状态\n     * @param status 状态码\n     */\n    public void postStatus(int status) {\n        this.status = status;\n\n        if (status == STATUS_GAME_PREPAR) {\n            resetConfigParams();\n        }\n\n        postInvalidate();\n    }\n\n    /**\n     * 获取当前控件状态\n     * @return\n     */\n    public int getCurrStatus() {\n        return status;\n    }\n\n    public String getTextGameOver() {\n        return textGameOver;\n    }\n\n    public void setTextGameOver(String textGameOver) {\n        this.textGameOver = textGameOver;\n    }\n\n    public String getTextLoading() {\n        return textLoading;\n    }\n\n    public void setTextLoading(String textLoading) {\n        this.textLoading = textLoading;\n    }\n\n    public String getTextLoadingFinished() {\n        return textLoadingFinished;\n    }\n\n    public void setTextLoadingFinished(String textLoadingFinished) {\n        this.textLoadingFinished = textLoadingFinished;\n    }\n\n    /**\n     * 获取屏幕尺寸\n     *\n     * @param context context\n     * @return 手机屏幕尺寸\n     */\n    private DisplayMetrics getScreenMetrics(Context context) {\n        WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);\n        DisplayMetrics dm = new DisplayMetrics();\n        manager.getDefaultDisplay().getMetrics(dm);\n        return dm;\n    }\n}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/fungame/HitBlockView.java",
    "content": "package gorden.krefreshlayout.demo.header.fungame;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\nimport android.graphics.Point;\nimport android.util.AttributeSet;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Created by Hitomis on 2016/2/29.\n * email:196425254@qq.com\n */\npublic class HitBlockView extends FunGameView {\n\n    /**\n     * 默认矩形块竖向排列的数目\n     */\n    private static final int BLOCK_VERTICAL_NUM = 5;\n\n    /**\n     * 默认矩形块横向排列的数目\n     */\n    private static final int BLOCK_HORIZONTAL_NUM = 3;\n\n    /**\n     * 矩形块的高度占屏幕高度比率\n     */\n    private static final float BLOCK_HEIGHT_RATIO = .03125f;\n\n    /**\n     * 矩形块的宽度占屏幕宽度比率\n     */\n    private static final float BLOCK_WIDTH_RATIO = .01806f;\n\n    /**\n     * 挡板所在位置占屏幕宽度的比率\n     */\n    private static final float RACKET_POSITION_RATIO = .8f;\n\n    /**\n     * 矩形块所在位置占屏幕宽度的比率\n     */\n    private static final float BLOCK_POSITION_RATIO = .08f;\n\n    /**\n     * 小球默认其实弹射角度\n     */\n    private static final int DEFAULT_ANGLE = 30;\n\n    /**\n     * 分割线默认宽度大小\n     */\n    static final float DIVIDING_LINE_SIZE = 1.f;\n\n    /**\n     * 小球移动速度\n     */\n    private static final int SPEED = 6;\n\n    /**\n     * 矩形砖块的高度、宽度\n     */\n    private float blockHeight, blockWidth;\n\n    /**\n     * 小球半径\n     */\n    private static final float BALL_RADIUS = 8.f;\n\n    private Paint blockPaint;\n\n    private float blockLeft, racketLeft;\n\n    private float cx, cy;\n\n    private List<Point> pointList;\n\n    private boolean isleft;\n\n    private int angle;\n\n    private int blockHorizontalNum;\n\n    private int speed;\n\n    public HitBlockView(Context context) {\n        this(context, null);\n    }\n\n    public HitBlockView(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public HitBlockView(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n        initAttrs(context, attrs);\n    }\n\n    private void initAttrs(Context context, AttributeSet attrs) {\n        blockHorizontalNum = BLOCK_HORIZONTAL_NUM;\n        speed = SPEED;\n    }\n\n    @Override\n    protected void initConcreteView() {\n        blockPaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n        blockPaint.setStyle(Paint.Style.FILL);\n\n        blockHeight = screenHeight * BLOCK_HEIGHT_RATIO;\n        blockWidth = screenWidth * BLOCK_WIDTH_RATIO;\n\n        blockLeft = screenWidth * BLOCK_POSITION_RATIO;\n        racketLeft = screenWidth * RACKET_POSITION_RATIO;\n\n        controllerSize = (int) (blockHeight * 1.6f);\n    }\n\n    @Override\n    protected void drawGame(Canvas canvas) {\n        drawColorBlock(canvas);\n        drawRacket(canvas);\n\n        if (status == STATUS_GAME_PLAY || status == STATUS_GAME_FINISHED)\n            makeBallPath(canvas);\n    }\n\n    @Override\n    protected void resetConfigParams() {\n        cx = racketLeft - 2 * BALL_RADIUS;\n        cy = (int) (getHeight() * .5f);\n\n        controllerPosition = DIVIDING_LINE_SIZE;\n\n        angle = DEFAULT_ANGLE;\n\n        isleft = true;\n\n        if (pointList == null) {\n            pointList = new ArrayList<>();\n        } else {\n            pointList.clear();\n        }\n    }\n\n    /**\n     * 绘制挡板\n     * @param canvas 默认画布\n     */\n    private void drawRacket(Canvas canvas) {\n        mPaint.setColor(rModelColor);\n        canvas.drawRect(racketLeft, controllerPosition, racketLeft + blockWidth, controllerPosition + controllerSize, mPaint);\n    }\n\n    /**\n     * 绘制并处理小球运动的轨迹\n     * @param canvas 默认画布\n     */\n    private void makeBallPath(Canvas canvas) {\n        mPaint.setColor(mModelColor);\n\n        if (cx <= blockLeft +  blockHorizontalNum * blockWidth + (blockHorizontalNum - 1) * DIVIDING_LINE_SIZE + BALL_RADIUS) { // 小球进入到色块区域\n            if (checkTouchBlock(cx, cy)) { // 反弹回来\n                isleft = false;\n            }\n        }\n        if (cx <= blockLeft + BALL_RADIUS ) { // 小球穿过色块区域\n            isleft = false;\n        }\n\n        if (cx + BALL_RADIUS >= racketLeft && cx - BALL_RADIUS < racketLeft + blockWidth) { //小球当前坐标X值在挡板X值区域范围内\n            if (checkTouchRacket(cy)) { // 小球与挡板接触\n                if (pointList.size() == blockHorizontalNum * BLOCK_VERTICAL_NUM) { // 矩形块全部被消灭，游戏结束\n                    status = STATUS_GAME_OVER;\n                    return;\n                }\n                isleft = true;\n            }\n        } else if (cx > canvas.getWidth()) { // 小球超出挡板区域\n            status = STATUS_GAME_OVER;\n        }\n\n        if (cy <= BALL_RADIUS + DIVIDING_LINE_SIZE) { // 小球撞到上边界\n            angle = 180 - DEFAULT_ANGLE;\n        } else if (cy >= getMeasuredHeight() - BALL_RADIUS - DIVIDING_LINE_SIZE) { // 小球撞到下边界\n            angle = 180 + DEFAULT_ANGLE;\n        }\n\n\n        if (isleft) {\n            cx -= speed;\n        } else {\n            cx += speed;\n        }\n        cy -= (float) Math.tan(Math.toRadians(angle)) * speed;\n\n        canvas.drawCircle(cx, cy, BALL_RADIUS, mPaint);\n\n        invalidate();\n\n    }\n\n    /**\n     * 检查小球是否撞击到挡板\n     * @param y 小球当前坐标Y值\n     * @return 小球位于挡板Y值区域范围内：true，反之：false\n     */\n    private boolean checkTouchRacket(float y) {\n        boolean flag = false;\n        float diffVal = y - controllerPosition;\n        if (diffVal >= 0 && diffVal <= controllerSize) { // 小球位于挡板Y值区域范围内\n            flag = true;\n        }\n        return flag;\n    }\n\n    /**\n     * 检查小球是否撞击到矩形块\n     * @param x 小球坐标X值\n     * @param y 小球坐标Y值\n     * @return 撞击到：true，反之：false\n     */\n    private boolean checkTouchBlock(float x, float y) {\n        int columnX = (int) ((x - blockLeft - BALL_RADIUS - speed ) / blockWidth);\n        columnX = columnX == blockHorizontalNum ? columnX - 1 : columnX;\n        int rowY = (int) (y / blockHeight);\n        rowY = rowY == BLOCK_VERTICAL_NUM ? rowY - 1 : rowY;\n        Point p = new Point();\n        p.set(columnX, rowY);\n\n        boolean flag = false;\n        for (Point point : pointList) {\n            if (point.equals(p.x, p.y)) {\n                flag = true;\n                break;\n            }\n        }\n\n        if (!flag) {\n            pointList.add(p);\n        }\n        return !flag;\n    }\n\n    /**\n     * 绘制矩形色块\n     * @param canvas 默认画布\n     */\n    private void drawColorBlock(Canvas canvas) {\n        float left, top;\n        int column, row, redCode, greenCode, blueCode;\n        for (int i = 0; i < blockHorizontalNum * BLOCK_VERTICAL_NUM; i++) {\n            row = i / blockHorizontalNum;\n            column = i % blockHorizontalNum;\n\n            boolean flag = false;\n            for (Point point : pointList) {\n                if (point.equals(column, row)) {\n                    flag = true;\n                    break;\n                }\n            }\n            if (flag) {\n                continue;\n            }\n\n            redCode = 255 - (255 - Color.red(lModelColor)) / (column + 1);\n            greenCode = 255 - (255 - Color.green(lModelColor)) / (column + 1);\n            blueCode = 255 - (255 - Color.blue(lModelColor)) / (column + 1);\n            blockPaint.setColor(Color.rgb(redCode, greenCode, blueCode));\n\n            left = blockLeft + column * (blockWidth + DIVIDING_LINE_SIZE);\n            top = DIVIDING_LINE_SIZE + row * (blockHeight + DIVIDING_LINE_SIZE);\n            canvas.drawRect(left, top, left + blockWidth, top + blockHeight, blockPaint);\n        }\n    }\n\n}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/materia/CircleImageView.java",
    "content": "package gorden.krefreshlayout.demo.header.materia;\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 *\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}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/materia/MateriaProgressHeader.java",
    "content": "package gorden.krefreshlayout.demo.header.materia;\n\nimport android.content.Context;\nimport android.content.res.Resources;\nimport android.graphics.Color;\nimport android.support.annotation.ColorInt;\nimport android.support.annotation.ColorRes;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.support.v4.view.ViewCompat;\nimport android.util.AttributeSet;\nimport android.util.DisplayMetrics;\nimport android.view.Gravity;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.FrameLayout;\n\nimport org.jetbrains.annotations.NotNull;\n\nimport gorden.krefreshlayout.demo.R;\nimport gorden.refresh.KRefreshHeader;\nimport gorden.refresh.KRefreshLayout;\n\n/**\n * document\n * Created by Gordn on 2017/6/20.\n */\n\npublic class MateriaProgressHeader extends FrameLayout implements KRefreshHeader {\n\n    private int mCircleWidth;\n    private int mCircleHeight;\n    private static final int CIRCLE_DIAMETER = 40;\n    private static final int CIRCLE_DIAMETER_LARGE = 56;\n    // Maps to ProgressBar.Large style\n    public static final int LARGE = MaterialProgressDrawable.LARGE;\n    // Maps to ProgressBar default style\n    public static final int DEFAULT = MaterialProgressDrawable.DEFAULT;\n    // Default background for the progress spinner\n    private static final int CIRCLE_BG_LIGHT = 0xFFFAFAFA;\n    // Default offset in dips from the top of the view to where the progress spinner should stop\n    private static final int DEFAULT_CIRCLE_TARGET = 64;\n    private static final float MAX_PROGRESS_ANGLE = .8f;\n\n    private static final int MAX_ALPHA = 255;\n    private static final int STARTING_PROGRESS_ALPHA = (int) (.3f * MAX_ALPHA);\n\n    private CircleImageView mCircleView;\n    private MaterialProgressDrawable mProgress;\n\n    public MateriaProgressHeader(@NonNull Context context) {\n        this(context, null);\n    }\n\n    public MateriaProgressHeader(@NonNull Context context, @Nullable AttributeSet attrs) {\n        super(context, attrs);\n        final DisplayMetrics metrics = getResources().getDisplayMetrics();\n        mCircleWidth = (int) (CIRCLE_DIAMETER * metrics.density);\n        mCircleHeight = (int) (CIRCLE_DIAMETER * metrics.density);\n        createProgressView();\n        ViewCompat.setChildrenDrawingOrderEnabled(this, true);\n\n        setColorSchemeColors(getResources().getIntArray(R.array.refresh_color));\n    }\n\n    private void createProgressView() {\n        mCircleView = new CircleImageView(getContext(), CIRCLE_BG_LIGHT, CIRCLE_DIAMETER / 2);\n        mProgress = new MaterialProgressDrawable(getContext(), this);\n        mProgress.setBackgroundColor(CIRCLE_BG_LIGHT);\n        mCircleView.setImageDrawable(mProgress);\n        mCircleView.setVisibility(View.GONE);\n        LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER);\n        mCircleView.setLayoutParams(params);\n        addView(mCircleView);\n    }\n\n    /**\n     * Set the background color of the progress spinner disc.\n     *\n     * @param color\n     */\n    public void setProgressBackgroundColorSchemeColor(@ColorInt int color) {\n        mCircleView.setBackgroundColor(color);\n        mProgress.setBackgroundColor(color);\n    }\n\n    public void setColorSchemeResources(@ColorRes int... colorResIds) {\n        final Resources res = getResources();\n        int[] colorRes = new int[colorResIds.length];\n        for (int i = 0; i < colorResIds.length; i++) {\n            colorRes[i] = res.getColor(colorResIds[i]);\n        }\n        setColorSchemeColors(colorRes);\n    }\n\n    public void setColorSchemeColors(int... colors) {\n        mProgress.setColorSchemeColors(colors);\n    }\n\n    public void setSize(int size) {\n        if (size != MaterialProgressDrawable.LARGE && size != MaterialProgressDrawable.DEFAULT) {\n            return;\n        }\n        final DisplayMetrics metrics = getResources().getDisplayMetrics();\n        if (size == MaterialProgressDrawable.LARGE) {\n            mCircleHeight = mCircleWidth = (int) (CIRCLE_DIAMETER_LARGE * metrics.density);\n        } else {\n            mCircleHeight = mCircleWidth = (int) (CIRCLE_DIAMETER * metrics.density);\n        }\n        // force the bounds of the progress circle inside the circle view to\n        // update by setting it to null before updating its size and then\n        // re-setting it\n        mCircleView.setImageDrawable(null);\n        mProgress.updateSizes(size);\n        mCircleView.setImageDrawable(mProgress);\n    }\n\n    @Override\n    public long succeedRetention() {\n        return 200;\n    }\n\n    @Override\n    public long failingRetention() {\n        return 0;\n    }\n\n    @Override\n    public int refreshHeight() {\n        return getHeight();\n    }\n\n    @Override\n    public int maxOffsetHeight() {\n        return 2 * getHeight();\n    }\n\n    boolean isReset = true;\n\n    @Override\n    public void onReset(@NotNull KRefreshLayout refreshLayout) {\n        mCircleView.clearAnimation();\n        mCircleView.animate().cancel();\n        mProgress.stop();\n        mCircleView.setVisibility(View.GONE);\n\n        mCircleView.getBackground().setAlpha(MAX_ALPHA);\n        mProgress.setAlpha(MAX_ALPHA);\n        ViewCompat.setScaleX(mCircleView, 0);\n        ViewCompat.setScaleY(mCircleView, 0);\n        ViewCompat.setAlpha(mCircleView, 1);\n        isReset = true;\n    }\n\n    @Override\n    public void onPrepare(@NotNull KRefreshLayout refreshLayout) {\n        mProgress.setAlpha(STARTING_PROGRESS_ALPHA);\n    }\n\n    @Override\n    public void onRefresh(@NotNull KRefreshLayout refreshLayout) {\n        mCircleView.setVisibility(View.VISIBLE);\n        mCircleView.getBackground().setAlpha(MAX_ALPHA);\n        mProgress.setAlpha(MAX_ALPHA);\n        ViewCompat.setScaleX(mCircleView, 1f);\n        ViewCompat.setScaleY(mCircleView, 1f);\n        mProgress.setArrowScale(1f);\n        mProgress.start();\n        isReset = false;\n    }\n\n    @Override\n    public void onComplete(@NotNull KRefreshLayout refreshLayout, boolean isSuccess) {\n        mCircleView.animate().scaleX(0).scaleY(0).alpha(0).start();\n    }\n\n    @Override\n    public void onScroll(@NotNull KRefreshLayout refreshLayout, int distance, float percent, boolean refreshing) {\n        if (!refreshing && isReset) {\n            if (mCircleView.getVisibility() != View.VISIBLE) {\n                mCircleView.setVisibility(View.VISIBLE);\n            }\n\n            if (percent >= 1f) {\n                ViewCompat.setScaleX(mCircleView, 1f);\n                ViewCompat.setScaleY(mCircleView, 1f);\n            } else {\n                ViewCompat.setScaleX(mCircleView, percent);\n                ViewCompat.setScaleY(mCircleView, percent);\n            }\n\n            if (percent <= 1f) {\n                mProgress.setAlpha((int) (STARTING_PROGRESS_ALPHA + (MAX_ALPHA - STARTING_PROGRESS_ALPHA) * percent));\n            }\n\n            float adjustedPercent = (float) Math.max(percent - .4, 0) * 5 / 3;\n            float strokeStart = adjustedPercent * .8f;\n            mProgress.setStartEndTrim(0f, Math.min(MAX_PROGRESS_ANGLE, strokeStart));\n            mProgress.setArrowScale(Math.min(1f, adjustedPercent));\n            float rotation = (-0.25f + .4f * adjustedPercent) * .5f;\n            mProgress.setProgressRotation(rotation);\n        }\n    }\n}\n"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/materia/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 gorden.krefreshlayout.demo.header.materia;\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 */\nclass MaterialProgressDrawable extends Drawable implements Animatable {\n    private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();\n    static final Interpolator MATERIAL_INTERPOLATOR = new FastOutSlowInInterpolator();\n\n    private static final float FULL_ROTATION = 1080.0f;\n\n    @Retention(RetentionPolicy.SOURCE)\n    @IntDef({LARGE, DEFAULT})\n    public @interface ProgressDrawableSize {}\n\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 static 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    float mRotationCount;\n    private double mWidth;\n    private double mHeight;\n    boolean mFinishing;\n\n    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    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    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    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        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": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/rentals/RentalsSunDrawable.java",
    "content": "package gorden.krefreshlayout.demo.header.rentals;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Canvas;\nimport android.graphics.ColorFilter;\nimport android.graphics.Matrix;\nimport android.graphics.PixelFormat;\nimport android.graphics.drawable.Animatable;\nimport android.graphics.drawable.Drawable;\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 gorden.krefreshlayout.demo.R;\nimport gorden.krefreshlayout.demo.util.DensityUtil;\n\npublic class RentalsSunDrawable extends Drawable implements Animatable {\n\n    private static final float SCALE_START_PERCENT = 0.3f;\n    private static final int ANIMATION_DURATION = 1000;\n\n    private final static float SKY_RATIO = 0.65f;\n    private static final float SKY_INITIAL_SCALE = 1.05f;\n\n    private final static float TOWN_RATIO = 0.22f;\n    private static final float TOWN_INITIAL_SCALE = 1.20f;\n    private static final float TOWN_FINAL_SCALE = 1.30f;\n\n    private static final float SUN_FINAL_SCALE = 0.75f;\n    private static final float SUN_INITIAL_ROTATE_GROWTH = 1.2f;\n    private static final float SUN_FINAL_ROTATE_GROWTH = 1.5f;\n\n    private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();\n\n    private View mParent;\n    private Matrix mMatrix;\n    private Animation mAnimation;\n\n    private int mTop;\n    private int mScreenWidth;\n\n    private int mSkyHeight;\n    private float mSkyTopOffset;\n    private float mSkyMoveOffset;\n\n    private int mTownHeight;\n    private float mTownInitialTopOffset;\n    private float mTownFinalTopOffset;\n    private float mTownMoveOffset;\n\n    private int mSunSize = 100;\n    private float mSunLeftOffset;\n    private float mSunTopOffset;\n\n    private float mPercent = 0.0f;\n    private float mRotate = 0.0f;\n\n    private Bitmap mSky;\n    private Bitmap mSun;\n    private Bitmap mTown;\n\n    private boolean isRefreshing = false;\n\n    private Context mContext;\n    private int mTotalDragDistance;\n\n    public RentalsSunDrawable(Context context, View parent) {\n        mContext = context;\n        mParent = parent;\n\n        mMatrix = new Matrix();\n\n        initiateDimens();\n        createBitmaps();\n        setupAnimations();\n    }\n\n    private Context getContext() {\n        return mContext;\n    }\n\n\n    private void initiateDimens() {\n        DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();\n        mTotalDragDistance = DensityUtil.dip2px(120);\n\n        mScreenWidth = getContext().getResources().getDisplayMetrics().widthPixels;\n        mSkyHeight = (int) (SKY_RATIO * mScreenWidth);\n        mSkyTopOffset = -(mSkyHeight * 0.28f);\n        mSkyMoveOffset = DensityUtil.dip2px(15);\n\n        mTownHeight = (int) (TOWN_RATIO * mScreenWidth);\n        mTownInitialTopOffset = (mTotalDragDistance - mTownHeight * TOWN_INITIAL_SCALE) + mTotalDragDistance * .42f;\n        mTownFinalTopOffset = (mTotalDragDistance - mTownHeight * TOWN_FINAL_SCALE) + mTotalDragDistance * .42f;\n        mTownMoveOffset = DensityUtil.dip2px(10);\n\n        mSunLeftOffset = 0.3f * (float) mScreenWidth;\n        mSunTopOffset = (mTotalDragDistance * 0.5f);\n\n        mTop = 0;\n    }\n\n    private void createBitmaps() {\n        mSky = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.sky);\n        mSky = Bitmap.createScaledBitmap(mSky, mScreenWidth, mSkyHeight, true);\n        mTown = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.buildings);\n        mTown = Bitmap.createScaledBitmap(mTown, mScreenWidth, (int) (mScreenWidth * TOWN_RATIO), true);\n        mSun = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.sun);\n        mSun = Bitmap.createScaledBitmap(mSun, mSunSize, mSunSize, true);\n    }\n\n    public void offsetTopAndBottom(int offset) {\n        mTop = offset;\n        invalidateSelf();\n    }\n\n    @Override\n    public void draw(Canvas canvas) {\n        final int saveCount = canvas.save();\n        canvas.translate(0, mTotalDragDistance - mTop);\n\n        drawSky(canvas);\n        drawSun(canvas);\n        drawTown(canvas);\n\n        canvas.restoreToCount(saveCount);\n    }\n\n    private void drawSky(Canvas canvas) {\n        Matrix matrix = mMatrix;\n        matrix.reset();\n        int y = Math.max(0, mTop - mTotalDragDistance);\n\n        //  0  ~ 1\n        float dragPercent = Math.min(1f, Math.abs(mPercent));\n\n        /** Change skyScale between {@link #SKY_INITIAL_SCALE} and 1.0f depending on {@link #mPercent} */\n        float skyScale;\n        float scalePercentDelta = dragPercent - SCALE_START_PERCENT;\n\n        /** less than {@link SCALE_START_PERCENT} will be {@link SKY_INITIAL_SCALE} */\n        if (scalePercentDelta > 0) {\n            /** will change from 0 ~ 1 **/\n            float scalePercent = scalePercentDelta / (1.0f - SCALE_START_PERCENT);\n            skyScale = SKY_INITIAL_SCALE - (SKY_INITIAL_SCALE - 1.0f) * scalePercent;\n        } else {\n            skyScale = SKY_INITIAL_SCALE;\n        }\n\n        float offsetX = -(mScreenWidth * skyScale - mScreenWidth) / 2.0f;\n\n        float offsetY = y + 50 + mSkyTopOffset // Offset canvas moving, goes lower when goes down\n                - mSkyHeight * (skyScale - 1.0f) / 2 // Offset sky scaling, lower than 0, will go greater when goes down\n                + mSkyMoveOffset * dragPercent; // Give it a little move top -> bottom  // will go greater when goes down\n\n        matrix.postScale(skyScale, skyScale);\n        matrix.postTranslate(offsetX, offsetY);\n        canvas.drawBitmap(mSky, matrix, null);\n    }\n\n    private void drawTown(Canvas canvas) {\n        Matrix matrix = mMatrix;\n        matrix.reset();\n\n        int y = Math.max(0, mTop - mTotalDragDistance);\n        float dragPercent = Math.min(1f, Math.abs(mPercent));\n\n        float townScale;\n        float townTopOffset;\n        float townMoveOffset;\n        float scalePercentDelta = dragPercent - SCALE_START_PERCENT;\n        if (scalePercentDelta > 0) {\n            /**\n             * Change townScale between {@link #TOWN_INITIAL_SCALE} and {@link #TOWN_FINAL_SCALE} depending on {@link #mPercent}\n             * Change townTopOffset between {@link #mTownInitialTopOffset} and {@link #mTownFinalTopOffset} depending on {@link #mPercent}\n             */\n            float scalePercent = scalePercentDelta / (1.0f - SCALE_START_PERCENT);\n            townScale = TOWN_INITIAL_SCALE + (TOWN_FINAL_SCALE - TOWN_INITIAL_SCALE) * scalePercent;\n            townTopOffset = mTownInitialTopOffset - (mTownFinalTopOffset - mTownInitialTopOffset) * scalePercent;\n            townMoveOffset = mTownMoveOffset * (1.0f - scalePercent);\n        } else {\n            float scalePercent = dragPercent / SCALE_START_PERCENT;\n            townScale = TOWN_INITIAL_SCALE;\n            townTopOffset = mTownInitialTopOffset;\n            townMoveOffset = mTownMoveOffset * scalePercent;\n        }\n\n        float offsetX = -(mScreenWidth * townScale - mScreenWidth) / 2.0f;\n        // float offsetY = (1.0f - dragPercent) * mTotalDragDistance // Offset canvas moving\n        float offsetY = y +\n                +townTopOffset\n                - mTownHeight * (townScale - 1.0f) / 2 // Offset town scaling\n                + townMoveOffset; // Give it a little move\n\n        matrix.postScale(townScale, townScale);\n        matrix.postTranslate(offsetX, offsetY);\n\n        canvas.drawBitmap(mTown, matrix, null);\n    }\n\n    private void drawSun(Canvas canvas) {\n        Matrix matrix = mMatrix;\n        matrix.reset();\n\n        float dragPercent = mPercent;\n        if (dragPercent > 1.0f) { // Slow down if pulling over set height\n            dragPercent = (dragPercent + 9.0f) / 10;\n        }\n\n        float sunRadius = (float) mSunSize / 2.0f;\n        float sunRotateGrowth = SUN_INITIAL_ROTATE_GROWTH;\n\n        float offsetX = mSunLeftOffset;\n        float offsetY = mSunTopOffset\n                + (mTotalDragDistance / 2) * (1.0f - dragPercent); // Move the sun up\n\n        float scalePercentDelta = dragPercent - SCALE_START_PERCENT;\n        if (scalePercentDelta > 0) {\n            float scalePercent = scalePercentDelta / (1.0f - SCALE_START_PERCENT);\n            float sunScale = 1.0f - (1.0f - SUN_FINAL_SCALE) * scalePercent;\n            sunRotateGrowth += (SUN_FINAL_ROTATE_GROWTH - SUN_INITIAL_ROTATE_GROWTH) * scalePercent;\n\n            matrix.preTranslate(offsetX + (sunRadius - sunRadius * sunScale), offsetY * (2.0f - sunScale));\n            matrix.preScale(sunScale, sunScale);\n\n            offsetX += sunRadius;\n            offsetY = offsetY * (2.0f - sunScale) + sunRadius * sunScale;\n        } else {\n            matrix.postTranslate(offsetX, offsetY);\n\n            offsetX += sunRadius;\n            offsetY += sunRadius;\n        }\n\n        float r = (isRefreshing ? -360 : 360) * mRotate * (isRefreshing ? 1 : sunRotateGrowth);\n        matrix.postRotate(r, offsetX, offsetY);\n\n        canvas.drawBitmap(mSun, matrix, null);\n    }\n\n    public void setPercent(float percent) {\n        mPercent = percent;\n        setRotate(percent);\n    }\n\n    public void setRotate(float rotate) {\n        mRotate = rotate;\n        mParent.invalidate();\n        invalidateSelf();\n    }\n\n    public void resetOriginals() {\n        setPercent(0);\n        setRotate(0);\n    }\n\n    @Override\n    public void setBounds(int left, int top, int right, int bottom) {\n        super.setBounds(left, top, right, mSkyHeight + top);\n    }\n\n    @Override\n    public void setAlpha(int alpha) {\n\n    }\n\n    @Override\n    public void setColorFilter(ColorFilter colorFilter) {\n\n    }\n\n    @Override\n    public int getOpacity() {\n        return PixelFormat.TRANSLUCENT;\n    }\n\n    @Override\n    public boolean isRunning() {\n        return false;\n    }\n\n    @Override\n    public void start() {\n        mAnimation.reset();\n        isRefreshing = true;\n        mParent.startAnimation(mAnimation);\n    }\n\n    @Override\n    public void stop() {\n        mParent.clearAnimation();\n        isRefreshing = false;\n        resetOriginals();\n    }\n\n    private void setupAnimations() {\n        mAnimation = new Animation() {\n            @Override\n            public void applyTransformation(float interpolatedTime, Transformation t) {\n                setRotate(interpolatedTime);\n            }\n        };\n        mAnimation.setRepeatCount(Animation.INFINITE);\n        mAnimation.setRepeatMode(Animation.RESTART);\n        mAnimation.setInterpolator(LINEAR_INTERPOLATOR);\n        mAnimation.setDuration(ANIMATION_DURATION);\n    }\n\n    public int getTotalDragDistance() {\n        return mTotalDragDistance;\n    }\n}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/rentals/RentalsSunHeaderView.java",
    "content": "package gorden.krefreshlayout.demo.header.rentals;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.drawable.Drawable;\nimport android.support.annotation.NonNull;\nimport android.support.annotation.Nullable;\nimport android.util.AttributeSet;\nimport android.view.View;\n\nimport org.jetbrains.annotations.NotNull;\n\nimport gorden.krefreshlayout.demo.util.DensityUtil;\nimport gorden.refresh.KRefreshHeader;\nimport gorden.refresh.KRefreshLayout;\n\n/*\n * 一个经典的太阳升起刷新Header\n */\n\npublic class RentalsSunHeaderView extends View implements KRefreshHeader {\n    private RentalsSunDrawable mDrawable;\n    private float mPercent;\n    private int mDistance;\n\n    public RentalsSunHeaderView(Context context) {\n        super(context);\n        init();\n    }\n\n    public RentalsSunHeaderView(Context context, @Nullable AttributeSet attrs) {\n        super(context, attrs);\n        init();\n    }\n\n    public RentalsSunHeaderView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        init();\n    }\n\n    private void init() {\n        mDrawable = new RentalsSunDrawable(getContext(), this);\n        setPadding(0, DensityUtil.dip2px(15), 0, DensityUtil.dip2px(10));\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        int height = mDrawable.getTotalDragDistance() * 5 / 4;\n        heightMeasureSpec = MeasureSpec.makeMeasureSpec(height + getPaddingTop() + getPaddingBottom(), MeasureSpec.EXACTLY);\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n    }\n\n    @Override\n    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {\n        int pl = getPaddingLeft();\n        int pt = getPaddingTop();\n        mDrawable.setBounds(pl, pt, pl + right - left, pt + bottom - top);\n    }\n\n    @Override\n    public long succeedRetention() {\n        return 300;\n    }\n\n    @Override\n    public long failingRetention() {\n        return 0;\n    }\n\n    @Override\n    public int refreshHeight() {\n        return mDrawable.getTotalDragDistance()+DensityUtil.dip2px(15);\n    }\n\n    @Override\n    public int maxOffsetHeight() {\n        return getHeight();\n    }\n\n    @Override\n    public void onReset(@NotNull KRefreshLayout refreshLayout) {\n        mDrawable.resetOriginals();\n    }\n\n    @Override\n    protected void onDraw(Canvas canvas) {\n        mDrawable.draw(canvas);\n    }\n\n    @Override\n    public void onPrepare(@NotNull KRefreshLayout refreshLayout) {\n    }\n\n    @Override\n    public void onRefresh(@NotNull KRefreshLayout refreshLayout) {\n        mDrawable.start();\n        mDrawable.offsetTopAndBottom(mDistance);\n        mDrawable.setPercent(mPercent);\n        invalidate();\n    }\n\n    @Override\n    public void onComplete(@NotNull KRefreshLayout refreshLayout,boolean isSuccess) {\n        mDrawable.stop();\n        mDrawable.offsetTopAndBottom(mDistance);\n        mDrawable.setPercent(mPercent);\n        invalidate();\n    }\n\n\n    @Override\n    public void onScroll(@NotNull KRefreshLayout refreshLayout, int distance, float percent, boolean refreshing) {\n        mPercent = percent;\n        mDistance = distance;\n        mDrawable.offsetTopAndBottom(distance);\n        mDrawable.setPercent(percent);\n        invalidate();\n    }\n\n    @Override\n    public void invalidateDrawable(@NonNull Drawable drawable) {\n        if (drawable == mDrawable) {\n            invalidate();\n        } else {\n            super.invalidateDrawable(drawable);\n        }\n    }\n}\n"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/storehouse/StoreHouseBarItem.java",
    "content": "package gorden.krefreshlayout.demo.header.storehouse;\n\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nimport android.graphics.PointF;\nimport android.view.animation.Animation;\nimport android.view.animation.Transformation;\n\nimport java.util.Random;\n\n/**\n * Created by srain on 11/6/14.\n */\npublic class StoreHouseBarItem extends Animation {\n\n    public PointF midPoint;\n    public float translationX;\n    public int index;\n\n    private final Paint mPaint = new Paint();\n    private float mFromAlpha = 1.0f;\n    private float mToAlpha = 0.4f;\n    private PointF mCStartPoint;\n    private PointF mCEndPoint;\n\n    public StoreHouseBarItem(int index, PointF start, PointF end, int color, int lineWidth) {\n        this.index = index;\n\n        midPoint = new PointF((start.x + end.x) / 2, (start.y + end.y) / 2);\n\n        mCStartPoint = new PointF(start.x - midPoint.x, start.y - midPoint.y);\n        mCEndPoint = new PointF(end.x - midPoint.x, end.y - midPoint.y);\n\n        setColor(color);\n        setLineWidth(lineWidth);\n        mPaint.setAntiAlias(true);\n        mPaint.setStyle(Paint.Style.STROKE);\n    }\n\n    public void setLineWidth(int width) {\n        mPaint.setStrokeWidth(width);\n    }\n\n    public void setColor(int color) {\n        mPaint.setColor(color);\n    }\n\n    public void resetPosition(int horizontalRandomness) {\n        Random random = new Random();\n        int randomNumber = -random.nextInt(horizontalRandomness) + horizontalRandomness;\n        translationX = randomNumber;\n    }\n\n    @Override\n    protected void applyTransformation(float interpolatedTime, Transformation t) {\n        float alpha = mFromAlpha;\n        alpha = alpha + ((mToAlpha - alpha) * interpolatedTime);\n        setAlpha(alpha);\n    }\n\n    public void start(float fromAlpha, float toAlpha) {\n        mFromAlpha = fromAlpha;\n        mToAlpha = toAlpha;\n        super.start();\n    }\n\n    public void setAlpha(float alpha) {\n        mPaint.setAlpha((int) (alpha * 255));\n    }\n\n    public void draw(Canvas canvas) {\n        canvas.drawLine(mCStartPoint.x, mCStartPoint.y, mCEndPoint.x, mCEndPoint.y, mPaint);\n    }\n}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/storehouse/StoreHouseHeader.java",
    "content": "package gorden.krefreshlayout.demo.header.storehouse;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Matrix;\nimport android.graphics.PointF;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.view.animation.Transformation;\n\nimport org.jetbrains.annotations.NotNull;\n\nimport java.util.ArrayList;\n\nimport gorden.krefreshlayout.demo.util.DensityUtil;\nimport gorden.refresh.KRefreshHeader;\nimport gorden.refresh.KRefreshLayout;\n\npublic class StoreHouseHeader extends View implements KRefreshHeader {\n\n    public ArrayList<StoreHouseBarItem> mItemList = new ArrayList<StoreHouseBarItem>();\n\n    private int mLineWidth = -1;\n    private float mScale = 1;\n    private int mDropHeight = -1;\n    private float mInternalAnimationFactor = 0.7f;\n    private int mHorizontalRandomness = -1;\n\n    private float mProgress = 0;\n\n    private int mDrawZoneWidth = 0;\n    private int mDrawZoneHeight = 0;\n    private int mOffsetX = 0;\n    private int mOffsetY = 0;\n    private float mBarDarkAlpha = 0.4f;\n    private float mFromAlpha = 1.0f;\n    private float mToAlpha = 0.4f;\n\n    private int mLoadingAniDuration = 1000;\n    private int mLoadingAniSegDuration = 1000;\n    private int mLoadingAniItemDuration = 400;\n\n    private Transformation mTransformation = new Transformation();\n    private boolean mIsInLoading = false;\n    private AniController mAniController = new AniController();\n    private int mTextColor = Color.WHITE;\n\n    public StoreHouseHeader(Context context) {\n        super(context);\n        initView();\n    }\n\n    public StoreHouseHeader(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        initView();\n    }\n\n    public StoreHouseHeader(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        initView();\n    }\n\n    private void initView() {\n        mLineWidth = DensityUtil.dip2px(1);\n        mDropHeight = DensityUtil.dip2px(40);\n        mHorizontalRandomness =DensityUtil.appWidth() / 2;\n        initWithString(\"KREFRESHLAYOUT\",25);\n        setPadding(0,20,0,20);\n    }\n\n    private void setProgress(float progress) {\n        mProgress = progress;\n    }\n\n    public int getLoadingAniDuration() {\n        return mLoadingAniDuration;\n    }\n\n    public void setLoadingAniDuration(int duration) {\n        mLoadingAniDuration = duration;\n        mLoadingAniSegDuration = duration;\n    }\n\n    public StoreHouseHeader setLineWidth(int width) {\n        mLineWidth = width;\n        for (int i = 0; i < mItemList.size(); i++) {\n            mItemList.get(i).setLineWidth(width);\n        }\n        return this;\n    }\n\n    public StoreHouseHeader setTextColor(int color) {\n        mTextColor = color;\n        for (int i = 0; i < mItemList.size(); i++) {\n            mItemList.get(i).setColor(color);\n        }\n        return this;\n    }\n\n    public StoreHouseHeader setDropHeight(int height) {\n        mDropHeight = height;\n        return this;\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        int height = getTopOffset() + mDrawZoneHeight + getBottomOffset();\n        heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n\n        mOffsetX = (getMeasuredWidth() - mDrawZoneWidth) / 2;\n        mOffsetY = getTopOffset();\n        mDropHeight = getTopOffset();\n    }\n\n    private int getTopOffset() {\n        return getPaddingTop() + DensityUtil.dip2px(10);\n    }\n\n    private int getBottomOffset() {\n        return getPaddingBottom() + DensityUtil.dip2px(10);\n    }\n\n    public void initWithString(String str) {\n        initWithString(str, 25);\n    }\n\n    public void initWithString(String str, int fontSize) {\n        ArrayList<float[]> pointList = StoreHousePath.getPath(str, fontSize * 0.01f, 14);\n        initWithPointList(pointList);\n    }\n\n    public void initWithStringArray(int id) {\n        String[] points = getResources().getStringArray(id);\n        ArrayList<float[]> pointList = new ArrayList<float[]>();\n        for (int i = 0; i < points.length; i++) {\n            String[] x = points[i].split(\",\");\n            float[] f = new float[4];\n            for (int j = 0; j < 4; j++) {\n                f[j] = Float.parseFloat(x[j]);\n            }\n            pointList.add(f);\n        }\n        initWithPointList(pointList);\n    }\n\n    public float getScale() {\n        return mScale;\n    }\n\n    public void setScale(float scale) {\n        mScale = scale;\n    }\n\n    public void initWithPointList(ArrayList<float[]> pointList) {\n\n        float drawWidth = 0;\n        float drawHeight = 0;\n        boolean shouldLayout = mItemList.size() > 0;\n        mItemList.clear();\n        for (int i = 0; i < pointList.size(); i++) {\n            float[] line = pointList.get(i);\n            PointF startPoint = new PointF(DensityUtil.dip2px(line[0]) * mScale, DensityUtil.dip2px(line[1]) * mScale);\n            PointF endPoint = new PointF(DensityUtil.dip2px(line[2]) * mScale, DensityUtil.dip2px(line[3]) * mScale);\n\n            drawWidth = Math.max(drawWidth, startPoint.x);\n            drawWidth = Math.max(drawWidth, endPoint.x);\n\n            drawHeight = Math.max(drawHeight, startPoint.y);\n            drawHeight = Math.max(drawHeight, endPoint.y);\n\n            StoreHouseBarItem item = new StoreHouseBarItem(i, startPoint, endPoint, mTextColor, mLineWidth);\n            item.resetPosition(mHorizontalRandomness);\n            mItemList.add(item);\n        }\n        mDrawZoneWidth = (int) Math.ceil(drawWidth);\n        mDrawZoneHeight = (int) Math.ceil(drawHeight);\n        if (shouldLayout) {\n            requestLayout();\n        }\n    }\n\n    private void beginLoading() {\n        mIsInLoading = true;\n        mAniController.start();\n        invalidate();\n    }\n\n    private void loadFinish() {\n        mIsInLoading = false;\n        mAniController.stop();\n    }\n\n    @Override\n    public void onDraw(Canvas canvas) {\n        super.onDraw(canvas);\n        float progress = mProgress;\n        int c1 = canvas.save();\n        int len = mItemList.size();\n\n        for (int i = 0; i < len; i++) {\n\n            canvas.save();\n            StoreHouseBarItem storeHouseBarItem = mItemList.get(i);\n            float offsetX = mOffsetX + storeHouseBarItem.midPoint.x;\n            float offsetY = mOffsetY + storeHouseBarItem.midPoint.y;\n\n            if (mIsInLoading) {\n                storeHouseBarItem.getTransformation(getDrawingTime(), mTransformation);\n                canvas.translate(offsetX, offsetY);\n            } else {\n\n                if (progress == 0) {\n                    storeHouseBarItem.resetPosition(mHorizontalRandomness);\n                    continue;\n                }\n\n                float startPadding = (1 - mInternalAnimationFactor) * i / len;\n                float endPadding = 1 - mInternalAnimationFactor - startPadding;\n\n                // done\n                if (progress == 1 || progress >= 1 - endPadding) {\n                    canvas.translate(offsetX, offsetY);\n                    storeHouseBarItem.setAlpha(mBarDarkAlpha);\n                } else {\n                    float realProgress;\n                    if (progress <= startPadding) {\n                        realProgress = 0;\n                    } else {\n                        realProgress = Math.min(1, (progress - startPadding) / mInternalAnimationFactor);\n                    }\n                    offsetX += storeHouseBarItem.translationX * (1 - realProgress);\n                    offsetY += -mDropHeight * (1 - realProgress);\n                    Matrix matrix = new Matrix();\n                    matrix.postRotate(360 * realProgress);\n                    matrix.postScale(realProgress, realProgress);\n                    matrix.postTranslate(offsetX, offsetY);\n                    storeHouseBarItem.setAlpha(mBarDarkAlpha * realProgress);\n                    canvas.concat(matrix);\n                }\n            }\n            storeHouseBarItem.draw(canvas);\n            canvas.restore();\n        }\n        if (mIsInLoading) {\n            invalidate();\n        }\n        canvas.restoreToCount(c1);\n    }\n\n    @Override\n    public long succeedRetention() {\n        return 200;\n    }\n\n    @Override\n    public long failingRetention() {\n        return 200;\n    }\n\n    @Override\n    public int refreshHeight() {\n        return getHeight();\n    }\n\n    @Override\n    public int maxOffsetHeight() {\n        return 2*getHeight();\n    }\n\n    @Override\n    public void onReset(@NotNull KRefreshLayout refreshLayout) {\n        loadFinish();\n        for (int i = 0; i < mItemList.size(); i++) {\n            mItemList.get(i).resetPosition(mHorizontalRandomness);\n\n        }\n    }\n\n    @Override\n    public void onPrepare(@NotNull KRefreshLayout refreshLayout) {\n\n    }\n\n    @Override\n    public void onRefresh(@NotNull KRefreshLayout refreshLayout) {\n        beginLoading();\n    }\n\n    @Override\n    public void onComplete(@NotNull KRefreshLayout refreshLayout, boolean isSuccess) {\n        loadFinish();\n    }\n\n    @Override\n    public void onScroll(@NotNull KRefreshLayout refreshLayout, int distance, float percent, boolean refreshing) {\n        float currentPercent = Math.min(1f, percent);\n        setProgress(currentPercent);\n        invalidate();\n    }\n\n    private class AniController implements Runnable {\n\n        private int mTick = 0;\n        private int mCountPerSeg = 0;\n        private int mSegCount = 0;\n        private int mInterval = 0;\n        private boolean mRunning = true;\n\n        private void start() {\n            mRunning = true;\n            mTick = 0;\n\n            mInterval = mLoadingAniDuration / mItemList.size();\n            mCountPerSeg = mLoadingAniSegDuration / mInterval;\n            mSegCount = mItemList.size() / mCountPerSeg + 1;\n            run();\n        }\n\n        @Override\n        public void run() {\n\n            int pos = mTick % mCountPerSeg;\n            for (int i = 0; i < mSegCount; i++) {\n\n                int index = i * mCountPerSeg + pos;\n                if (index > mTick) {\n                    continue;\n                }\n\n                index = index % mItemList.size();\n                StoreHouseBarItem item = mItemList.get(index);\n\n                item.setFillAfter(false);\n                item.setFillEnabled(true);\n                item.setFillBefore(false);\n                item.setDuration(mLoadingAniItemDuration);\n                item.start(mFromAlpha, mToAlpha);\n            }\n\n            mTick++;\n            if (mRunning) {\n                postDelayed(this, mInterval);\n            }\n        }\n\n        private void stop() {\n            mRunning = false;\n            removeCallbacks(this);\n        }\n    }\n}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/storehouse/StoreHousePath.java",
    "content": "package gorden.krefreshlayout.demo.header.storehouse;\n\nimport android.util.SparseArray;\n\nimport java.util.ArrayList;\n\n/**\n * Created by srain on 11/7/14.\n */\npublic class StoreHousePath {\n\n    private static final SparseArray<float[]> sPointList;\n\n    static {\n        sPointList = new SparseArray<float[]>();\n        float[][] LETTERS = new float[][]{\n                new float[]{\n                        // A\n                        24, 0, 1, 22,\n                        1, 22, 1, 72,\n                        24, 0, 47, 22,\n                        47, 22, 47, 72,\n                        1, 48, 47, 48\n                },\n\n                new float[]{\n                        // B\n                        0, 0, 0, 72,\n                        0, 0, 37, 0,\n                        37, 0, 47, 11,\n                        47, 11, 47, 26,\n                        47, 26, 38, 36,\n                        38, 36, 0, 36,\n                        38, 36, 47, 46,\n                        47, 46, 47, 61,\n                        47, 61, 38, 71,\n                        37, 72, 0, 72,\n                },\n\n                new float[]{\n                        // C\n                        47, 0, 0, 0,\n                        0, 0, 0, 72,\n                        0, 72, 47, 72,\n                },\n\n                new float[]{\n                        // D\n                        0, 0, 0, 72,\n                        0, 0, 24, 0,\n                        24, 0, 47, 22,\n                        47, 22, 47, 48,\n                        47, 48, 23, 72,\n                        23, 72, 0, 72,\n                },\n\n                new float[]{\n                        // E\n                        0, 0, 0, 72,\n                        0, 0, 47, 0,\n                        0, 36, 37, 36,\n                        0, 72, 47, 72,\n                },\n\n                new float[]{\n                        // F\n                        0, 0, 0, 72,\n                        0, 0, 47, 0,\n                        0, 36, 37, 36,\n                },\n\n                new float[]{\n                        // G\n                        47, 23, 47, 0,\n                        47, 0, 0, 0,\n                        0, 0, 0, 72,\n                        0, 72, 47, 72,\n                        47, 72, 47, 48,\n                        47, 48, 24, 48,\n                },\n\n                new float[]{\n                        // H\n                        0, 0, 0, 72,\n                        0, 36, 47, 36,\n                        47, 0, 47, 72,\n                },\n\n                new float[]{\n                        // I\n                        0, 0, 47, 0,\n                        24, 0, 24, 72,\n                        0, 72, 47, 72,\n                },\n\n                new float[]{\n                        // J\n                        47, 0, 47, 72,\n                        47, 72, 24, 72,\n                        24, 72, 0, 48,\n                },\n\n                new float[]{\n                        // K\n                        0, 0, 0, 72,\n                        47, 0, 3, 33,\n                        3, 38, 47, 72,\n                },\n\n                new float[]{\n                        // L\n                        0, 0, 0, 72,\n                        0, 72, 47, 72,\n                },\n\n                new float[]{\n                        // M\n                        0, 0, 0, 72,\n                        0, 0, 24, 23,\n                        24, 23, 47, 0,\n                        47, 0, 47, 72,\n                },\n\n                new float[]{\n                        // N\n                        0, 0, 0, 72,\n                        0, 0, 47, 72,\n                        47, 72, 47, 0,\n                },\n\n                new float[]{\n                        // O\n                        0, 0, 0, 72,\n                        0, 72, 47, 72,\n                        47, 72, 47, 0,\n                        47, 0, 0, 0,\n                },\n\n                new float[]{\n                        // P\n                        0, 0, 0, 72,\n                        0, 0, 47, 0,\n                        47, 0, 47, 36,\n                        47, 36, 0, 36,\n                },\n\n                new float[]{\n                        // Q\n                        0, 0, 0, 72,\n                        0, 72, 23, 72,\n                        23, 72, 47, 48,\n                        47, 48, 47, 0,\n                        47, 0, 0, 0,\n                        24, 28, 47, 71,\n                },\n\n                new float[]{\n                        // R\n                        0, 0, 0, 72,\n                        0, 0, 47, 0,\n                        47, 0, 47, 36,\n                        47, 36, 0, 36,\n                        0, 37, 47, 72,\n                },\n\n                new float[]{\n                        // S\n                        47, 0, 0, 0,\n                        0, 0, 0, 36,\n                        0, 36, 47, 36,\n                        47, 36, 47, 72,\n                        47, 72, 0, 72,\n                },\n\n                new float[]{\n                        // T\n                        0, 0, 47, 0,\n                        24, 0, 24, 72,\n                },\n\n                new float[]{\n                        // U\n                        0, 0, 0, 72,\n                        0, 72, 47, 72,\n                        47, 72, 47, 0,\n                },\n\n                new float[]{\n                        // V\n                        0, 0, 24, 72,\n                        24, 72, 47, 0,\n                },\n\n                new float[]{\n                        // W\n                        0, 0, 0, 72,\n                        0, 72, 24, 49,\n                        24, 49, 47, 72,\n                        47, 72, 47, 0\n                },\n\n                new float[]{\n                        // X\n                        0, 0, 47, 72,\n                        47, 0, 0, 72\n                },\n\n                new float[]{\n                        // Y\n                        0, 0, 24, 23,\n                        47, 0, 24, 23,\n                        24, 23, 24, 72\n                },\n\n                new float[]{\n                        // Z\n                        0, 0, 47, 0,\n                        47, 0, 0, 72,\n                        0, 72, 47, 72\n                },\n        };\n        final float[][] NUMBERS = new float[][]{\n                new float[]{\n                        // 0\n                        0, 0, 0, 72,\n                        0, 72, 47, 72,\n                        47, 72, 47, 0,\n                        47, 0, 0, 0,\n                },\n                new float[]{\n                        // 1\n                        24, 0, 24, 72,\n                },\n\n                new float[]{\n                        // 2\n                        0, 0, 47, 0,\n                        47, 0, 47, 36,\n                        47, 36, 0, 36,\n                        0, 36, 0, 72,\n                        0, 72, 47, 72\n                },\n\n                new float[]{\n                        // 3\n                        0, 0, 47, 0,\n                        47, 0, 47, 36,\n                        47, 36, 0, 36,\n                        47, 36, 47, 72,\n                        47, 72, 0, 72,\n                },\n\n                new float[]{\n                        // 4\n                        0, 0, 0, 36,\n                        0, 36, 47, 36,\n                        47, 0, 47, 72,\n                },\n\n                new float[]{\n                        // 5\n                        0, 0, 0, 36,\n                        0, 36, 47, 36,\n                        47, 36, 47, 72,\n                        47, 72, 0, 72,\n                        0, 0, 47, 0\n                },\n\n                new float[]{\n                        // 6\n                        0, 0, 0, 72,\n                        0, 72, 47, 72,\n                        47, 72, 47, 36,\n                        47, 36, 0, 36\n                },\n\n                new float[]{\n                        // 7\n                        0, 0, 47, 0,\n                        47, 0, 47, 72\n                },\n\n                new float[]{\n                        // 8\n                        0, 0, 0, 72,\n                        0, 72, 47, 72,\n                        47, 72, 47, 0,\n                        47, 0, 0, 0,\n                        0, 36, 47, 36\n                },\n\n                new float[]{\n                        // 9\n                        47, 0, 0, 0,\n                        0, 0, 0, 36,\n                        0, 36, 47, 36,\n                        47, 0, 47, 72,\n                }\n        };\n        // A - Z\n        for (int i = 0; i < LETTERS.length; i++) {\n            sPointList.append(i + 65, LETTERS[i]);\n        }\n        // a - z\n        for (int i = 0; i < LETTERS.length; i++) {\n            sPointList.append(i + 65 + 32, LETTERS[i]);\n        }\n        // 0 - 9\n        for (int i = 0; i < NUMBERS.length; i++) {\n            sPointList.append(i + 48, NUMBERS[i]);\n        }\n        // blank\n        addChar(' ', new float[]{});\n        // -\n        addChar('-', new float[]{\n                0, 36, 47, 36\n        });\n        // .\n        addChar('.', new float[]{\n                24, 60, 24, 72\n        });\n    }\n\n    public static void addChar(char c, float[] points) {\n        sPointList.append(c, points);\n    }\n\n    public static ArrayList<float[]> getPath(String str) {\n        return getPath(str, 1, 14);\n    }\n\n    /**\n     * @param str\n     * @param scale\n     * @param gapBetweenLetter\n     * @return ArrayList of float[] {x1, y1, x2, y2}\n     */\n    public static ArrayList<float[]> getPath(String str, float scale, int gapBetweenLetter) {\n        ArrayList<float[]> list = new ArrayList<float[]>();\n        float offsetForWidth = 0;\n        for (int i = 0; i < str.length(); i++) {\n            int pos = str.charAt(i);\n            int key = sPointList.indexOfKey(pos);\n            if (key == -1) {\n                continue;\n            }\n            float[] points = sPointList.get(pos);\n            int pointCount = points.length / 4;\n\n            for (int j = 0; j < pointCount; j++) {\n                float[] line = new float[4];\n                for (int k = 0; k < 4; k++) {\n                    float l = points[j * 4 + k];\n                    // x\n                    if (k % 2 == 0) {\n                        line[k] = (l + offsetForWidth) * scale;\n                    }\n                    // y\n                    else {\n                        line[k] = l * scale;\n                    }\n                }\n                list.add(line);\n            }\n            offsetForWidth += 57 + gapBetweenLetter;\n        }\n        return list;\n    }\n}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/MainActivity.kt",
    "content": "package gorden.krefreshlayout.demo.ui\n\nimport android.content.Intent\nimport android.os.Bundle\nimport android.support.v7.app.AppCompatActivity\nimport android.widget.SimpleAdapter\nimport gorden.krefreshlayout.demo.R\nimport gorden.krefreshlayout.demo.util.XLog\nimport kotlinx.android.synthetic.main.activity_main.*\n\nclass MainActivity : AppCompatActivity() {\n    val gridItems = arrayOf(\"RecyclerView\", \"ScrollView\", \"NestedScrollView\", \"ViewPager in NestedScrollView\", \"ViewPager in ScrollView\"\n            , \"WebView \", \"Fragment in ViewPager\", \"CoordinatorLayout\", \"Wechat_Refresh\",\"LoadMoreView\",\"gordenxqw@gmail.com\", \"QQ:354419188\")\n    val dataList = ArrayList<Map<String, String>>()\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_main)\n\n        for (item in gridItems) {\n            val map = HashMap<String, String>()\n            map.put(\"name\", item)\n            dataList.add(map)\n        }\n        gridView.adapter = SimpleAdapter(this, dataList, R.layout.item_main, arrayOf(\"name\"), intArrayOf(R.id.textView))\n\n        gridView.setOnItemClickListener { parent, view, position, id ->\n            val intent = Intent(\"SampleActivity\")\n            intent.putExtra(\"position\", position);\n            intent.putExtra(\"name\", gridItems[position])\n            startActivity(intent)\n        }\n\n        refreshLayout.setKRefreshListener {\n            XLog.e(\"xxx\",\"开始刷新\")\n            refreshLayout.postDelayed({\n                refreshLayout.refreshComplete(true)\n            }, 2000)\n        }\n\n//        refreshLayout.startRefresh()\n    }\n}\n"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/SampleActivity.kt",
    "content": "package gorden.krefreshlayout.demo.ui\n\nimport android.app.Activity\nimport android.content.Intent\nimport android.support.v7.app.AppCompatActivity\nimport android.os.Bundle\nimport android.support.v4.app.FragmentManager\n\nimport gorden.krefreshlayout.demo.R\nimport gorden.krefreshlayout.demo.ui.fragment.*\nimport kotlinx.android.synthetic.main.activity_sample.*\n\nclass SampleActivity : AppCompatActivity() {\n    private var mFragment:ISampleFragment? = null\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_sample)\n\n        text_title.text = intent.getStringExtra(\"name\")\n\n        btn_back.setOnClickListener {\n            finish()\n        }\n\n        btn_setting.setOnClickListener {\n            val intent = Intent(\"SettingActivity\")\n            intent.putExtra(\"header\",mFragment?.headerPosition)\n            intent.putExtra(\"pincontent\",mFragment?.pinContent)\n            intent.putExtra(\"keepheader\",mFragment?.keepHeaderWhenRefresh)\n            intent.putExtra(\"durationoffset\",mFragment?.durationOffset)\n            intent.putExtra(\"refreshtime\",mFragment?.refreshTime)\n            startActivityForResult(intent,612)\n        }\n\n        val position = intent.getIntExtra(\"position\",0)\n\n        val manager:FragmentManager = supportFragmentManager\n\n        when(position){\n            0-> mFragment = SampleAFragment()\n            1-> mFragment = SampleBFragment()\n            2-> mFragment = SampleCFragment()\n            3-> mFragment = SampleDFragment()\n            4-> mFragment = SampleEFragment()\n            5-> mFragment = SampleFFragment()\n            6-> mFragment = SampleGFragment()\n            7-> mFragment = SampleHFragment()\n            8-> mFragment = SampleIFragment()\n            9-> mFragment = SampleJFragment()\n            else ->mFragment = SampleAFragment()\n        }\n        manager.beginTransaction().replace(R.id.frame_content,mFragment).commit()\n    }\n\n    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {\n        super.onActivityResult(requestCode, resultCode, data)\n\n        if (requestCode == 612&&resultCode == Activity.RESULT_OK){\n            mFragment?.headerPosition = data!!.getIntExtra(\"header\",mFragment!!.headerPosition)\n            mFragment?.pinContent = data.getBooleanExtra(\"pincontent\",mFragment!!.pinContent)\n            mFragment?.keepHeaderWhenRefresh = data.getBooleanExtra(\"keepheader\",mFragment!!.keepHeaderWhenRefresh)\n            mFragment?.durationOffset = data.getLongExtra(\"durationoffset\",mFragment!!.durationOffset)\n            mFragment?.refreshTime = data.getLongExtra(\"refreshtime\",mFragment!!.refreshTime)\n        }\n    }\n}\n"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/SettingActivity.kt",
    "content": "package gorden.krefreshlayout.demo.ui\n\nimport android.app.Activity\nimport android.content.Intent\nimport android.os.Bundle\nimport android.support.v7.app.AppCompatActivity\nimport android.text.TextUtils\nimport android.view.View\nimport android.widget.AdapterView\nimport gorden.krefreshlayout.demo.R\nimport kotlinx.android.synthetic.main.activity_setting.*\n\nclass SettingActivity : AppCompatActivity() {\n    private var headerPosition = 0\n\n    private var pinContent = false\n    private var keepHeaderWhenRefresh = true\n    private var durationOffset = 200L\n    private var refreshTime = 2000L\n\n    override fun onCreate(savedInstanceState: Bundle?) {\n        super.onCreate(savedInstanceState)\n        setContentView(R.layout.activity_setting)\n\n        btn_back.setOnClickListener {\n            finish()\n        }\n\n        headerPosition = intent.getIntExtra(\"header\", 0)\n        pinContent = intent.getBooleanExtra(\"pincontent\", false)\n        keepHeaderWhenRefresh = intent.getBooleanExtra(\"keepheader\", true)\n        durationOffset = intent.getLongExtra(\"durationoffset\", 200)\n        refreshTime = intent.getLongExtra(\"refreshtime\", 2000)\n\n        spinner.setSelection(headerPosition)\n        togglePinContent.isChecked = pinContent\n        toggleKeepHeader.isChecked = keepHeaderWhenRefresh\n        edit_offset.setText(durationOffset.toString())\n        edit_refresh.setText(refreshTime.toString())\n\n        spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {\n            override fun onNothingSelected(parent: AdapterView<*>?) {\n            }\n\n            override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {\n                headerPosition = position\n            }\n        }\n    }\n\n    override fun finish() {\n        val data = Intent()\n\n        pinContent = togglePinContent.isChecked\n        keepHeaderWhenRefresh = toggleKeepHeader.isChecked\n        durationOffset = if (TextUtils.isEmpty(edit_offset.text)) 200 else edit_offset.text.toString().toLong()\n        refreshTime = if (TextUtils.isEmpty(edit_refresh.text)) 2000 else edit_refresh.text.toString().toLong()\n\n        data.putExtra(\"header\", headerPosition)\n        data.putExtra(\"pincontent\", pinContent)\n        data.putExtra(\"keepheader\", keepHeaderWhenRefresh)\n        data.putExtra(\"durationoffset\", durationOffset)\n        data.putExtra(\"refreshtime\", refreshTime)\n        setResult(Activity.RESULT_OK, data)\n        super.finish()\n    }\n}\n"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/ISampleFragment.kt",
    "content": "package gorden.krefreshlayout.demo.ui.fragment\n\nimport android.support.v4.app.Fragment\nimport android.view.ViewGroup\nimport gorden.krefreshlayout.demo.header.ClassicalHeader\nimport gorden.krefreshlayout.demo.header.WechatHeader\nimport gorden.krefreshlayout.demo.header.circle.CircleHeader\nimport gorden.krefreshlayout.demo.header.fungame.FunGameHeader\nimport gorden.krefreshlayout.demo.header.materia.MateriaProgressHeader\nimport gorden.krefreshlayout.demo.header.rentals.RentalsSunHeaderView\nimport gorden.krefreshlayout.demo.header.storehouse.StoreHouseHeader\nimport gorden.krefreshlayout.demo.util.DensityUtil\nimport gorden.refresh.KRefreshLayout\n\n/**\n * document\n * Created by Gordn on 2017/6/21.\n */\nabstract class ISampleFragment : Fragment() {\n    abstract val mRefreshLayout: KRefreshLayout\n    var headerPosition: Int = 0\n        get() = field\n        set(value) {\n            if (field != value) {\n                field = value\n                header()\n            }\n        }\n\n    var pinContent: Boolean = false\n        get() = field\n        set(value) {\n            if (field != value) {\n                field = value\n                mRefreshLayout.pinContent = field\n            }\n        }\n\n    var keepHeaderWhenRefresh: Boolean = true\n        get() = field\n        set(value) {\n            if (field != value) {\n                field = value\n                mRefreshLayout.keepHeaderWhenRefresh = field\n            }\n        }\n\n    var durationOffset: Long = 200\n        get() = field\n        set(value) {\n            if (field != value) {\n                field = value\n                mRefreshLayout.durationOffset=field\n            }\n        }\n\n    var refreshTime: Long = 2000\n        get() = field\n        set(value) {\n            field = value\n        }\n\n    fun header(): Unit {\n        when (headerPosition) {\n            0 -> mRefreshLayout.setHeader(ClassicalHeader(context))\n            1 -> mRefreshLayout.setHeader(MateriaProgressHeader(context), ViewGroup.LayoutParams.MATCH_PARENT, DensityUtil.dip2px(80))\n            2 -> mRefreshLayout.setHeader(RentalsSunHeaderView(context))\n            3 -> mRefreshLayout.setHeader(StoreHouseHeader(context))\n            4 -> mRefreshLayout.setHeader(CircleHeader(context))\n            5 -> mRefreshLayout.setHeader(FunGameHeader(context))\n            6 -> mRefreshLayout.setHeader(WechatHeader(context))\n            else -> mRefreshLayout.removeHeader()\n        }\n    }\n}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleAFragment.kt",
    "content": "package gorden.krefreshlayout.demo.ui.fragment\n\nimport android.os.Bundle\nimport android.support.v7.widget.DividerItemDecoration\nimport android.support.v7.widget.LinearLayoutManager\nimport android.support.v7.widget.RecyclerView\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport gorden.krefreshlayout.demo.R\nimport gorden.krefreshlayout.demo.header.ClassicalHeader\nimport gorden.refresh.KRefreshLayout\nimport kotlinx.android.synthetic.main.layout_recyclerview.*\n\n/**\n * document\n * Created by Gordn on 2017/6/21.\n */\nclass SampleAFragment : ISampleFragment() {\n    override val mRefreshLayout: KRefreshLayout\n        get() = refreshLayout\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {\n        return inflater.inflate(R.layout.layout_recyclerview,container,false)\n    }\n\n    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n\n        refreshLayout.setHeader(ClassicalHeader(context))\n        recyclerView.layoutManager = LinearLayoutManager(context)\n        recyclerView.addItemDecoration(DividerItemDecoration(context,DividerItemDecoration.VERTICAL))\n        recyclerView.adapter = object : RecyclerView.Adapter<RecyclerView.ViewHolder>() {\n            override fun onBindViewHolder(holder: RecyclerView.ViewHolder?, position: Int) {\n            }\n\n            override fun getItemCount(): Int {\n                return 20\n            }\n\n            override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): RecyclerView.ViewHolder {\n\n                return object :RecyclerView.ViewHolder(LayoutInflater.from(context).inflate(R.layout.item_sample,parent,false)){}\n            }\n        }\n\n        refreshLayout.setKRefreshListener {\n            refreshLayout.postDelayed({\n                refreshLayout?.refreshComplete(true)\n            },refreshTime)\n        }\n\n    }\n\n}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleBFragment.kt",
    "content": "package gorden.krefreshlayout.demo.ui.fragment\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport gorden.krefreshlayout.demo.R\nimport gorden.krefreshlayout.demo.header.ClassicalHeader\nimport gorden.refresh.KRefreshLayout\nimport kotlinx.android.synthetic.main.layout_scrollview.*\n\n/**\n * document\n * Created by Gordn on 2017/6/21.\n */\nclass SampleBFragment : ISampleFragment() {\n    override val mRefreshLayout: KRefreshLayout\n        get() = refreshLayout\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {\n        return inflater.inflate(R.layout.layout_scrollview,container,false)\n    }\n\n    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n\n        refreshLayout.setHeader(ClassicalHeader(context))\n\n        refreshLayout.setKRefreshListener {\n            refreshLayout.postDelayed({\n                refreshLayout?.refreshComplete(true)\n            },refreshTime)\n        }\n\n    }\n\n}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleCFragment.kt",
    "content": "package gorden.krefreshlayout.demo.ui.fragment\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport gorden.krefreshlayout.demo.R\nimport gorden.krefreshlayout.demo.header.ClassicalHeader\nimport gorden.refresh.KRefreshLayout\nimport kotlinx.android.synthetic.main.layout_nestedscrollview.*\n\n/**\n * document\n * Created by Gordn on 2017/6/21.\n */\nclass SampleCFragment : ISampleFragment() {\n\n    override val mRefreshLayout: KRefreshLayout\n        get() = refreshLayout\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {\n        return inflater.inflate(R.layout.layout_nestedscrollview,container,false)\n    }\n\n    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        refreshLayout.setHeader(ClassicalHeader(context))\n        refreshLayout.setKRefreshListener {\n            refreshLayout.postDelayed({\n                refreshLayout?.refreshComplete(true)\n            },refreshTime)\n        }\n\n    }\n\n}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleDFragment.kt",
    "content": "package gorden.krefreshlayout.demo.ui.fragment\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport gorden.krefreshlayout.demo.R\nimport gorden.krefreshlayout.demo.header.ClassicalHeader\nimport gorden.refresh.KRefreshLayout\nimport kotlinx.android.synthetic.main.layout_vp_nestedscrollview.*\n\n/**\n * document\n * Created by Gordn on 2017/6/21.\n */\nclass SampleDFragment : ISampleFragment() {\n\n    override val mRefreshLayout: KRefreshLayout\n        get() = refreshLayout\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {\n        return inflater.inflate(R.layout.layout_vp_nestedscrollview, container, false)\n    }\n\n    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        refreshLayout.setHeader(ClassicalHeader(context))\n        viewPager.setImages(arrayListOf<Int>(R.drawable.img_pager1, R.drawable.img_pager2, R.drawable.img_pager3))\n\n        refreshLayout.setKRefreshListener {\n            refreshLayout.postDelayed({\n                refreshLayout?.refreshComplete(true)\n            }, refreshTime)\n        }\n\n    }\n\n}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleEFragment.kt",
    "content": "package gorden.krefreshlayout.demo.ui.fragment\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport gorden.krefreshlayout.demo.R\nimport gorden.krefreshlayout.demo.header.ClassicalHeader\nimport gorden.refresh.KRefreshLayout\nimport kotlinx.android.synthetic.main.layout_vp_scrollview.*\n\n/**\n * document\n * Created by Gordn on 2017/6/21.\n */\nclass SampleEFragment : ISampleFragment() {\n\n    override val mRefreshLayout: KRefreshLayout\n        get() = refreshLayout\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {\n        return inflater.inflate(R.layout.layout_vp_scrollview, container, false)\n    }\n\n    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        refreshLayout.setHeader(ClassicalHeader(context))\n        viewPager.setImages(arrayListOf<Int>(R.drawable.img_pager1, R.drawable.img_pager2, R.drawable.img_pager3))\n\n        refreshLayout.setKRefreshListener {\n            refreshLayout.postDelayed({\n                refreshLayout?.refreshComplete(true)\n            }, refreshTime)\n        }\n\n    }\n\n}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleFFragment.kt",
    "content": "package gorden.krefreshlayout.demo.ui.fragment\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport android.webkit.WebResourceRequest\nimport android.webkit.WebView\nimport android.webkit.WebViewClient\nimport gorden.krefreshlayout.demo.R\nimport gorden.krefreshlayout.demo.header.ClassicalHeader\nimport gorden.refresh.KRefreshLayout\nimport kotlinx.android.synthetic.main.layout_webview.*\n\n/**\n * document\n * Created by Gordn on 2017/6/21.\n */\nclass SampleFFragment : ISampleFragment() {\n\n    override val mRefreshLayout: KRefreshLayout\n        get() = refreshLayout\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {\n        return inflater.inflate(R.layout.layout_webview, container, false)\n    }\n\n    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        refreshLayout.setHeader(ClassicalHeader(context))\n\n        webView.loadUrl(\"http://www.baidu.com\")\n        webView.setWebViewClient(object :WebViewClient(){\n            override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {\n                return true\n            }\n        })\n\n        refreshLayout.setKRefreshListener {\n            refreshLayout.postDelayed({\n                refreshLayout?.refreshComplete(true)\n            }, refreshTime)\n        }\n\n    }\n\n}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleGFragment.kt",
    "content": "package gorden.krefreshlayout.demo.ui.fragment\n\nimport android.os.Bundle\nimport android.support.v4.app.Fragment\nimport android.support.v4.app.FragmentStatePagerAdapter\nimport android.support.v4.view.ViewPager\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport gorden.krefreshlayout.demo.R\nimport gorden.krefreshlayout.demo.header.ClassicalHeader\nimport gorden.refresh.KRefreshLayout\nimport kotlinx.android.synthetic.main.layout_viewpager.*\n\n/**\n * document\n * Created by Gordn on 2017/6/21.\n */\nclass SampleGFragment : ISampleFragment() {\n    var currentPosition = 0\n    val fragmentList = arrayListOf(SampleAFragment(), SampleDFragment(), SampleCFragment())\n    val titleList = arrayListOf(\"TAB1\",\"TAB2\",\"TAB3\")\n\n    override val mRefreshLayout: KRefreshLayout\n        get() = fragmentList[currentPosition].mRefreshLayout\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {\n        return inflater.inflate(R.layout.layout_viewpager, container, false)\n    }\n\n    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n\n        tabLayout.setupWithViewPager(viewPager)\n\n        viewPager.adapter = object : FragmentStatePagerAdapter(fragmentManager) {\n            override fun getItem(position: Int): Fragment {\n                return fragmentList[position]\n            }\n\n            override fun getCount(): Int {\n                return 3\n            }\n\n            override fun getPageTitle(position: Int): CharSequence {\n                return titleList[position]\n            }\n\n        }\n\n        viewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener {\n            override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {\n\n            }\n\n            override fun onPageSelected(position: Int) {\n                currentPosition = position\n            }\n\n            override fun onPageScrollStateChanged(state: Int) {\n            }\n\n        })\n    }\n\n}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleHFragment.kt",
    "content": "package gorden.krefreshlayout.demo.ui.fragment\n\nimport android.os.Bundle\nimport android.support.v7.widget.DividerItemDecoration\nimport android.support.v7.widget.RecyclerView\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport gorden.krefreshlayout.demo.R\nimport gorden.krefreshlayout.demo.header.ClassicalHeader\nimport gorden.refresh.KRefreshLayout\nimport kotlinx.android.synthetic.main.layout_coordinatorlayout.*\n\n/**\n * document\n * Created by Gordn on 2017/6/21.\n */\nclass SampleHFragment : ISampleFragment() {\n    override val mRefreshLayout: KRefreshLayout\n        get() = refreshLayout\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {\n        return inflater.inflate(R.layout.layout_coordinatorlayout, container, false)\n    }\n\n    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n\n        refreshLayout.setHeader(ClassicalHeader(context))\n        recyclerView.addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL))\n\n        textView.addOnLayoutChangeListener {\n            _, _, _, _, _, _, _, _, _ ->\n            refreshLayout.refreshEnable = scrolling_header.translationY==0f\n        }\n\n        recyclerView.adapter = object : RecyclerView.Adapter<RecyclerView.ViewHolder>() {\n            override fun onBindViewHolder(holder: RecyclerView.ViewHolder?, position: Int) {\n            }\n\n            override fun getItemCount(): Int {\n                return 20\n            }\n\n            override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): RecyclerView.ViewHolder {\n\n                return object : RecyclerView.ViewHolder(LayoutInflater.from(context).inflate(R.layout.item_sample,parent,false)){}\n            }\n        }\n\n        refreshLayout.setKRefreshListener {\n            refreshLayout.postDelayed({\n                refreshLayout?.refreshComplete(true)\n            },refreshTime)\n        }\n    }\n\n}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleIFragment.kt",
    "content": "package gorden.krefreshlayout.demo.ui.fragment\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport gorden.krefreshlayout.demo.R\nimport gorden.krefreshlayout.demo.header.ClassicalHeader\nimport gorden.krefreshlayout.demo.header.WechatHeader\nimport gorden.krefreshlayout.demo.util.DensityUtil\nimport gorden.refresh.KRefreshLayout\nimport kotlinx.android.synthetic.main.layout_vp_nestedscrollview.*\n\n/**\n * document\n * Created by Gordn on 2017/6/21.\n */\nclass SampleIFragment : ISampleFragment() {\n\n    override val mRefreshLayout: KRefreshLayout\n        get() = refreshLayout\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {\n        return inflater.inflate(R.layout.layout_vp_nestedscrollview, container, false)\n    }\n\n    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n        refreshLayout.setHeader(WechatHeader(context))\n        refreshLayout.keepHeaderWhenRefresh = false\n        viewPager.setImages(arrayListOf<Int>(R.drawable.img_pager1, R.drawable.img_pager2, R.drawable.img_pager3))\n\n        refreshLayout.setKRefreshListener {\n            refreshLayout.postDelayed({\n                refreshLayout?.refreshComplete(true)\n            }, refreshTime)\n        }\n\n        //头部自带偏移效果的header 自动刷新\n        refreshLayout.headerOffset = DensityUtil.dip2px(50)\n        (refreshLayout.getHeader() as WechatHeader).mDistance = DensityUtil.dip2px(50)\n        refreshLayout.startRefresh()\n    }\n\n}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleJFragment.kt",
    "content": "package gorden.krefreshlayout.demo.ui.fragment\n\nimport android.os.Bundle\nimport android.support.v7.widget.DividerItemDecoration\nimport android.support.v7.widget.LinearLayoutManager\nimport android.support.v7.widget.RecyclerView\nimport android.view.LayoutInflater\nimport android.view.View\nimport android.view.ViewGroup\nimport gorden.krefreshlayout.demo.R\nimport gorden.krefreshlayout.demo.footer.ClassicalFooter\nimport gorden.krefreshlayout.demo.header.ClassicalHeader\nimport gorden.refresh.KRefreshLayout\nimport kotlinx.android.synthetic.main.layout_krecyclerview.*\n\n/**\n * document\n * Created by Gordn on 2017/6/21.\n */\nclass SampleJFragment : ISampleFragment() {\n    override val mRefreshLayout: KRefreshLayout\n        get() = refreshLayout\n\n    var count = 0\n\n    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {\n        return inflater.inflate(R.layout.layout_krecyclerview, container, false)\n    }\n\n    override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {\n        super.onViewCreated(view, savedInstanceState)\n\n        refreshLayout.setHeader(ClassicalHeader(context))\n        recyclerView.layoutManager = LinearLayoutManager(context)\n        recyclerView.addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL))\n        val adapter = object : RecyclerView.Adapter<RecyclerView.ViewHolder>() {\n            override fun onBindViewHolder(holder: RecyclerView.ViewHolder?, position: Int) {\n            }\n\n            override fun getItemCount(): Int {\n                return count\n            }\n\n            override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): RecyclerView.ViewHolder {\n\n                return object : RecyclerView.ViewHolder(LayoutInflater.from(context).inflate(R.layout.item_sample, parent, false)) {}\n            }\n        }\n        recyclerView.adapter = adapter\n\n        recyclerView.setLoadMoreView(ClassicalFooter(context))\n\n        refreshLayout.setKRefreshListener {\n            refreshLayout.postDelayed({\n                count = 10\n                adapter.notifyDataSetChanged()\n                recyclerView.hasMore = true\n                refreshLayout?.refreshComplete(true)\n            }, refreshTime)\n        }\n\n        refreshLayout.startRefresh()\n\n        recyclerView.setLoadMoreListener {\n            recyclerView.postDelayed({\n                count += 10\n                adapter.notifyDataSetChanged()\n                recyclerView.loadMoreComplete(count <= 20)\n            }, 2000)\n        }\n\n\n    }\n\n}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/util/CrashHandler.java",
    "content": "package gorden.krefreshlayout.demo.util;\n\nimport android.content.Context;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\nimport android.os.Environment;\nimport android.os.Process;\nimport android.util.Log;\n\nimport java.io.BufferedWriter;\nimport java.io.File;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\n/**\n * 错误日志\n * Created by Gorden on 2015/11/23.\n */\n@SuppressWarnings(\"unused\")\npublic class CrashHandler implements Thread.UncaughtExceptionHandler {\n    private static final String TAG = \"crash_log\";\n    private Context mContext;\n    private static final String SDCARD_ROOT = Environment.getExternalStorageDirectory().toString();\n    private static final String PATH = Environment.getExternalStorageDirectory().getPath() + File.separator + \"Acrash\";\n    private static final String FILE_NAME = \"crash\";\n    //log文件的后缀名\n    private static final String FILE_NAME_SUFFIX = \".log\";\n    private static CrashHandler mInstance = new CrashHandler();\n    //系统默认的异常处理（默认情况下，系统会终止当前的异常程序）\n    private Thread.UncaughtExceptionHandler mDefaultCrashHandler;\n\n    private boolean DEBUG = false;\n\n    private CrashHandler() {\n    }\n\n    public static CrashHandler getInstance() {\n        return mInstance;\n    }\n\n    @Override\n    public void uncaughtException(Thread thread, Throwable ex) {\n//        try {\n//            //导出异常信息到SD卡中\n//            saveExceptionToSDCard(ex);\n//            //这里可以通过网络上传异常信息到服务器，便于开发人员分析日志从而解决bug\n//            uploadExceptionToServer(ex);\n//        } catch (IOException e) {\n//            e.printStackTrace();\n//        }\n        //打印出当前调用栈信息\n        if (DEBUG) {\n            XLog.e(TAG, \"开始打印错误日志\");\n            StringWriter mStringWriter = new StringWriter();\n            PrintWriter mPrintWriter = new PrintWriter(mStringWriter);\n            ex.printStackTrace(mPrintWriter);\n            mPrintWriter.close();\n            XLog.e(TAG, mStringWriter.toString());\n        }\n        //如果系统提供了默认的异常处理器，则交给系统去结束我们的程序，否则就由我们自己结束自己\n        if (mDefaultCrashHandler != null) {\n            mDefaultCrashHandler.uncaughtException(thread, ex);\n        } else {\n//            ActivityStack.getInstance().finishAllActivity();\n            Process.killProcess(Process.myPid());\n        }\n    }\n\n    /**\n     * 为我们的应用程序设置自定义Crash处理\n     */\n    public void init(Context context, boolean isDebug) {\n        mContext = context.getApplicationContext();\n        DEBUG = isDebug;\n        //获取系统默认的异常处理器\n        mDefaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler();\n        //将当前实例设为系统默认的异常处理器\n        Thread.setDefaultUncaughtExceptionHandler(this);\n    }\n\n    private void saveExceptionToSDCard(Throwable ex) throws IOException {\n        if (!DEBUG) return;\n        //如果SD卡不存在或无法使用，则无法把异常信息写入SD卡\n        if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {\n            Log.w(TAG, \"sdcard unmounted,skip dump exception\");\n            return;\n        }\n        File dir = new File(PATH);\n        if (!dir.exists()) {\n            dir.mkdirs();\n        }\n        long current = System.currentTimeMillis();\n        String time = new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\").format(new Date(current));\n        //以当前时间创建log文件\n        File file = new File(PATH + File.separator + FILE_NAME + time + FILE_NAME_SUFFIX);\n        try {\n            PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file)));\n            //导出发生异常的时间\n            pw.println(time);\n\n            //导出手机信息\n            dumpPhoneInfo(pw);\n\n            pw.println();\n            //导出异常的调用栈信息\n            ex.printStackTrace(pw);\n\n            pw.close();\n        } catch (Exception e) {\n            Log.e(TAG, \"dump crash info failed\");\n        }\n\n    }\n\n    private void uploadExceptionToServer(Throwable ex) {\n        //TODO Upload Exception Message To Your Web Server\n    }\n\n\n    private void dumpPhoneInfo(PrintWriter pw) throws PackageManager.NameNotFoundException {\n        //应用的版本名称和版本号\n        PackageManager pm = mContext.getPackageManager();\n        PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(), PackageManager.GET_ACTIVITIES);\n        pw.print(\"App Version: \");\n        pw.print(pi.versionName);\n        pw.print('_');\n        pw.println(pi.versionCode);\n\n        //android版本号\n        pw.print(\"OS Version: \");\n        pw.print(Build.VERSION.RELEASE);\n        pw.print(\"_\");\n        pw.println(Build.VERSION.SDK_INT);\n\n        //手机制造商\n        pw.print(\"Vendor: \");\n        pw.println(Build.MANUFACTURER);\n\n        //手机型号\n        pw.print(\"Model: \");\n        pw.println(Build.MODEL);\n\n        //cpu架构\n        pw.print(\"CPU ABI: \");\n        pw.println(Build.CPU_ABI);\n    }\n}\n"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/util/DensityUtil.java",
    "content": "package gorden.krefreshlayout.demo.util;\n\nimport android.content.res.Resources;\n\n/**\n * document\n * Created by Gordn on 2017/6/19.\n */\n\npublic class DensityUtil {\n    private static float density = Resources.getSystem().getDisplayMetrics().density;\n\n    public static int dip2px(int dp){\n        return (int) (dp*density);\n    }\n    public static int dip2px(float dp){\n        return (int) (dp*density);\n    }\n    public static int appWidth(){\n        return Resources.getSystem().getDisplayMetrics().widthPixels;\n    }\n    public static int appHeight(){\n        return Resources.getSystem().getDisplayMetrics().heightPixels;\n    }\n}\n"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/util/XLog.java",
    "content": "package gorden.krefreshlayout.demo.util;\n\nimport android.text.TextUtils;\nimport android.util.Log;\n\nimport java.io.PrintWriter;\nimport java.io.StringWriter;\n\n/**\n * Log日志打印工具类\n * Created by gorden on 2016/7/26.\n */\npublic class XLog {\n\n    public static final String NULL_TIPS = \"Log with null object\";\n\n    private static final String DEFAULT_MESSAGE = \"execute\";\n    private static final String PARAM = \"Param\";\n    private static final String NULL = \"null\";\n    private static final String SUFFIX = \".java\";\n\n    private static final String TAG_DEFAULT = \"XLog\";\n    private static boolean IS_SHOW_LOG = true;\n\n    private static String TAG_NAME;\n    private static boolean mIsGlobalTagEmpty = true;\n\n    public static final int V = 0x1;\n    public static final int D = 0x2;\n    public static final int I = 0x3;\n    public static final int W = 0x4;\n    public static final int E = 0x5;\n    public static final int A = 0x6;\n\n    private static final int STACK_TRACE_INDEX = 5;\n\n    public static void init(boolean showLog){\n        IS_SHOW_LOG = showLog;\n    }\n\n    public static void init(boolean showLog,String tag){\n        IS_SHOW_LOG = showLog;\n        TAG_NAME = tag;\n        mIsGlobalTagEmpty = TextUtils.isEmpty(TAG_NAME);\n    }\n\n    public static void v() {\n        printLog(V, null, DEFAULT_MESSAGE);\n    }\n\n    public static void v(Object msg) {\n        printLog(V, null, msg);\n    }\n\n    public static void v(String tag, Object... objects) {\n        printLog(V, tag, objects);\n    }\n\n    public static void d() {\n        printLog(D, null, DEFAULT_MESSAGE);\n    }\n\n    public static void d(Object msg) {\n        printLog(D, null, msg);\n    }\n\n    public static void d(String tag, Object... objects) {\n        printLog(D, tag, objects);\n    }\n\n    public static void i() {\n        printLog(I, null, DEFAULT_MESSAGE);\n    }\n\n    public static void i(Object msg) {\n        printLog(I, null, msg);\n    }\n\n    public static void i(String tag, Object... objects) {\n        printLog(I, tag, objects);\n    }\n\n    public static void w() {\n        printLog(W, null, DEFAULT_MESSAGE);\n    }\n\n    public static void w(Object msg) {\n        printLog(W, null, msg);\n    }\n\n    public static void w(String tag, Object... objects) {\n        printLog(W, tag, objects);\n    }\n\n    public static void e() {\n        printLog(E, null, DEFAULT_MESSAGE);\n    }\n\n    public static void e(Object msg) {\n        printLog(E, null, msg);\n    }\n\n    public static void e(String tag, Object... objects) {\n        printLog(E, tag, objects);\n    }\n\n    public static void exception(Exception ex){\n        StringWriter mStringWriter = new StringWriter();\n        PrintWriter mPrintWriter = new PrintWriter(mStringWriter);\n        ex.printStackTrace(mPrintWriter);\n        mPrintWriter.close();\n        printLog(E,null,mStringWriter.toString());\n    }\n\n    public static void a() {\n        printLog(A, null, DEFAULT_MESSAGE);\n    }\n\n    public static void a(Object msg) {\n        printLog(A, null, msg);\n    }\n\n    public static void a(String tag, Object... objects) {\n        printLog(A, tag, objects);\n    }\n\n\n    private static void printLog(int type,String tagStr,Object... objects) {\n\n        if(!IS_SHOW_LOG) return;\n\n        String[] contents = wrapperContent(tagStr, objects);\n        String tag = contents[0];\n        String msg = contents[1];\n        String headString = contents[2];\n\n        switch (type) {\n            case V:\n            case D:\n            case I:\n            case W:\n            case E:\n            case A:\n                printDefault(type, tag, headString + msg);\n                break;\n        }\n\n    }\n\n    public static void printDefault(int type, String tag, String msg) {\n\n        int index = 0;\n        int maxLength = 4000;\n        int countOfSub = msg.length() / maxLength;\n\n        if (countOfSub > 0) {\n            for (int i = 0; i < countOfSub; i++) {\n                String sub = msg.substring(index, index + maxLength);\n                printSub(type, tag, sub);\n                index += maxLength;\n            }\n            printSub(type, tag, msg.substring(index, msg.length()));\n        } else {\n            printSub(type, tag, msg);\n        }\n    }\n\n    private static void printSub(int type, String tag, String sub) {\n\n        switch (type) {\n            case V:\n                Log.v(tag, sub);\n                break;\n            case D:\n                Log.d(tag, sub);\n                break;\n            case I:\n                Log.i(tag, sub);\n                break;\n            case W:\n                Log.w(tag, sub);\n                break;\n            case E:\n                Log.e(tag, sub);\n                break;\n            case A:\n                Log.wtf(tag, sub);\n                break;\n        }\n    }\n\n\n    private static String[] wrapperContent(String tagStr, Object... objects) {\n\n        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();\n\n        StackTraceElement targetElement = stackTrace[STACK_TRACE_INDEX];\n        String className = targetElement.getClassName();\n        String[] classNameInfo = className.split(\"\\\\.\");\n        if (classNameInfo.length > 0) {\n            className = classNameInfo[classNameInfo.length - 1] + SUFFIX;\n        }\n\n        if (className.contains(\"$\")) {\n            className = className.split(\"\\\\$\")[0] + SUFFIX;\n        }\n\n        String methodName = targetElement.getMethodName();\n        int lineNumber = targetElement.getLineNumber();\n\n        if (lineNumber < 0) {\n            lineNumber = 0;\n        }\n\n        String methodNameShort = methodName.substring(0, 1).toUpperCase() + methodName.substring(1);\n\n        String tag = (tagStr == null ? className : tagStr);\n\n        if (mIsGlobalTagEmpty && TextUtils.isEmpty(tag)) {\n            tag = TAG_DEFAULT;\n        } else if (!mIsGlobalTagEmpty && TextUtils.isEmpty(tagStr)) {\n            tag = TAG_NAME;\n        }\n\n        String msg = (objects == null) ? NULL_TIPS : getObjectsString(objects);\n        String headString = \"[ (\" + className + \":\" + lineNumber + \")#\" + methodNameShort + \" ] \";\n\n        return new String[]{tag, msg, headString};\n    }\n\n    private static String getObjectsString(Object... objects) {\n\n        if (objects.length > 1) {\n            StringBuilder stringBuilder = new StringBuilder();\n            stringBuilder.append(\"\\n\");\n            for (int i = 0; i < objects.length; i++) {\n                Object object = objects[i];\n                if (object == null) {\n                    stringBuilder.append(PARAM).append(\"[\").append(i).append(\"]\").append(\" = \").append(NULL).append(\"\\n\");\n                } else {\n                    stringBuilder.append(PARAM).append(\"[\").append(i).append(\"]\").append(\" = \").append(object.toString()).append(\"\\n\");\n                }\n            }\n            return stringBuilder.toString();\n        } else {\n            Object object = objects[0];\n            return object == null ? NULL : object.toString();\n        }\n    }\n}\n"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/widget/AdViewPager.java",
    "content": "package gorden.krefreshlayout.demo.widget;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Color;\nimport android.graphics.drawable.ColorDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.os.Build;\nimport android.os.Handler;\nimport android.os.Message;\nimport android.support.annotation.NonNull;\nimport android.support.v4.view.PagerAdapter;\nimport android.support.v4.view.ViewPager;\nimport android.util.AttributeSet;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.RelativeLayout;\n\n//import com.bumptech.glide.Glide;\n\nimport java.util.List;\n\nimport gorden.krefreshlayout.demo.R;\n\n/**\n * 广告轮播ViewPager\n */\n@SuppressWarnings(\"unused\")\npublic class AdViewPager extends RelativeLayout {\n    private static final int RMP = LayoutParams.MATCH_PARENT;\n    private static final int RWP = LayoutParams.WRAP_CONTENT;\n    private static final int LWC = LinearLayout.LayoutParams.WRAP_CONTENT;\n    private static final int WAIT_AUTO_PLAY = 1000;\n\n    //Point位置\n    public static final int CENTER = 0;\n    public static final int LEFT = 1;\n    public static final int RIGHT = 2;\n\n    private RelativeLayout mPointContainerRl;\n    private LinearLayout mPointRealContainerLl;\n\n    private ViewPager mViewPager;\n    //本地图片资源\n    private List<Integer> mImages;\n    //网络图片资源\n    private List<String> mImageUrls;\n    //是否是网络图片\n    private boolean mIsImageUrl = false;\n    //是否只有一张图片\n    private boolean mIsOneImg = false;\n    //是否可以自动播放\n    private boolean mAutoPlayAble = true;\n    //是否正在播放\n    private boolean mIsAutoPlaying = false;\n    //自动播放时间\n    private int mAutoPalyTime = 5000;\n\n    //当前页面位置\n    private int mCurrentPositon;\n    //指示点位置\n    private int mPointPosition = CENTER;\n    //指示点资源\n    private int mPointDrawableResId = R.drawable.selector_adpager_point;\n    //指示容器背景\n    private Drawable mPointContainerBackgroundDrawable;\n    //指示容器布局规则\n    private LayoutParams mPointRealContainerLp;\n\n    //指示点是否可见\n    private boolean mPointsIsVisible = true;\n\n    /**\n     * 自动轮播handler\n     */\n    private Handler mAutoPlayHandler = new Handler(new Handler.Callback() {\n        @Override\n        public boolean handleMessage(Message msg) {\n            mCurrentPositon++;\n            mViewPager.setCurrentItem(mCurrentPositon);\n            mAutoPlayHandler.sendEmptyMessageDelayed(WAIT_AUTO_PLAY, mAutoPalyTime);\n            return false;\n        }\n    });\n\n    public AdViewPager(Context context) {\n        this(context, null);\n    }\n\n    public AdViewPager(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        init(context, attrs);\n    }\n\n    private void init(Context context, AttributeSet attrs) {\n\n        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AdViewPager);\n\n        mPointsIsVisible = a.getBoolean(R.styleable.AdViewPager_ad_points_visibility, true);\n        mPointPosition = a.getInt(R.styleable.AdViewPager_ad_points_position, CENTER);\n        mPointContainerBackgroundDrawable\n                = a.getDrawable(R.styleable.AdViewPager_ad_points_container_background);\n\n        a.recycle();\n\n        setLayout(context);\n    }\n\n    private void setLayout(Context context) {\n        //关闭view的OverScroll\n        setOverScrollMode(OVER_SCROLL_NEVER);\n        //设置指示器背景\n        if (mPointContainerBackgroundDrawable == null) {\n            mPointContainerBackgroundDrawable = new ColorDrawable(Color.parseColor(\"#33AAAAAA\"));\n        }\n        //添加ViewPager\n        mViewPager = new ViewPager(context);\n        addView(mViewPager, new LayoutParams(RMP, RMP));\n        //设置指示器背景容器\n        mPointContainerRl = new RelativeLayout(context);\n        if (Build.VERSION.SDK_INT >= 16) {\n            mPointContainerRl.setBackground(mPointContainerBackgroundDrawable);\n        } else {\n            mPointContainerRl.setBackgroundDrawable(mPointContainerBackgroundDrawable);\n        }\n        //设置内边距\n        mPointContainerRl.setPadding(0, 10, 0, 10);\n        //设定指示器容器布局及位置\n        LayoutParams pointContainerLp = new LayoutParams(RMP, RWP);\n        pointContainerLp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);\n        addView(mPointContainerRl, pointContainerLp);\n        //设置指示器容器\n        mPointRealContainerLl = new LinearLayout(context);\n        mPointRealContainerLl.setOrientation(LinearLayout.HORIZONTAL);\n        mPointRealContainerLp = new LayoutParams(RWP, RWP);\n        mPointContainerRl.addView(mPointRealContainerLl, mPointRealContainerLp);\n        mPointContainerRl.setVisibility(GONE);\n        //设置指示器布局位置\n        if (mPointPosition == CENTER) {\n            mPointRealContainerLp.addRule(RelativeLayout.CENTER_HORIZONTAL);\n        } else if (mPointPosition == LEFT) {\n            mPointRealContainerLp.addRule(RelativeLayout.ALIGN_PARENT_LEFT);\n        } else if (mPointPosition == RIGHT) {\n            mPointRealContainerLp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);\n        }\n    }\n\n    /**\n     * 设置本地图片\n     */\n    public void setImages(List<Integer> images) {\n        //加载本地图片\n        mIsImageUrl = false;\n        mIsOneImg = false;\n\n        this.mImages = images;\n        if (images.size() <= 1)\n            mIsOneImg = true;\n\n        //初始化ViewPager\n        initViewPager();\n    }\n\n    /**\n     * 设置网络图片\n     */\n    public void setImagesUrl(List<String> urls) {\n        //加载网络图片\n        mIsImageUrl = true;\n        mIsOneImg = false;\n\n        this.mImageUrls = urls;\n        if (urls.size() <= 1)\n            mIsOneImg = true;\n        //初始化ViewPager\n        initViewPager();\n    }\n\n    /**\n     * 设置指示点是否可见\n     */\n    public void setPointsIsVisible(boolean isVisible) {\n        if (mPointContainerRl != null) {\n            if (isVisible) {\n                mPointContainerRl.setVisibility(View.VISIBLE);\n            } else {\n                mPointContainerRl.setVisibility(View.GONE);\n            }\n        }\n    }\n\n    /**\n     * 对应三个位置 CENTER,RIGHT,LEFT\n     */\n    public void setPoinstPosition(int position) {\n        //设置指示器布局位置\n        if (position == CENTER) {\n            mPointRealContainerLp.addRule(RelativeLayout.CENTER_HORIZONTAL);\n        } else if (position == LEFT) {\n            mPointRealContainerLp.addRule(RelativeLayout.ALIGN_PARENT_LEFT);\n        } else if (position == RIGHT) {\n            mPointRealContainerLp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);\n        }\n    }\n\n    private void initViewPager() {\n        //当图片多于1张时添加指示点\n        mPointRealContainerLl.removeAllViews();\n        mPointContainerRl.setVisibility(GONE);\n        if (!mIsOneImg) {\n            addPoints();\n        }\n        //设置ViewPager\n        AdPageAdapter adapter = new AdPageAdapter();\n        mViewPager.setAdapter(adapter);\n        mViewPager.addOnPageChangeListener(mOnPageChangeListener);\n        //跳转到首页\n        mViewPager.setCurrentItem(1, false);\n        //当图片多于1张时开始轮播\n        if (!mIsOneImg) {\n            startAutoPlay();\n        } else {\n            stopAutoPlay();\n        }\n    }\n\n    /**\n     * 返回真实的位置\n     */\n    private int toRealPosition(int position) {\n        int realPosition;\n        if (mIsImageUrl) {\n            realPosition = (position - 1) % mImageUrls.size();\n            if (realPosition < 0)\n                realPosition += mImageUrls.size();\n        } else {\n            realPosition = (position - 1) % mImages.size();\n            if (realPosition < 0)\n                realPosition += mImages.size();\n        }\n\n        return realPosition;\n    }\n\n    private ViewPager.OnPageChangeListener mOnPageChangeListener = new ViewPager.OnPageChangeListener() {\n        @Override\n        public void onPageScrolled(int position, float positionOffset,\n                                   int positionOffsetPixels) {\n        }\n\n        @Override\n        public void onPageSelected(int position) {\n            if (mIsImageUrl) {\n                mCurrentPositon = position % (mImageUrls.size() + 2);\n            } else {\n                mCurrentPositon = position % (mImages.size() + 2);\n            }\n            switchToPoint(toRealPosition(mCurrentPositon));\n        }\n\n        @Override\n        public void onPageScrollStateChanged(int state) {\n            int current = mViewPager.getCurrentItem();\n            int lastReal = mViewPager.getAdapter().getCount() - 2;\n\n            if (state == ViewPager.SCROLL_STATE_IDLE) {\n                if (current == 0) {\n                    mViewPager.setCurrentItem(lastReal, false);\n                } else if (current == lastReal + 1) {\n                    mViewPager.setCurrentItem(1, false);\n                }\n            } else if (state == ViewPager.SCROLL_STATE_DRAGGING) {\n                if (current == lastReal + 1) {\n                    mViewPager.setCurrentItem(1, false);\n                } else if (current == 0) {\n                    mViewPager.setCurrentItem(lastReal, false);\n                }\n            }\n        }\n    };\n\n\n    private class AdPageAdapter extends PagerAdapter {\n\n        @Override\n        public int getCount() {\n            //当只有一张图片时返回1\n            if (mIsOneImg) {\n                return 1;\n            }\n            //当为网络图片，返回网页图片长度\n            if (mIsImageUrl)\n                return mImageUrls.size() + 2;\n            //当为本地图片，返回本地图片长度\n            return mImages.size() + 2;\n        }\n\n        @Override\n        public boolean isViewFromObject(View view, Object object) {\n            return view == object;\n        }\n\n        @Override\n        public Object instantiateItem(ViewGroup container, final int position) {\n            ImageView imageView = new ImageView(getContext());\n            imageView.setOnClickListener(new OnClickListener() {\n                @Override\n                public void onClick(View view) {\n                    if (mOnItemClickListener != null) {\n                        mOnItemClickListener.onItemClick(toRealPosition(position));\n                    }\n                }\n            });\n            imageView.setScaleType(ImageView.ScaleType.FIT_XY);\n            if (mIsImageUrl) {\n//                Glide.with(getContext()).load(mImageUrls.get(toRealPosition(position))).asBitmap().into(imageView);\n            } else {\n                imageView.setImageResource(mImages.get(toRealPosition(position)));\n            }\n            container.addView(imageView);\n\n            return imageView;\n        }\n\n        @Override\n        public void destroyItem(ViewGroup container, int position, Object object) {\n            container.removeView((View) object);\n        }\n    }\n\n    /**\n     * 添加指示点\n     */\n    private void addPoints() {\n        //设置指示器容器是否可见\n        if (mPointsIsVisible) {\n            mPointContainerRl.setVisibility(View.VISIBLE);\n        }\n\n        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LWC, LWC);\n        lp.setMargins(10, 10, 10, 10);\n        ImageView imageView;\n        int length = mIsImageUrl ? mImageUrls.size() : mImages.size();\n        for (int i = 0; i < length; i++) {\n            imageView = new ImageView(getContext());\n            imageView.setLayoutParams(lp);\n            imageView.setImageResource(mPointDrawableResId);\n            mPointRealContainerLl.addView(imageView);\n        }\n        switchToPoint(0);\n    }\n\n    /**\n     * 切换指示器\n     */\n    private void switchToPoint(final int currentPoint) {\n        for (int i = 0; i < mPointRealContainerLl.getChildCount(); i++) {\n            mPointRealContainerLl.getChildAt(i).setEnabled(false);\n        }\n        mPointRealContainerLl.getChildAt(currentPoint).setEnabled(true);\n\n    }\n\n    @Override\n    public boolean dispatchTouchEvent(MotionEvent ev) {\n        if (mAutoPlayAble && !mIsOneImg) {\n            switch (ev.getAction()) {\n                case MotionEvent.ACTION_DOWN:\n                    stopAutoPlay();\n                    break;\n                case MotionEvent.ACTION_UP:\n                case MotionEvent.ACTION_CANCEL:\n                case MotionEvent.ACTION_OUTSIDE:\n                    startAutoPlay();\n                    break;\n            }\n        }\n        return super.dispatchTouchEvent(ev);\n    }\n\n    /**\n     * 开始播放\n     */\n    public void startAutoPlay() {\n        if (mAutoPlayAble && !mIsAutoPlaying) {\n            mIsAutoPlaying = true;\n            mAutoPlayHandler.sendEmptyMessageDelayed(WAIT_AUTO_PLAY, mAutoPalyTime);\n        }\n    }\n\n    /**\n     * 停止播放\n     */\n    public void stopAutoPlay() {\n        if (mAutoPlayAble && mIsAutoPlaying) {\n            mIsAutoPlaying = false;\n            mAutoPlayHandler.removeMessages(WAIT_AUTO_PLAY);\n        }\n    }\n\n    private OnItemClickListener mOnItemClickListener;\n\n    public void setOnItemClickListener(OnItemClickListener listener) {\n        this.mOnItemClickListener = listener;\n    }\n\n    public interface OnItemClickListener {\n        void onItemClick(int position);\n    }\n\n    @Override\n    protected void onVisibilityChanged(@NonNull View changedView, int visibility) {\n        super.onVisibilityChanged(changedView, visibility);\n        if (visibility == View.VISIBLE) {\n            if (mIsImageUrl && mImageUrls != null && mImageUrls.size() > 1) {\n                startAutoPlay();\n            } else if (!mIsImageUrl && mImages != null && mImages.size() > 1) {\n                startAutoPlay();\n            }\n        } else {\n            stopAutoPlay();\n        }\n    }\n\n    @Override\n    protected void onDetachedFromWindow() {\n        super.onDetachedFromWindow();\n        mAutoPlayHandler.removeCallbacksAndMessages(null);\n    }\n}\n"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/widget/HeaderFloatBehavior.java",
    "content": "package gorden.krefreshlayout.demo.widget;\n\nimport android.animation.ArgbEvaluator;\nimport android.content.Context;\nimport android.content.res.Resources;\nimport android.support.design.widget.CoordinatorLayout;\nimport android.util.AttributeSet;\nimport android.view.View;\n\n\nimport java.lang.ref.WeakReference;\n\nimport gorden.krefreshlayout.demo.R;\n\n/**\n * Created by cyandev on 2016/12/14.\n */\npublic class HeaderFloatBehavior extends CoordinatorLayout.Behavior<View> {\n\n    private WeakReference<View> dependentView;\n    private ArgbEvaluator argbEvaluator;\n\n    public HeaderFloatBehavior(Context context, AttributeSet attrs) {\n        super(context, attrs);\n\n        argbEvaluator = new ArgbEvaluator();\n    }\n\n    @Override\n    public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) {\n        if (dependency != null && dependency.getId() == R.id.scrolling_header) {\n            dependentView = new WeakReference<>(dependency);\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    public boolean onDependentViewChanged(CoordinatorLayout parent, View child, View dependency) {\n        Resources resources = getDependentView().getResources();\n        final float progress = 1.f -\n                Math.abs(dependency.getTranslationY() / (dependency.getHeight() - resources.getDimension(R.dimen.collapsed_header_height)));\n\n        // Translation\n        final float collapsedOffset = resources.getDimension(R.dimen.collapsed_float_offset_y);\n        final float initOffset = resources.getDimension(R.dimen.init_float_offset_y);\n        final float translateY = collapsedOffset + (initOffset - collapsedOffset) * progress;\n        child.setTranslationY(translateY);\n\n        // Background\n        child.setBackgroundColor((int) argbEvaluator.evaluate(\n                progress,\n                resources.getColor(R.color.colorCollapsedFloatBackground),\n                resources.getColor(R.color.colorInitFloatBackground)));\n\n        // Margins\n        final float collapsedMargin = resources.getDimension(R.dimen.collapsed_float_margin);\n        final float initMargin = resources.getDimension(R.dimen.init_float_margin);\n        final int margin = (int) (collapsedMargin + (initMargin - collapsedMargin) * progress);\n        CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) child.getLayoutParams();\n        lp.setMargins(margin, 0, margin, 0);\n        child.setLayoutParams(lp);\n\n        return true;\n    }\n\n    private View getDependentView() {\n        return dependentView.get();\n    }\n\n}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/widget/HeaderScrollingBehavior.java",
    "content": "package gorden.krefreshlayout.demo.widget;\n\nimport android.content.Context;\nimport android.content.res.Resources;\nimport android.os.Handler;\nimport android.support.design.widget.CoordinatorLayout;\nimport android.support.v4.view.ViewCompat;\nimport android.support.v7.widget.RecyclerView;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.widget.Scroller;\n\n\nimport java.lang.ref.WeakReference;\n\nimport gorden.krefreshlayout.demo.R;\n\n\npublic class HeaderScrollingBehavior extends CoordinatorLayout.Behavior<RecyclerView> {\n\n    private boolean isExpanded = false;\n    private boolean isScrolling = false;\n\n    private WeakReference<View> dependentView;\n    private Scroller scroller;\n    private Handler handler;\n\n    public HeaderScrollingBehavior(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        scroller = new Scroller(context);\n        handler = new Handler();\n    }\n\n    public boolean isExpanded() {\n        return isExpanded;\n    }\n\n    @Override\n    public boolean layoutDependsOn(CoordinatorLayout parent, RecyclerView child, View dependency) {\n        if (dependency != null && dependency.getId() == R.id.scrolling_header) {\n            dependentView = new WeakReference<>(dependency);\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    public boolean onLayoutChild(CoordinatorLayout parent, RecyclerView child, int layoutDirection) {\n        CoordinatorLayout.LayoutParams lp = (CoordinatorLayout.LayoutParams) child.getLayoutParams();\n        if (lp.height == CoordinatorLayout.LayoutParams.MATCH_PARENT) {\n            child.layout(0, 0, parent.getWidth(), (int) (parent.getHeight() - getDependentViewCollapsedHeight()));\n            return true;\n        }\n        return super.onLayoutChild(parent, child, layoutDirection);\n    }\n\n    @Override\n    public boolean onDependentViewChanged(CoordinatorLayout parent, RecyclerView child, View dependency) {\n        Resources resources = getDependentView().getResources();\n        final float progress = 1.f -\n                Math.abs(dependency.getTranslationY() / (dependency.getHeight() - resources.getDimension(R.dimen.collapsed_header_height)));\n\n        child.setTranslationY(dependency.getHeight() + dependency.getTranslationY());\n\n        float scale = 1 + 0.4f * (1.f - progress);\n        dependency.setScaleX(scale);\n        dependency.setScaleY(scale);\n\n        dependency.setAlpha(progress);\n\n        return true;\n    }\n\n    @Override\n    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, RecyclerView child, View directTargetChild, View target, int nestedScrollAxes) {\n        return (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;\n    }\n\n    @Override\n    public void onNestedScrollAccepted(CoordinatorLayout coordinatorLayout, RecyclerView child, View directTargetChild, View target, int nestedScrollAxes) {\n        scroller.abortAnimation();\n        isScrolling = false;\n\n        super.onNestedScrollAccepted(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);\n    }\n\n    @Override\n    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, RecyclerView child, View target, int dx, int dy, int[] consumed) {\n        if (dy < 0) {\n            return;\n        }\n\n        View dependentView = getDependentView();\n        float newTranslateY = dependentView.getTranslationY() - dy;\n        float minHeaderTranslate = -(dependentView.getHeight() - getDependentViewCollapsedHeight());\n\n        if (newTranslateY > minHeaderTranslate) {\n            dependentView.setTranslationY(newTranslateY);\n            consumed[1] = dy;\n        }\n    }\n\n    @Override\n    public void onNestedScroll(CoordinatorLayout coordinatorLayout, RecyclerView child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {\n        if (dyUnconsumed > 0) {\n            return;\n        }\n\n        View dependentView = getDependentView();\n        float newTranslateY = dependentView.getTranslationY() - dyUnconsumed;\n        final float maxHeaderTranslate = 0;\n\n        if (newTranslateY < maxHeaderTranslate) {\n            dependentView.setTranslationY(newTranslateY);\n        }\n    }\n\n    @Override\n    public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, RecyclerView child, View target, float velocityX, float velocityY) {\n        return onUserStopDragging(velocityY);\n    }\n\n    @Override\n    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, RecyclerView child, View target) {\n        if (!isScrolling) {\n            onUserStopDragging(800);\n        }\n    }\n\n    private boolean onUserStopDragging(float velocity) {\n        View dependentView = getDependentView();\n        float translateY = dependentView.getTranslationY();\n        float minHeaderTranslate = -(dependentView.getHeight() - getDependentViewCollapsedHeight());\n\n        if (translateY == 0 || translateY == minHeaderTranslate) {\n            return false;\n        }\n\n        boolean targetState; // Flag indicates whether to expand the content.\n        if (Math.abs(velocity) <= 800) {\n            if (Math.abs(translateY) < Math.abs(translateY - minHeaderTranslate)) {\n                targetState = false;\n            } else {\n                targetState = true;\n            }\n            velocity = 800; // Limit velocity's minimum value.\n        } else {\n            if (velocity > 0) {\n                targetState = true;\n            } else {\n                targetState = false;\n            }\n        }\n\n        float targetTranslateY = targetState ? minHeaderTranslate : 0;\n\n        scroller.startScroll(0, (int) translateY, 0, (int) (targetTranslateY - translateY), (int) (1000000 / Math.abs(velocity)));\n        handler.post(flingRunnable);\n        isScrolling = true;\n        return true;\n    }\n\n    private float getDependentViewCollapsedHeight() {\n        return getDependentView().getResources().getDimension(R.dimen.collapsed_header_height);\n    }\n\n    private View getDependentView() {\n        return dependentView.get();\n    }\n\n    private Runnable flingRunnable = new Runnable() {\n        @Override\n        public void run() {\n            if (scroller.computeScrollOffset()) {\n                getDependentView().setTranslationY(scroller.getCurrY());\n                handler.post(this);\n            } else {\n                isExpanded = getDependentView().getTranslationY() != 0;\n                isScrolling = false;\n            }\n        }\n    };\n\n}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/widget/recyclerview/KLoadMoreView.kt",
    "content": "package gorden.krefreshlayout.demo.widget.recyclerview\n\ninterface KLoadMoreView {\n    /**\n     * 自定义适当的加载时机\n     * @return true 自定义生效 false默认的加载时机\n     */\n    fun shouldLoadMore(recyclerView: KRecyclerView):Boolean\n\n    /**\n     * 正在加载\n     */\n    fun onLoadMore(recyclerView: KRecyclerView)\n\n    /**\n     * 加载完成\n     * @param hasMore 是否还有更多数据\n     */\n    fun onComplete(recyclerView: KRecyclerView, hasMore:Boolean)\n\n    /**\n     * 加载失败\n     * @param errorCode 错误码，由用户定义\n     */\n    fun onError(recyclerView: KRecyclerView, errorCode:Int)\n}"
  },
  {
    "path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/widget/recyclerview/KRecyclerView.kt",
    "content": "package gorden.krefreshlayout.demo.widget.recyclerview\n\nimport android.content.Context\nimport android.support.v4.util.SparseArrayCompat\nimport android.support.v7.widget.GridLayoutManager\nimport android.support.v7.widget.RecyclerView\nimport android.support.v7.widget.StaggeredGridLayoutManager\nimport android.util.AttributeSet\nimport android.view.View\nimport android.view.ViewGroup\n\n@Suppress(\"unused\")\n/**\n * 支持添加Header Footer\n * 支持加载更多\n */\nclass KRecyclerView(context: Context, attrs: AttributeSet?, defStyle: Int) : RecyclerView(context, attrs, defStyle) {\n    private val ITEM_TYPE_HEADER_INIT = 100000\n    private val ITEM_TYPE_FOOTER_INIT = 200000\n    private val ITEM_TYPE_LOADMORE = 300000\n\n    var hasMore: Boolean = false\n        set(value) {\n            field = value\n            if (value) showMore = true\n        }\n    var showMore:Boolean = false\n    private var mLoading: Boolean = false\n    var loadMoreEnable: Boolean = true\n\n    private var mWrapAdapter: WrapAdapter = WrapAdapter()\n    private var mInnerAdapter: Adapter<ViewHolder>? = null\n\n    private var mLoadMoreView: KLoadMoreView? = null\n    private val mHeaderViews = SparseArrayCompat<View>()\n    private val mFooterViews = SparseArrayCompat<View>()\n\n    private var mLoadMoreListener: ((RecyclerView) -> Unit)? = null\n\n    constructor(context: Context) : this(context, null)\n    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)\n\n    override fun setAdapter(adapter: Adapter<ViewHolder>?) {\n        if (mInnerAdapter!=null){\n            mInnerAdapter?.unregisterAdapterDataObserver(mDataObserver)\n        }\n        mInnerAdapter = adapter\n        mInnerAdapter?.registerAdapterDataObserver(mDataObserver)\n        super.setAdapter(mWrapAdapter)\n    }\n\n    /**\n     * 添加HeaderView\n     */\n    fun addHeaderView(view: View) {\n        mHeaderViews.put(mHeaderViews.size() + ITEM_TYPE_HEADER_INIT, view)\n        mWrapAdapter.notifyDataSetChanged()\n    }\n\n    /**\n     * 添加FooterView\n     */\n    fun addFooterView(view: View) {\n        mFooterViews.put(mFooterViews.size() + ITEM_TYPE_FOOTER_INIT, view)\n        mWrapAdapter.notifyDataSetChanged()\n    }\n\n    /**\n     * 设置LoadMoreView\n     * 必须是一个视图View\n     */\n    fun setLoadMoreView(loadMoreView: KLoadMoreView) {\n        if (loadMoreView !is View) {\n            throw IllegalStateException(\"KLoadMoreView must is a View?\")\n        }\n\n        this.mLoadMoreView = loadMoreView\n\n        mWrapAdapter.notifyDataSetChanged()\n\n        removeOnScrollListener(defaultScrollListener)\n        if (!(mLoadMoreView?.shouldLoadMore(this) ?: true)) {\n            addOnScrollListener(defaultScrollListener)\n        }\n    }\n\n    /**\n     * 开始加载更多\n     */\n    fun startLoadMore() {\n        if (!mLoading && loadMoreEnable && hasMore) {\n            mLoading = true\n            mLoadMoreView?.onLoadMore(this)\n            mLoadMoreListener?.invoke(this)\n        }\n    }\n\n    /**\n     * 加载完成\n     */\n    fun loadMoreComplete(hasMore: Boolean) {\n        mLoading = false\n        mLoadMoreView?.onComplete(this, hasMore)\n        this.hasMore = hasMore\n    }\n\n    fun loadMoreError(errorCode: Int) {\n        mLoading = false\n        mLoadMoreView?.onError(this, errorCode)\n    }\n\n    /**\n     * 设置加载更多监听\n     */\n    fun setLoadMoreListener(loadMoreListener: (recyclerView: RecyclerView) -> Unit): Unit {\n        mLoadMoreListener = loadMoreListener\n    }\n\n    /**\n     * 默认的加载触发时机\n     */\n    private val defaultScrollListener = object : OnScrollListener() {\n        override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {\n            if (!recyclerView.canScrollVertically(1)) {\n                startLoadMore()\n            }\n        }\n    }\n\n    private inner class WrapAdapter : Adapter<ViewHolder>() {\n        override fun onBindViewHolder(holder: ViewHolder, position: Int) {\n            if (!isContent(position)) {\n                return\n            }\n            mInnerAdapter?.onBindViewHolder(holder, position - mHeaderViews.size())\n        }\n\n        override fun getItemCount(): Int {\n            val adapterCount = mInnerAdapter?.itemCount ?: 0\n\n            if (adapterCount > 0) {\n                return adapterCount + mHeaderViews.size() + mFooterViews.size() + if (mLoadMoreView == null||!showMore) 0 else 1\n            } else {//防止没有内容的时候加载更多显示出来\n                return mHeaderViews.size() + mFooterViews.size()\n            }\n        }\n\n        override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder? {\n            if (mHeaderViews[viewType] != null) {\n                return object : ViewHolder(mHeaderViews[viewType]) {\n                    init {\n                        itemView.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)\n                    }\n                }\n            }\n            if (viewType == ITEM_TYPE_LOADMORE)\n                return object : ViewHolder(mLoadMoreView as View) {\n                    init {\n                        itemView.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)\n                    }\n                }\n\n            if (mFooterViews[viewType] != null) {\n                return object : ViewHolder(mFooterViews[viewType]) {\n                    init {\n                        itemView.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)\n                    }\n                }\n            }\n            return mInnerAdapter?.onCreateViewHolder(parent, viewType)\n        }\n\n        override fun getItemViewType(position: Int): Int {\n            if (position < mHeaderViews.size()) {\n                return mHeaderViews.keyAt(position)\n            }\n\n            if (mLoadMoreView != null && position == itemCount - 1&&showMore) {\n                return ITEM_TYPE_LOADMORE\n            }\n\n            if (position >= mHeaderViews.size() + (mInnerAdapter?.itemCount ?: 0)) {\n                return mFooterViews.keyAt(position - mHeaderViews.size() - (mInnerAdapter?.itemCount ?: 0))\n            }\n\n            return mInnerAdapter?.getItemViewType(position - mHeaderViews.size()) ?: -1\n        }\n\n        override fun onAttachedToRecyclerView(recyclerView: RecyclerView?) {\n            mInnerAdapter?.onAttachedToRecyclerView(recyclerView)\n            val layoutManager = layoutManager\n            if (layoutManager is GridLayoutManager) {\n                layoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {\n                    override fun getSpanSize(position: Int): Int {\n                        if (!isContent(position)) {\n                            return layoutManager.spanCount\n                        }\n                        return 1\n                    }\n                }\n            }\n        }\n\n        override fun onViewAttachedToWindow(holder: ViewHolder) {\n            mInnerAdapter?.onViewAttachedToWindow(holder)\n            val position = holder.layoutPosition\n            val layoutParams = holder.itemView.layoutParams\n            if (!isContent(position) && layoutParams != null && layoutParams is StaggeredGridLayoutManager.LayoutParams) {\n                layoutParams.isFullSpan = true\n            }\n        }\n\n        fun isContent(position: Int): Boolean {\n            if (position < mHeaderViews.size())\n                return false\n            if (mLoadMoreView != null && position == itemCount - 1)\n                return false\n            if (position >= mHeaderViews.size() + (mInnerAdapter?.itemCount ?: 0))\n                return false\n            return true\n        }\n\n    }\n\n    private val mDataObserver = object : AdapterDataObserver() {\n        override fun onChanged() {\n            mWrapAdapter.notifyDataSetChanged()\n        }\n\n        override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {\n            mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount)\n        }\n\n        override fun onItemRangeChanged(positionStart: Int, itemCount: Int, payload: Any?) {\n            mWrapAdapter.notifyItemRangeChanged(positionStart, itemCount, payload)\n        }\n\n        override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {\n            mWrapAdapter.notifyItemRangeInserted(positionStart, itemCount)\n        }\n\n        override fun onItemRangeMoved(fromPosition: Int, toPosition: Int, itemCount: Int) {\n            mWrapAdapter.notifyItemMoved(fromPosition, toPosition)\n        }\n\n        override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {\n            mWrapAdapter.notifyItemRangeRemoved(positionStart, itemCount)\n        }\n    }\n}"
  },
  {
    "path": "app_kotlin/src/main/res/drawable/bg_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <gradient android:angle=\"45\"\n        android:startColor=\"#b30d5a\"\n        android:centerColor=\"#5d06cf\"\n        android:endColor=\"#0aa68c\"\n        />\n</shape>"
  },
  {
    "path": "app_kotlin/src/main/res/drawable/selector_adpager_point.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_enabled=\"true\">\n        <shape android:shape=\"oval\">\n            <size android:width=\"6dp\" android:height=\"6dp\" />\n            <solid android:color=\"@android:color/white\" />\n        </shape>\n    </item>\n    <item>\n        <shape android:shape=\"oval\">\n            <size android:width=\"6dp\" android:height=\"6dp\" />\n            <solid android:color=\"#666\" />\n        </shape>\n    </item>\n</selector>"
  },
  {
    "path": "app_kotlin/src/main/res/layout/activity_header_list.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout 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:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@drawable/bg_main\"\n    tools:ignore=\"HardcodedText\"\n    tools:context=\"gorden.krefreshlayout.demo.ui.HeaderListActivity\">\n    <android.support.v4.widget.NestedScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:padding=\"10dp\"\n            android:orientation=\"vertical\">\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"100dp\"\n                android:orientation=\"horizontal\">\n                <Button\n                    android:id=\"@+id/btn_classical\"\n                    android:text=\"RecyclerView\"\n                    style=\"@style/btn_item\"\n                    />\n                <Button\n                    android:id=\"@+id/btn_rentalsun\"\n                    style=\"@style/btn_item_center\"\n                    android:text=\"RentalSun\"\n                    />\n                <Button\n                    android:text=\"Materia\"\n                    style=\"@style/btn_item\"\n                    />\n            </LinearLayout>\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"10dp\"\n                android:orientation=\"horizontal\">\n                <Button\n                    android:text=\"Classical\"\n                    style=\"@style/btn_item\"\n                    />\n                <Button\n                    style=\"@style/btn_item_center\"\n                    android:text=\"RentalSun\"\n                    />\n                <Button\n                    android:text=\"Materia\"\n                    style=\"@style/btn_item\"\n                    />\n            </LinearLayout>\n        </LinearLayout>\n    </android.support.v4.widget.NestedScrollView>\n</RelativeLayout>\n"
  },
  {
    "path": "app_kotlin/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout 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:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@drawable/bg_main\"\n    tools:ignore=\"HardcodedText\"\n    >\n    <gorden.refresh.KRefreshLayout\n        android:id=\"@+id/refreshLayout\"\n        android:layout_width=\"match_parent\"\n        app:k_def_max_offset=\"match_parent\"\n        android:layout_height=\"match_parent\">\n        <GridView\n            android:id=\"@+id/gridView\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:numColumns=\"3\"\n            android:verticalSpacing=\"5dp\"\n            android:horizontalSpacing=\"5dp\"\n            />\n    </gorden.refresh.KRefreshLayout>\n</RelativeLayout>\n"
  },
  {
    "path": "app_kotlin/src/main/res/layout/activity_sample.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@drawable/bg_main\"\n    >\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\"\n        android:background=\"#88000000\"\n        >\n        <android.support.v7.widget.AppCompatImageButton\n            android:id=\"@+id/btn_back\"\n            android:layout_width=\"50dp\"\n            android:layout_height=\"match_parent\"\n            android:src=\"@drawable/ic_back\"\n            android:padding=\"8dp\"\n            android:scaleType=\"centerInside\"\n            android:background=\"@null\"\n            />\n        <TextView\n            android:id=\"@+id/text_title\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerVertical=\"true\"\n            android:text=\"RecyclerView\"\n            android:textColor=\"#9ef7df\"\n            android:textSize=\"18sp\"\n            android:lines=\"1\"\n            android:layout_marginRight=\"50dp\"\n            android:ellipsize=\"end\"\n            android:layout_toRightOf=\"@id/btn_back\"\n            />\n        <android.support.v7.widget.AppCompatImageButton\n            android:id=\"@+id/btn_setting\"\n            android:layout_width=\"50dp\"\n            android:layout_height=\"match_parent\"\n            android:layout_alignParentRight=\"true\"\n            android:scaleType=\"centerInside\"\n            android:src=\"@drawable/ic_setting\"\n            android:padding=\"15dp\"\n            android:background=\"@null\"\n            />\n    </RelativeLayout>\n    <FrameLayout\n        android:id=\"@+id/frame_content\"\n        android:layout_marginTop=\"50dp\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        />\n</RelativeLayout>\n"
  },
  {
    "path": "app_kotlin/src/main/res/layout/activity_setting.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:background=\"@drawable/bg_main\"\n    >\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\"\n        android:background=\"#88000000\"\n        >\n        <android.support.v7.widget.AppCompatImageButton\n            android:id=\"@+id/btn_back\"\n            android:layout_width=\"50dp\"\n            android:layout_height=\"match_parent\"\n            android:src=\"@drawable/ic_back\"\n            android:padding=\"8dp\"\n            android:scaleType=\"centerInside\"\n            android:background=\"@null\"\n            />\n        <TextView\n            android:id=\"@+id/text_title\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerVertical=\"true\"\n            android:text=\"设置\"\n            android:textColor=\"#9ef7df\"\n            android:textSize=\"18sp\"\n            android:lines=\"1\"\n            android:layout_marginRight=\"50dp\"\n            android:ellipsize=\"end\"\n            android:layout_toRightOf=\"@id/btn_back\"\n            />\n    </RelativeLayout>\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"horizontal\">\n        <TextView\n            android:layout_width=\"150dp\"\n            android:layout_height=\"match_parent\"\n            android:gravity=\"center_vertical\"\n            android:paddingLeft=\"20dp\"\n            android:textColor=\"#13ca39\"\n            android:textStyle=\"bold\"\n            android:textSize=\"15sp\"\n            android:text=\"HeaderStyle\"\n            />\n        <Spinner\n            android:id=\"@+id/spinner\"\n            android:layout_width=\"match_parent\"\n            android:spinnerMode=\"dropdown\"\n            android:entries=\"@array/header_style\"\n            android:layout_height=\"50dp\"/>\n    </LinearLayout>\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1dp\"\n        android:background=\"#0b8b18\"\n        />\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"horizontal\">\n        <TextView\n            android:layout_width=\"150dp\"\n            android:layout_height=\"match_parent\"\n            android:gravity=\"center_vertical\"\n            android:paddingLeft=\"20dp\"\n            android:textColor=\"#13ca39\"\n            android:textStyle=\"bold\"\n            android:textSize=\"15sp\"\n            android:text=\"PinContent\"\n            />\n        <ToggleButton\n            android:id=\"@+id/togglePinContent\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\" />\n    </LinearLayout>\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1dp\"\n        android:background=\"#0b8b18\"\n        />\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"horizontal\">\n        <TextView\n            android:layout_width=\"150dp\"\n            android:layout_height=\"match_parent\"\n            android:gravity=\"center_vertical\"\n            android:paddingLeft=\"20dp\"\n            android:textColor=\"#13ca39\"\n            android:textStyle=\"bold\"\n            android:textSize=\"15sp\"\n            android:text=\"KeepHeader\"\n            />\n        <ToggleButton\n            android:id=\"@+id/toggleKeepHeader\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:checked=\"true\"\n            />\n    </LinearLayout>\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1dp\"\n        android:background=\"#0b8b18\"\n        />\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"horizontal\">\n        <TextView\n            android:layout_width=\"150dp\"\n            android:layout_height=\"match_parent\"\n            android:gravity=\"center_vertical\"\n            android:paddingLeft=\"20dp\"\n            android:textColor=\"#13ca39\"\n            android:textStyle=\"bold\"\n            android:textSize=\"15sp\"\n            android:text=\"OffsetTime\"\n            />\n        <EditText\n            android:id=\"@+id/edit_offset\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            />\n    </LinearLayout>\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1dp\"\n        android:background=\"#0b8b18\"\n        />\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"horizontal\">\n        <TextView\n            android:layout_width=\"150dp\"\n            android:layout_height=\"match_parent\"\n            android:gravity=\"center_vertical\"\n            android:paddingLeft=\"20dp\"\n            android:textColor=\"#13ca39\"\n            android:textStyle=\"bold\"\n            android:textSize=\"15sp\"\n            android:text=\"刷新持续时间\"\n            />\n        <EditText\n            android:id=\"@+id/edit_refresh\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            />\n    </LinearLayout>\n    <View\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"1dp\"\n        android:background=\"#0b8b18\"\n        />\n</LinearLayout>\n"
  },
  {
    "path": "app_kotlin/src/main/res/layout/item_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\" android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n    <TextView\n        android:id=\"@+id/textView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"100dp\"\n        android:gravity=\"center\"\n        android:textSize=\"15sp\"\n        android:textColor=\"#fff\"\n        android:background=\"#66000000\"\n        />\n</LinearLayout>"
  },
  {
    "path": "app_kotlin/src/main/res/layout/item_sample.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"100dp\">\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"100dp\"\n        android:paddingLeft=\"10dp\"\n        android:paddingRight=\"10dp\"\n        android:background=\"#ffffff\"\n        android:gravity=\"center_vertical\"\n\n        android:orientation=\"horizontal\">\n        <ImageView\n            android:layout_width=\"100dp\"\n            android:layout_height=\"100dp\"\n            android:src=\"@drawable/img_kotlin\"\n            />\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n            <TextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"This is Sample Item\"\n                android:textColor=\"#333\"\n                android:textSize=\"16sp\"\n                />\n            <TextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"5dp\"\n                android:text=\"This is Sample Item description\"\n                />\n        </LinearLayout>\n    </LinearLayout>\n</RelativeLayout>"
  },
  {
    "path": "app_kotlin/src/main/res/layout/layout_coordinatorlayout.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <gorden.refresh.KRefreshLayout\n        android:id=\"@+id/refreshLayout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <android.support.design.widget.CoordinatorLayout\n            android:id=\"@+id/coordinatorLayout\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:fitsSystemWindows=\"false\">\n\n            <ImageView\n                android:id=\"@+id/scrolling_header\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"200dp\"\n                android:scaleType=\"centerCrop\"\n                android:src=\"@drawable/ic_home\" />\n\n            <TextView\n                android:id=\"@+id/textView\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"40dp\"\n                android:background=\"#88000000\"\n                android:gravity=\"center\"\n                android:text=\"https://github.com/XiaoQiWen/KRefreshLayout\"\n                android:textColor=\"#fff\"\n                android:textSize=\"15sp\"\n                app:layout_behavior=\"@string/header_float_behavior\" />\n\n            <android.support.v7.widget.RecyclerView\n                android:id=\"@+id/recyclerView\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                app:layoutManager=\"LinearLayoutManager\"\n                app:layout_behavior=\"@string/header_scrolling_behavior\" />\n        </android.support.design.widget.CoordinatorLayout>\n    </gorden.refresh.KRefreshLayout>\n</RelativeLayout>"
  },
  {
    "path": "app_kotlin/src/main/res/layout/layout_krecyclerview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\" android:layout_height=\"match_parent\">\n    <gorden.refresh.KRefreshLayout\n        android:id=\"@+id/refreshLayout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n        <gorden.krefreshlayout.demo.widget.recyclerview.KRecyclerView\n            android:id=\"@+id/recyclerView\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"/>\n    </gorden.refresh.KRefreshLayout>\n</RelativeLayout>"
  },
  {
    "path": "app_kotlin/src/main/res/layout/layout_nestedscrollview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\" android:layout_height=\"match_parent\">\n    <gorden.refresh.KRefreshLayout\n        android:id=\"@+id/refreshLayout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n        <android.support.v4.widget.NestedScrollView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"vertical\">\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n            </LinearLayout>\n        </android.support.v4.widget.NestedScrollView>\n    </gorden.refresh.KRefreshLayout>\n</FrameLayout>"
  },
  {
    "path": "app_kotlin/src/main/res/layout/layout_recyclerview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\" android:layout_height=\"match_parent\">\n    <gorden.refresh.KRefreshLayout\n        android:id=\"@+id/refreshLayout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n        <android.support.v7.widget.RecyclerView\n            android:id=\"@+id/recyclerView\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"/>\n    </gorden.refresh.KRefreshLayout>\n</RelativeLayout>"
  },
  {
    "path": "app_kotlin/src/main/res/layout/layout_scrollview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\" android:layout_height=\"match_parent\">\n    <gorden.refresh.KRefreshLayout\n        android:id=\"@+id/refreshLayout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n        <ScrollView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"vertical\">\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n            </LinearLayout>\n        </ScrollView>\n    </gorden.refresh.KRefreshLayout>\n</FrameLayout>"
  },
  {
    "path": "app_kotlin/src/main/res/layout/layout_viewpager.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\" android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n    <android.support.design.widget.TabLayout\n        android:id=\"@+id/tabLayout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\"/>\n    <android.support.v4.view.ViewPager\n        android:id=\"@+id/viewPager\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"/>\n</LinearLayout>"
  },
  {
    "path": "app_kotlin/src/main/res/layout/layout_vp_nestedscrollview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\" android:layout_height=\"match_parent\">\n    <gorden.refresh.KRefreshLayout\n        android:id=\"@+id/refreshLayout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n        <android.support.v4.widget.NestedScrollView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"vertical\">\n                <gorden.krefreshlayout.demo.widget.AdViewPager\n                    android:id=\"@+id/viewPager\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"200dp\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n            </LinearLayout>\n        </android.support.v4.widget.NestedScrollView>\n    </gorden.refresh.KRefreshLayout>\n</RelativeLayout>"
  },
  {
    "path": "app_kotlin/src/main/res/layout/layout_vp_scrollview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\" android:layout_height=\"match_parent\">\n    <gorden.refresh.KRefreshLayout\n        android:id=\"@+id/refreshLayout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n        <ScrollView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n            <LinearLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"vertical\">\n                <gorden.krefreshlayout.demo.widget.AdViewPager\n                    android:id=\"@+id/viewPager\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"200dp\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n                <android.support.v4.widget.Space android:layout_width=\"match_parent\" android:layout_height=\"2dp\" />\n                <include layout=\"@layout/item_sample\"/>\n            </LinearLayout>\n        </ScrollView>\n    </gorden.refresh.KRefreshLayout>\n</RelativeLayout>"
  },
  {
    "path": "app_kotlin/src/main/res/layout/layout_webview.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:orientation=\"vertical\" android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n    <gorden.refresh.KRefreshLayout\n        android:id=\"@+id/refreshLayout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n        <WebView\n            android:id=\"@+id/webView\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"/>\n    </gorden.refresh.KRefreshLayout>\n</LinearLayout>"
  },
  {
    "path": "app_kotlin/src/main/res/values/attrs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <declare-styleable name=\"AdViewPager\">\n        <attr name=\"ad_points_visibility\" format=\"boolean\"/>\n        <attr name=\"ad_points_position\" format=\"enum\">\n            <enum name=\"CENTER\" value=\"0\"/>\n            <enum name=\"LEFT\" value=\"1\"/>\n            <enum name=\"RIGHT\" value=\"2\"/>\n        </attr>\n        <attr name=\"ad_points_container_background\" format=\"reference|color\"/>\n    </declare-styleable>\n</resources>"
  },
  {
    "path": "app_kotlin/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=\"colorInitFloatBackground\">#b0ffffff</color>\n    <color name=\"colorCollapsedFloatBackground\">#e4e4e4</color>\n\n    <array name=\"refresh_color\">\n        <item>#F2A829</item>\n        <item>#FF4081</item>\n        <item>#0b6b1c</item>\n        <item>#151c66</item>\n    </array>\n</resources>\n"
  },
  {
    "path": "app_kotlin/src/main/res/values/dimens.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n    <dimen name=\"fab_margin\">16dp</dimen>\n    <dimen name=\"app_bar_height\">180dp</dimen>\n    <dimen name=\"text_margin\">16dp</dimen>\n    <dimen name=\"collapsed_header_height\">50dp</dimen>\n    <dimen name=\"init_float_offset_y\">130dp</dimen>\n    <dimen name=\"collapsed_float_offset_y\">5dp</dimen>\n    <dimen name=\"init_float_margin\">20dp</dimen>\n    <dimen name=\"collapsed_float_margin\">5dp</dimen>\n</resources>"
  },
  {
    "path": "app_kotlin/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">KRefreshLayout</string>\n\n    <string name=\"header_scrolling_behavior\">gorden.krefreshlayout.demo.widget.HeaderScrollingBehavior</string>\n    <string name=\"header_float_behavior\">gorden.krefreshlayout.demo.widget.HeaderFloatBehavior</string>\n    \n    <string-array name=\"header_style\">\n        <item>ClassicalHeader</item>\n        <item>MateriaHeader</item>\n        <item>RentalsSunHeader</item>\n        <item>StoreHouseHeader</item>\n        <item>CircleHeader</item>\n        <item>FunGameHeader</item>\n        <item>WechatHeader</item>\n    </string-array>\n</resources>\n"
  },
  {
    "path": "app_kotlin/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.NoActionBar\">\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\n    <style name=\"btn_item\">\n        <item name=\"android:layout_width\">0dp</item>\n        <item name=\"android:layout_weight\">1</item>\n        <item name=\"android:layout_height\">match_parent</item>\n        <item name=\"android:textColor\">#666666</item>\n        <item name=\"android:background\">#88ffffff</item>\n        <item name=\"android:textAllCaps\">false</item>\n        <item name=\"android:textSize\">15sp</item>\n        <item name=\"android:gravity\">center</item>\n    </style>\n\n    <style name=\"btn_item_center\" parent=\"btn_item\">\n        <item name=\"android:layout_marginLeft\">10dp</item>\n        <item name=\"android:layout_marginRight\">10dp</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "bintrayUpload.gradle",
    "content": "apply plugin: 'com.jfrog.bintray'\napply plugin: 'com.github.dcendents.android-maven'\napply plugin: 'org.jetbrains.dokka-android' //TODO kotlin\n\nProperties properties = new Properties()\nFile projectPropertiesFile = project.file(\"project.properties\")\nif(projectPropertiesFile.exists()){\n    properties.load(projectPropertiesFile.newDataInputStream())\n}\n\n// read properties\ndef projectName = properties.getProperty(\"project.name\")\ndef projectGroupId = properties.getProperty(\"project.groupId\")\ndef projectArtifactId = properties.getProperty(\"project.artifactId\")\ndef projectVersionName = android.defaultConfig.versionName\ndef projectPackaging = properties.getProperty(\"project.packaging\")\ndef projectSiteUrl = properties.getProperty(\"project.siteUrl\")\ndef projectGitUrl = properties.getProperty(\"project.gitUrl\")\n\ndef javadocName = properties.getProperty(\"javadoc.name\")\n\n//read local.properties\nFile localPropertiesFile = project.rootProject.file(\"local.properties\")\nif(localPropertiesFile.exists()){\n    properties.load(localPropertiesFile.newDataInputStream())\n}\n\ndef developerId = properties.getProperty(\"developer.id\")\ndef developerName = properties.getProperty(\"developer.name\")\ndef developerEmail = properties.getProperty(\"developer.email\")\n\ndef bintrayUser = properties.getProperty(\"bintray.user\")\ndef bintrayApikey = properties.getProperty(\"bintray.apikey\")\n\ngroup = projectGroupId\nversion = projectVersionName\n\n// This generates POM.xml with proper parameters  //TODO java\n//install {\n//    repositories.mavenInstaller {\n//        pom {\n//            project {\n//                name projectName\n//                groupId projectGroupId\n//                artifactId projectArtifactId\n//                version projectVersionName\n//                packaging projectPackaging\n//                url projectSiteUrl\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//                developers {\n//                    developer {\n//                        id developerId\n//                        name developerName\n//                        email developerEmail\n//                    }\n//                }\n//                scm {\n//                    connection projectGitUrl\n//                    developerConnection projectGitUrl\n//                    url projectSiteUrl\n//                }\n//            }\n//        }\n//    }\n//}\n\n// This generates sources.jar\ntask sourcesJar(type: Jar) {\n    from android.sourceSets.main.java.srcDirs\n    classifier = 'sources'\n}\n\n//task javadoc(type: Javadoc) { //TODO java\n//    source = android.sourceSets.main.java.srcDirs\n//    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))\n//}\n\n//This generates javadoc.jar\n//task javadocJar(type: Jar, dependsOn: javadoc) {//TODO java\n//    classifier = 'javadoc'\n//    from javadoc.destinationDir\n//}\n\ndokka { //TODO kotlin\n    outputFormat = 'javadoc'\n    outputDirectory = \"$buildDir/javadoc\"\n}\n\ntask dokkaJavadocJar(type:Jar,dependsOn: dokka) {   //TODO kotlin\n    classifier = 'javadoc'\n    from dokka.outputDirectory\n}\n\nartifacts {\n//    archives javadocJar //TODO java\n    archives dokkaJavadocJar    //TODO kotlin\n    archives sourcesJar\n}\n\n\n// javadoc configuration\n//javadoc { //TODO java\n//    options{\n//        encoding \"UTF-8\"\n//        charSet 'UTF-8'\n//        author true\n//        version projectVersionName\n//        links \"http://docs.oracle.com/javase/7/docs/api\"\n//        title javadocName\n//    }\n//}\n\n// bintrayJava configuration\nbintray {\n    user = bintrayUser\n    key = bintrayApikey\n    configurations = ['archives']\n    pkg {\n        repo = \"maven\"\n        name = projectName\n        websiteUrl = projectSiteUrl\n        vcsUrl = projectGitUrl\n        licenses = [\"Apache-2.0\"]\n        publish = true\n    }\n}\n"
  },
  {
    "path": "build.gradle",
    "content": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n    ext.kotlin_version = '1.1.51'\n    ext.dokka_version = '0.9.14'\n    repositories {\n        jcenter()\n        google()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:3.0.0'\n        classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version\"\n        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'\n        classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'\n\n        classpath \"org.jetbrains.dokka:dokka-android-gradle-plugin:${dokka_version}\"\n        // NOTE: Do not place your application dependencies here; they belong\n        // in the individual module build.gradle files\n    }\n}\nallprojects {\n    repositories {\n        jcenter()\n        google()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "refresh-java/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "refresh-java/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 27\n    buildToolsVersion \"27.0.1\"\n    defaultConfig {\n        minSdkVersion 15\n        versionCode 1\n        versionName '1.3'\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_7\n        targetCompatibility JavaVersion.VERSION_1_7\n    }\n}\n//apply from: '../bintrayUpload.gradle'\ndependencies {\n    compile fileTree(include: ['*.jar'], dir: 'libs')\n    provided 'com.android.support:appcompat-v7:27.0.0'\n    provided 'com.android.support:design:27.0.0'\n}\n"
  },
  {
    "path": "refresh-java/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 D:\\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\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "refresh-java/project.properties",
    "content": "#project\nproject.name=JRefreshLayout\nproject.groupId=gorden.refresh\nproject.artifactId=refresh-java\nproject.packaging=aar\nproject.siteUrl=https://github.com/XiaoQiWen/KRefreshLayout\nproject.gitUrl=https://github.com/XiaoQiWen/KRefreshLayout.git\n\n#javadoc\njavadoc.name=JRefreshLayout"
  },
  {
    "path": "refresh-java/src/main/AndroidManifest.xml",
    "content": "<manifest package=\"gorden.refresh\"/>\n"
  },
  {
    "path": "refresh-java/src/main/java/gorden/refresh/JRefreshHeader.java",
    "content": "package gorden.refresh;\n\n\npublic interface JRefreshHeader {\n    /**\n     * 刷新成功停滞时间\n     */\n    long succeedRetention();\n    /**\n     * 刷新失败停滞时间\n     */\n    long failingRetention();\n    /**\n     * 刷新高度，达到这个高度将触发刷新\n     */\n    int refreshHeight();\n    /**\n     * 最大下拉高度\n     */\n    int maxOffsetHeight();\n\n    /**\n     *  当内容视图到达顶部，视图将被重置\n     */\n    void onReset(JRefreshLayout refreshLayout);\n    /**\n     * 准备下拉，作初始化工作\n     */\n    void onPrepare(JRefreshLayout refreshLayout);\n    /**\n     * 刷新中\n     */\n    void onRefresh(JRefreshLayout refreshLayout);\n    /**\n     * 刷新完成\n     * @param isSuccess 成功还是失败\n     */\n    void onComplete(JRefreshLayout refreshLayout,boolean isSuccess);\n    /**\n     * 拖拽中\n     * @param distance 当前滑动距离\n     * @param percent 当前移动比例  0f - max  1.0为刷新临界点\n     * @param refreshing 是否处于刷新中\n     */\n    void onScroll(JRefreshLayout refreshLayout,int distance,float percent,boolean refreshing);\n}\n"
  },
  {
    "path": "refresh-java/src/main/java/gorden/refresh/JRefreshLayout.java",
    "content": "package gorden.refresh;\n\nimport android.animation.ValueAnimator;\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.support.v4.view.GestureDetectorCompat;\nimport android.support.v4.view.NestedScrollingChild;\nimport android.support.v4.view.ViewCompat;\nimport android.support.v4.widget.NestedScrollView;\nimport android.support.v7.widget.RecyclerView;\nimport android.util.AttributeSet;\nimport android.util.Log;\nimport android.view.GestureDetector;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.ViewConfiguration;\nimport android.view.ViewGroup;\nimport android.widget.AbsListView;\nimport android.widget.OverScroller;\nimport android.widget.ScrollView;\n\n/**\n * Universal pull down the refresh frame\n * version 1.1\n */\n\n@SuppressWarnings({\"unused\", \"FieldCanBeLocal\"})\npublic class JRefreshLayout extends ViewGroup {\n    private static final String LOG_TAG = \"LOG_JRefreshLayout\";\n\n    private static final int MAX_OFFSET = 30;//单次最大偏移量\n\n    private JRefreshHeader mHeader;\n    private View mHeaderView;\n    private View mContentView;\n\n    private OverScroller mScroller;\n    private ValueAnimator mOffsetAnimator;\n    private GestureDetectorCompat mGesture;\n\n    private int mCurrentOffset;\n    private int mLastFlingY;\n    private float mInitialDownY;\n\n    //状态参数↓\n    private boolean mRefreshing = false;//是否处于刷新中\n    private boolean mIsReset = true;//刷新完成后是否重置\n    private boolean mIsBeingDragged = true;\n    private boolean mIsFling = false;\n    private boolean mGestureExecute = false;\n    private boolean mNestedScrollExecute = false;\n    private boolean mNestedScrollInProgress = false;\n\n    //可配置参数,提供set方法\n    private int defaultRefreshHeight;\n    private int defaultMaxOffset;\n    private long mDurationOffset = 200;\n    private boolean mKeepHeaderWhenRefresh = true;\n    private boolean mIsPinContent = false;\n    private boolean mRefreshEnable = true;\n    private int mTouchSlop;\n    private int mFlingSlop = 1000;\n    private int mHeaderOffset = 0;\n\n    private JRefreshListener mRefreshListener;\n    private JScrollListener mScrollListener;\n\n    public JRefreshLayout(Context context) {\n        this(context, null);\n    }\n\n    public JRefreshLayout(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public JRefreshLayout(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        mScroller = new OverScroller(context);\n        mGesture = new GestureDetectorCompat(context, new RefreshGestureListener());\n        mGesture.setIsLongpressEnabled(false);\n        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 2;\n\n        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.JRefreshLayout);\n        mIsPinContent = a.getBoolean(R.styleable.JRefreshLayout_j_pin_content, false);\n        mKeepHeaderWhenRefresh = a.getBoolean(R.styleable.JRefreshLayout_j_keep_header, true);\n        mDurationOffset = a.getInt(R.styleable.JRefreshLayout_j_duration_offset, 200);\n        mRefreshEnable = a.getBoolean(R.styleable.JRefreshLayout_j_refresh_enable, true);\n        defaultRefreshHeight = a.getLayoutDimension(R.styleable.JRefreshLayout_j_def_refresh_height, Integer.MAX_VALUE);\n        defaultMaxOffset = a.getLayoutDimension(R.styleable.JRefreshLayout_j_def_max_offset, defaultMaxOffset);\n        a.recycle();\n    }\n\n    @Override\n    protected void onFinishInflate() {\n        int childCount = getChildCount();\n        if (childCount > 2)\n            throw new IllegalStateException(\"JRefreshLayout111 can only accommodate two elements\");\n        else if (childCount == 1) {\n            mContentView = getChildAt(0);\n        } else if (childCount == 2) {\n            if (getChildAt(0) instanceof JRefreshHeader) {\n                mHeader = (JRefreshHeader) getChildAt(0);\n                mHeaderView = (View) mHeader;\n            }\n            mContentView = getChildAt(1);\n        }\n\n        if (mHeaderView != null)\n            mHeaderView.bringToFront();\n        super.onFinishInflate();\n    }\n\n    @Override\n    protected LayoutParams generateDefaultLayoutParams() {\n        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);\n    }\n\n    @Override\n    public LayoutParams generateLayoutParams(AttributeSet attrs) {\n        return new LayoutParams(getContext(), attrs);\n    }\n\n    @Override\n    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {\n        return new LayoutParams(p);\n    }\n\n    @SuppressWarnings(\"WeakerAccess\")\n    public static class LayoutParams extends MarginLayoutParams {\n\n        public LayoutParams(Context c, AttributeSet attrs) {\n            super(c, attrs);\n        }\n\n        public LayoutParams(int width, int height) {\n            super(width, height);\n        }\n\n        public LayoutParams(MarginLayoutParams source) {\n            super(source);\n        }\n\n        public LayoutParams(ViewGroup.LayoutParams source) {\n            super(source);\n        }\n    }\n\n    @Override\n    protected void onLayout(boolean changed, int l, int t, int r, int b) {\n        if (mHeaderView != null && !isInEditMode()) {\n            LayoutParams lp = (LayoutParams) mHeaderView.getLayoutParams();\n            int childLeft = getPaddingLeft() + lp.leftMargin;\n            int childTop = getPaddingTop() + lp.topMargin - mHeaderView.getMeasuredHeight() + mCurrentOffset + mHeaderOffset;\n            int childRight = childLeft + mHeaderView.getMeasuredWidth();\n            int childBottom = childTop + mHeaderView.getMeasuredHeight();\n            mHeaderView.layout(childLeft, childTop, childRight, childBottom);\n        }\n\n        if (mContentView != null) {\n            LayoutParams lp = (LayoutParams) mContentView.getLayoutParams();\n            int childLeft = getPaddingLeft() + lp.leftMargin;\n            int childTop = getPaddingTop() + lp.topMargin + (mIsPinContent ? 0 : mCurrentOffset);\n            int childRight = childLeft + mContentView.getMeasuredWidth();\n            int childBottom = childTop + mContentView.getMeasuredHeight();\n            mContentView.layout(childLeft, childTop, childRight, childBottom);\n        }\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n\n        for (int i = 0; i < getChildCount(); i++) {\n            View child = getChildAt(i);\n            measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);\n        }\n\n    }\n\n    @Override\n    public boolean dispatchTouchEvent(MotionEvent ev) {\n        switch (ev.getAction()) {\n            case MotionEvent.ACTION_DOWN:\n                cancelAnimator();\n                mIsFling = false;\n                mLastFlingY = 0;\n                break;\n            case MotionEvent.ACTION_UP:\n            case MotionEvent.ACTION_CANCEL:\n                //如果NestedScroll未真正执行，则结束移动\n                if (!mNestedScrollExecute && !mGestureExecute) {\n                    finishSpinner();\n                }\n                break;\n        }\n        return super.dispatchTouchEvent(ev);\n    }\n\n    @Override\n    public boolean onInterceptTouchEvent(MotionEvent event) {\n        if (!isEnabled() || !mRefreshEnable)\n            return false;\n\n        if (mNestedScrollInProgress || canChildScrollUp())\n            return false;\n\n        if (mRefreshing && mIsPinContent && mKeepHeaderWhenRefresh)\n            return false;\n\n        int action = event.getAction();\n        switch (action) {\n            case MotionEvent.ACTION_DOWN:\n                mIsBeingDragged = false;\n                mInitialDownY = event.getY();\n                mGesture.onTouchEvent(event);\n                break;\n            case MotionEvent.ACTION_MOVE:\n                if (!mIsBeingDragged && event.getY() - mInitialDownY > mTouchSlop) {\n                    mIsBeingDragged = true;\n                }\n                if (mCurrentOffset > 0 && !mIsBeingDragged) {\n                    mIsBeingDragged = true;\n                }\n                break;\n            case MotionEvent.ACTION_UP:\n            case MotionEvent.ACTION_CANCEL:\n                mIsBeingDragged = false;\n                break;\n        }\n        return mIsBeingDragged;\n    }\n\n    @SuppressWarnings(\"StatementWithEmptyBody\")\n    @Override\n    public void requestDisallowInterceptTouchEvent(boolean b) {\n        if ((android.os.Build.VERSION.SDK_INT < 21 && mContentView instanceof AbsListView)\n                || (mContentView != null && !ViewCompat.isNestedScrollingEnabled(mContentView))) {\n\n        } else {\n            super.requestDisallowInterceptTouchEvent(b);\n        }\n    }\n\n    @Override\n    public boolean onTouchEvent(MotionEvent event) {\n        if (!isEnabled() || mNestedScrollExecute || canChildScrollUp())\n            return false;\n        mGesture.onTouchEvent(event);\n        if (event.getAction() == MotionEvent.ACTION_UP) {\n            if (!mIsFling && mGestureExecute) {\n                finishSpinner();\n            }\n            mGestureExecute = false;\n        }\n        return true;\n    }\n\n    private class RefreshGestureListener extends GestureDetector.SimpleOnGestureListener {\n        @Override\n        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {\n            mGestureExecute = true;\n            int maxOffset = mHeader == null ? defaultMaxOffset == -1 ? getHeight() : defaultMaxOffset : mHeader.maxOffsetHeight();\n            if ((mCurrentOffset == 0 && distanceY > 0) || mCurrentOffset == maxOffset && distanceY < 0)\n                return super.onScroll(e1, e2, distanceX, distanceY);\n\n            int offset = -calculateOffset((int) distanceY);\n            if (mCurrentOffset + offset > maxOffset) {\n                offset = maxOffset - mCurrentOffset;\n            } else if (mCurrentOffset + offset < 0) {\n                offset = -mCurrentOffset;\n            }\n            moveView(offset);\n            return super.onScroll(e1, e2, distanceX, distanceY);\n        }\n\n        @Override\n        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {\n            mGestureExecute = true;\n            int refreshHeight = mHeader == null ? defaultRefreshHeight : mHeader.refreshHeight();\n            if (velocityY > 0 && (!mRefreshing || !mKeepHeaderWhenRefresh || mCurrentOffset >= refreshHeight)) {\n                return super.onFling(e1, e2, velocityX, velocityY);\n            }\n            if (Math.abs(velocityY) > mFlingSlop) {\n                mIsFling = true;\n                mScroller.fling(0, 0, (int) velocityX, (int) -velocityY, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE);\n                invalidate();\n            }\n            return super.onFling(e1, e2, velocityX, velocityY);\n        }\n    }\n\n    private boolean canChildScrollUp() {\n        return mContentView != null && ViewCompat.canScrollVertically(mContentView, -1);\n    }\n\n    @Override\n    public boolean onStartNestedScroll(View child, View target, int nestedScrollAxes) {\n        return isEnabled() && mRefreshEnable && !(mRefreshing && mIsPinContent && mKeepHeaderWhenRefresh)\n                && (nestedScrollAxes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;\n    }\n\n    @Override\n    public void onNestedScrollAccepted(View child, View target, int axes) {\n        mNestedScrollExecute = false;\n        mNestedScrollInProgress = true;\n    }\n\n    @Override\n    public void onNestedPreScroll(View target, int dx, int dy, int[] consumed) {\n        mNestedScrollExecute = true;\n        if (mCurrentOffset > 0 && dy > 0) {\n            int offset = dy > mCurrentOffset ? mCurrentOffset : dy;\n            consumed[1] = dy > mCurrentOffset ? dy - mCurrentOffset : dy;\n            moveView(-offset);\n        }\n    }\n\n    @Override\n    public void onNestedScroll(View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {\n        int maxOffset = mHeader == null ? defaultMaxOffset == -1 ? getHeight() : defaultMaxOffset : mHeader.maxOffsetHeight();\n        if (dyUnconsumed < 0 && !canChildScrollUp() && mCurrentOffset < maxOffset) {\n            if (mCurrentOffset - dyUnconsumed > maxOffset) {\n                dyUnconsumed = mCurrentOffset - maxOffset;\n            }\n            int offset = -calculateOffset(dyUnconsumed);\n            moveView(offset);\n        }\n    }\n\n    @Override\n    public boolean onNestedPreFling(View target, float velocityX, float velocityY) {\n        mNestedScrollExecute = true;\n        //如果当前偏移量大于0，则交给KrefreshLayout处理Fling事件\n        if (mCurrentOffset > 0) {\n            int refreshHeight = mHeader == null ? defaultRefreshHeight : mHeader.refreshHeight();\n            if (velocityY < 0 && (!mRefreshing || !mKeepHeaderWhenRefresh || mCurrentOffset >= refreshHeight)) {\n                return true;\n            }\n            if (Math.abs(velocityY) > mFlingSlop) {\n                mIsFling = true;\n                mScroller.fling(0, 0, (int) velocityX, (int) velocityY, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE);\n                invalidate();\n            }\n            return true;\n        } else\n            return false;\n    }\n\n    @Override\n    public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {\n        //如果向上滚动，且处于刷新过程中，监听Fling过程\n        if (mRefreshing && velocityY < -mTouchSlop && mKeepHeaderWhenRefresh) {\n            mIsFling = true;\n            mScroller.fling(0, 0, (int) velocityX, (int) velocityY, Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE);\n            invalidate();\n        }\n        return true;\n    }\n\n    @Override\n    public void onStopNestedScroll(View child) {\n        if (!mIsFling && mNestedScrollExecute) {\n            finishSpinner();\n        }\n        mNestedScrollExecute = false;\n        mNestedScrollInProgress = false;\n    }\n\n    @Override\n    public void computeScroll() {\n        if (mScroller.computeScrollOffset() && mIsFling) {\n            //本次Fling移动距离(<0向下滚动、>0向上滚动)\n            int offset = mLastFlingY - mScroller.getCurrY();\n            int refreshHeight = mHeader == null ? defaultRefreshHeight : mHeader.refreshHeight();\n            int maxOffset = mHeader == null ? defaultMaxOffset == -1 ? getHeight() : defaultMaxOffset : mHeader.maxOffsetHeight();\n            int mFlingMaxHeight = offset > 0 ? refreshHeight : maxOffset;\n            //记录上次Fling的Y值\n            mLastFlingY = mScroller.getCurrY();\n\n            if (mCurrentOffset > 0 || (offset > 0 && !canChildScrollUp())) {\n                offset = mCurrentOffset + offset > mFlingMaxHeight ? mFlingMaxHeight - mCurrentOffset : mCurrentOffset + offset < 0 ? -mCurrentOffset : offset;\n                moveView(offset);\n                if (mCurrentOffset >= mFlingMaxHeight) {\n                    mScroller.forceFinished(true);\n                }\n            } else if (offset < 0) {\n                if (mContentView instanceof RecyclerView) {\n                    ((RecyclerView) mContentView).fling(0, (int) mScroller.getCurrVelocity());\n                } else if (mContentView instanceof NestedScrollView) {\n                    ((NestedScrollView) mContentView).fling((int) mScroller.getCurrVelocity());\n                } else if (mContentView instanceof ScrollView) {\n                    ((ScrollView) mContentView).fling((int) mScroller.getCurrVelocity());\n                }\n                mScroller.forceFinished(true);\n            }\n            invalidate();\n        } else if (mIsFling) {\n            Log.d(LOG_TAG, \"mScroll fling complete mCurrentOffset is \" + mCurrentOffset);\n            mIsFling = false;\n            finishSpinner();\n        }\n    }\n\n    /**\n     * 计算实际偏移量\n     */\n    private int calculateOffset(int offset) {\n        //下拉阻力(0f-1f) 越小阻力越大，当前计算公式:1-mDistanceY/maxheight\n        int maxOffset = mHeader == null ? defaultMaxOffset == -1 ? getHeight() : defaultMaxOffset : mHeader.maxOffsetHeight();\n        float downResistance = offset > 0 ? 0.8f : 1f - (float) mCurrentOffset / maxOffset;\n        if (offset > 0) {\n            offset = Math.min(MAX_OFFSET, (int) Math.ceil(downResistance * offset));\n        } else {\n            offset = Math.max(-MAX_OFFSET, (int) Math.floor(downResistance * offset));\n        }\n        return offset;\n    }\n\n    /**\n     * 移动视图\n     *\n     * @param offset 偏移量\n     *               //     * @param requiresUpdate 是否需要更新\n     */\n    private void moveView(int offset) {\n        boolean invalidate = false;\n        int refreshHeight = mHeader == null ? defaultRefreshHeight : mHeader.refreshHeight();\n        if (!mRefreshing && mCurrentOffset == 0 && offset > 0) {\n            if (mHeader != null) mHeader.onPrepare(this);\n        }\n\n        if (mCurrentOffset > getHeight() || mCurrentOffset == 0) {\n            invalidate = true;\n        }\n\n        mCurrentOffset += offset;\n        if (mHeaderView != null) mHeaderView.offsetTopAndBottom(offset);\n        if (!mIsPinContent)\n            mContentView.offsetTopAndBottom(offset);\n        if (invalidate) invalidate();\n        if (mHeader != null)\n            mHeader.onScroll(this, mCurrentOffset, (float) mCurrentOffset / refreshHeight, mRefreshing);\n        if (mScrollListener != null)\n            mScrollListener.onScroll(offset, mCurrentOffset, (float) mCurrentOffset / refreshHeight, mRefreshing);\n        if (!mRefreshing && offset < 0 && mCurrentOffset == 0) {\n            if (mHeader != null) mHeader.onReset(this);\n            mIsReset = true;\n        }\n    }\n\n    /**\n     * 取消offset动画\n     */\n    private void cancelAnimator() {\n        if (mOffsetAnimator != null && mOffsetAnimator.isRunning()) {\n            mOffsetAnimator.cancel();\n        }\n    }\n\n    /**\n     * offset动画更新监听\n     */\n    private ValueAnimator.AnimatorUpdateListener mAnimatorUpdateListener = new ValueAnimator.AnimatorUpdateListener() {\n        @Override\n        public void onAnimationUpdate(ValueAnimator animation) {\n            int value = (int) animation.getAnimatedValue();\n            moveView(value - mCurrentOffset);\n        }\n    };\n\n    /**\n     * 结束下拉\n     */\n    private void finishSpinner() {\n        if (mCurrentOffset <= 0) return;\n        Log.d(LOG_TAG, \"finishSpinner mCurrentOffset is \" + mCurrentOffset + \" , mRefreshing is \" + mRefreshing);\n        final int target;\n        int refreshHeight = mHeader == null ? defaultRefreshHeight : mHeader.refreshHeight();\n        if (mRefreshing) {\n            target = mCurrentOffset >= refreshHeight / 2 ? refreshHeight : 0;\n        } else {\n            target = mCurrentOffset >= refreshHeight && mIsReset ? refreshHeight : 0;\n            if (mCurrentOffset >= refreshHeight && mIsReset) {\n                mRefreshing = true;//开始刷新\n                mIsReset = false;\n                if (mHeader != null) mHeader.onRefresh(this);\n                if (mRefreshListener != null)\n                    mRefreshListener.onRefresh(this);\n            }\n        }\n        animTo(target);\n    }\n\n    /**\n     * 动画方式移动\n     *\n     * @param target 目标位置\n     */\n    private void animTo(int target) {\n        if (mOffsetAnimator == null) {\n            mOffsetAnimator = new ValueAnimator();\n            mOffsetAnimator.addUpdateListener(mAnimatorUpdateListener);\n        }\n\n        cancelAnimator();\n\n        if (!mKeepHeaderWhenRefresh) target = 0;\n\n        if (mCurrentOffset == target) {\n            return;\n        }\n        Log.d(LOG_TAG, \"animTo \" + mCurrentOffset + \" to \" + target);\n        mOffsetAnimator.setDuration(mDurationOffset);\n        mOffsetAnimator.setIntValues(mCurrentOffset, target);\n        mOffsetAnimator.start();\n    }\n\n\n    @SuppressWarnings(\"WeakerAccess\")\n    public interface JRefreshListener {\n        void onRefresh(JRefreshLayout refreshLayout);\n    }\n\n    @SuppressWarnings(\"WeakerAccess\")\n    public interface JScrollListener {\n        /**\n         * @param offset     本次的偏移量\n         * @param distance   总的偏移量\n         * @param percent    偏移比率\n         * @param refreshing 是否在刷新\n         */\n        void onScroll(int offset, int distance, float percent, boolean refreshing);\n    }\n\n\n    //开放Api\n\n    public void setJRefreshListener(JRefreshListener refreshListener) {\n        mRefreshListener = refreshListener;\n    }\n\n    public void setJScrollListener(JScrollListener scrollListener) {\n        mScrollListener = scrollListener;\n    }\n\n    public void setPinContent(boolean pinContent) {\n        mIsPinContent = pinContent;\n    }\n\n    public void setKeepHeaderWhenRefresh(boolean keep) {\n        mKeepHeaderWhenRefresh = keep;\n    }\n\n    public void setRefreshEnable(boolean enable) {\n        mRefreshEnable = enable;\n    }\n\n    public void setDurationOffset(long duration) {\n        mDurationOffset = duration;\n    }\n\n    public void setHeaderView(JRefreshHeader headerView) {\n        setHeaderView(headerView, LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);\n    }\n\n    public void setHeaderView(JRefreshHeader headerView, int width, int height) {\n        LayoutParams params = generateDefaultLayoutParams();\n        params.width = width;\n        params.height = height;\n        setHeaderView(headerView, params);\n    }\n\n    public void setHeaderView(JRefreshHeader headerView, LayoutParams params) {\n        removeHeader();\n        mHeader = headerView;\n        mHeaderView = (View) mHeader;\n        addView(mHeaderView, 0, params);\n        mHeaderView.bringToFront();\n    }\n\n    public JRefreshHeader getHeader() {\n        return mHeader;\n    }\n\n    public void removeHeader() {\n        if (mHeaderView != null) {\n            removeView(mHeaderView);\n        }\n    }\n\n    public void setTouchSlop(int mTouchSlop) {\n        this.mTouchSlop = mTouchSlop;\n    }\n\n    public void setFlingSlop(int mFlingSlop) {\n        this.mFlingSlop = mFlingSlop;\n    }\n\n    public void setHeaderOffset(int mHeaderOffset) {\n        this.mHeaderOffset = mHeaderOffset;\n    }\n\n    public void setDefaultRefreshHeight(int defaultRefreshHeight) {\n        this.defaultRefreshHeight = defaultRefreshHeight;\n    }\n\n    public void setDefaultMaxOffset(int defaultMaxOffset) {\n        this.defaultMaxOffset = defaultMaxOffset;\n    }\n\n    /**\n     * 自动刷新\n     */\n    public void startRefresh() {\n        if (!mRefreshing && mRefreshEnable) {\n            postDelayed(new Runnable() {\n                @Override\n                public void run() {\n                    mRefreshing = true;\n                    mIsReset = false;\n                    if (mHeader != null) mHeader.onRefresh(JRefreshLayout.this);\n                    if (mRefreshListener != null) mRefreshListener.onRefresh(JRefreshLayout.this);\n                    mContentView.scrollTo(0, 0);\n                    animTo(mHeader == null ? defaultRefreshHeight : mHeader.refreshHeight());\n                }\n            }, 100);\n        }\n    }\n\n    /**\n     * 刷新完成\n     */\n    public void refreshComplete(boolean isSuccess) {\n        if (mRefreshing) {\n            if (mHeader != null) mHeader.onComplete(this, isSuccess);\n            mRefreshing = false;\n            if (mCurrentOffset == 0) {\n                mIsReset = true;\n                cancelAnimator();\n                if (mHeader != null) mHeader.onReset(this);\n            } else {\n                //刷新完成停滞时间\n                long retention = mHeader == null ? 0 : isSuccess ? mHeader.succeedRetention() : mHeader.failingRetention();\n                postDelayed(new Runnable() {\n                    @Override\n                    public void run() {\n                        animTo(0);\n                    }\n                }, retention);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "refresh-java/src/main/res/values/jattr.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <declare-styleable name=\"JRefreshLayout\">\n        <attr name=\"j_pin_content\" format=\"boolean\"/>\n        <attr name=\"j_keep_header\" format=\"boolean\"/>\n        <attr name=\"j_duration_offset\" format=\"integer\"/>\n        <attr name=\"j_refresh_enable\" format=\"boolean\" />\n        <attr name=\"j_def_refresh_height\" format=\"dimension\"/>\n        <attr name=\"j_def_max_offset\" format=\"dimension|enum\">\n            <enum name=\"match_parent\" value=\"-1\" />\n        </attr>\n    </declare-styleable>\n</resources>"
  },
  {
    "path": "refresh-kotlin/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "refresh-kotlin/build.gradle",
    "content": "apply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\napply plugin: 'kotlin-android-extensions'\n\nandroid {\n    compileSdkVersion 27\n    buildToolsVersion \"27.0.1\"\n\n    defaultConfig {\n        minSdkVersion 15\n        versionCode 1\n        versionName \"1.3\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n    sourceSets {\n        main.java.srcDirs += 'src/main/kotlin'\n    }\n}\n//apply from: '../bintrayUpload.gradle'\ndependencies {\n    provided 'com.android.support:appcompat-v7:27.0.0'\n    provided 'com.android.support:design:27.0.0'\n    provided \"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version\"\n}"
  },
  {
    "path": "refresh-kotlin/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 D:\\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\n# Uncomment this to preserve the line number information for\n# debugging stack traces.\n#-keepattributes SourceFile,LineNumberTable\n\n# If you keep the line number information, uncomment this to\n# hide the original source file name.\n#-renamesourcefileattribute SourceFile\n"
  },
  {
    "path": "refresh-kotlin/project.properties",
    "content": "#project\nproject.name=KRefreshLayout\nproject.groupId=gorden.refresh\nproject.artifactId=refresh-kotlin\nproject.packaging=aar\nproject.siteUrl=https://github.com/XiaoQiWen/KRefreshLayout\nproject.gitUrl=https://github.com/XiaoQiWen/KRefreshLayout.git\n\n#javadoc\njavadoc.name=KRefreshLayout\n\n"
  },
  {
    "path": "refresh-kotlin/src/main/AndroidManifest.xml",
    "content": "<manifest package=\"gorden.refresh\"/>\n"
  },
  {
    "path": "refresh-kotlin/src/main/kotlin/gorden/refresh/KRefreshHeader.kt",
    "content": "package gorden.refresh\n\ninterface KRefreshHeader {\n    /**\n     * 刷新成功停滞时间\n     */\n    fun succeedRetention(): Long\n    /**\n     * 刷新失败停滞时间\n     */\n    fun failingRetention(): Long\n\n    /**\n     * 刷新高度，达到这个高度将触发刷新\n     */\n    fun refreshHeight(): Int\n\n    /**\n     * Content最大下拉高度,无特殊要求\n     */\n    fun maxOffsetHeight(): Int\n\n    /**\n     *  当内容视图到达顶部，视图将被重置\n     */\n    fun onReset(refreshLayout: KRefreshLayout)\n\n    /**\n     * 准备下拉，作初始化工作\n     */\n    fun onPrepare(refreshLayout: KRefreshLayout)\n\n    /**\n     * 刷新中\n     */\n    fun onRefresh(refreshLayout: KRefreshLayout)\n\n    /**\n     * 刷新完成\n     * @param isSuccess 成功还是失败\n     */\n    fun onComplete(refreshLayout: KRefreshLayout,isSuccess:Boolean)\n\n    /**\n     * 拖拽中\n     * @param distance 当前滑动距离\n     * @param percent 当前移动比例  0f - max  1.0为刷新临界点\n     * @param refreshing 是否处于刷新中\n     */\n    fun onScroll(refreshLayout: KRefreshLayout, distance: Int, percent: Float, refreshing: Boolean)\n\n}"
  },
  {
    "path": "refresh-kotlin/src/main/kotlin/gorden/refresh/KRefreshLayout.kt",
    "content": "package gorden.refresh\n\nimport android.animation.ValueAnimator\nimport android.annotation.SuppressLint\nimport android.content.Context\nimport android.support.v4.view.GestureDetectorCompat\nimport android.support.v4.view.NestedScrollingParent\nimport android.support.v4.view.ViewCompat\nimport android.support.v4.widget.NestedScrollView\nimport android.support.v7.widget.RecyclerView\nimport android.util.AttributeSet\nimport android.util.Log\nimport android.view.*\nimport android.view.ViewGroup.LayoutParams.MATCH_PARENT\nimport android.view.ViewGroup.LayoutParams.WRAP_CONTENT\nimport android.widget.AbsListView\nimport android.widget.OverScroller\nimport android.widget.ScrollView\n\n@Suppress(\"unused\", \"PrivatePropertyName\", \"MemberVisibilityCanPrivate\")\n/**\n * Universal pull down the refresh frame\n * version 1.31\n */\nclass KRefreshLayout(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : ViewGroup(context, attrs, defStyleAttr), NestedScrollingParent {\n    private val LOG_TAG = \"LOG_KRefreshLayout\"\n\n    private val MAX_OFFSET = 30                             //单次最大偏移量\n\n    private var mHeader: KRefreshHeader? = null\n    private var mContentView: View? = null\n    private var mHeaderView: View? = null\n\n    private val mScroller by lazy { OverScroller(context) }\n    private val mOffsetAnimator by lazy {\n        ValueAnimator().apply {\n            addUpdateListener {\n                val value = animatedValue as Int\n                moveView(value - mCurrentOffset)\n            }\n        }\n    }\n    private val mGesture: GestureDetectorCompat by lazy {\n        GestureDetectorCompat(context, RefreshGestureListener()).apply { setIsLongpressEnabled(false) }\n    }\n\n    private var mLastFlingY: Int = 0\n    private var mCurrentOffset: Int = 0\n    private var mInitialDownY: Float = 0f\n\n    /*状态参数↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓*/\n    private var mIsReset = true                             //刷新完成后是否重置\n    private var mIsFling = false                            //是否处于Fling状态\n    private var mRefreshing = false                         //是否正在刷新中\n    private var mIsBeingDragged = false                     //是否开始拖动\n    private var mGestureExecute = false                    //Gesture事件是否响应\n    private var mNestedScrollExecute = false                //NestedScroll事件是否响应\n    private var mNestedScrollInProgress = false             //NestedScroll是否可以执行，遇到部分手机不会走NestedScroll流程\n    /*状态参数↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑*/\n\n    /*可配置参数↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓*/\n    var defaultRefreshHeight: Int = 0                        //默认刷新个高度,header为空时使用\n    var defaultMaxOffset: Int = 0                            //默认最大下拉高度，header为空时使用\n    var durationOffset: Long = 200                           //位移动画持续时间\n    var keepHeaderWhenRefresh: Boolean = true               //刷新时Header自动移动到刷新高度,false回到初始位置\n    var pinContent: Boolean = false                         //下拉刷新过程是否让ContentView不发生位置移动\n    var refreshEnable: Boolean = true                       //是否允许下拉刷新\n    var touchSlop: Int = 0                                 //触发移动事件的最短距离\n    var flingSlop: Int = 1000                              //触发Fling事件的最低速度\n    var headerOffset: Int = 0                               //Header 自身消耗Offset,可处理一些特殊效果\n    /*可配置参数↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑*/\n\n    private var mRefreshListener: ((KRefreshLayout) -> Unit)? = null\n    private var mScrollListener: ((offset: Int, distance: Int, percent: Float, refreshing: Boolean) -> Unit)? = null\n\n    constructor(context: Context) : this(context, null)\n    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)\n\n    init {\n        touchSlop = ViewConfiguration.get(context).scaledTouchSlop * 2\n\n        val a = context.obtainStyledAttributes(attrs, R.styleable.KRefreshLayout)\n        pinContent = a.getBoolean(R.styleable.KRefreshLayout_k_pin_content, false)\n        keepHeaderWhenRefresh = a.getBoolean(R.styleable.KRefreshLayout_k_keep_header, true)\n        refreshEnable = a.getBoolean(R.styleable.KRefreshLayout_k_refresh_enable, true)\n        durationOffset = a.getInt(R.styleable.KRefreshLayout_k_duration_offset, 200).toLong()\n        defaultRefreshHeight = a.getLayoutDimension(R.styleable.KRefreshLayout_k_def_refresh_height, Int.MAX_VALUE)\n        defaultMaxOffset = a.getLayoutDimension(R.styleable.KRefreshLayout_k_def_max_offset, defaultMaxOffset)\n        a.recycle()\n    }\n\n    override fun onFinishInflate() {\n        super.onFinishInflate()\n        when {\n            childCount > 2 -> throw IllegalStateException(\"KRefreshLayout111 can only accommodate two elements\")\n            childCount == 1 -> mContentView = getChildAt(0)\n            childCount == 2 -> {\n                mContentView = getChildAt(1)\n                mHeader = getChildAt(0) as? KRefreshHeader ?: return\n                mHeaderView = getChildAt(0)\n            }\n        }\n        mHeaderView?.bringToFront()\n    }\n\n    override fun generateDefaultLayoutParams(): LayoutParams = LayoutParams(MATCH_PARENT, MATCH_PARENT)\n\n    override fun generateLayoutParams(attrs: AttributeSet): LayoutParams = LayoutParams(context, attrs)\n\n    override fun generateLayoutParams(p: ViewGroup.LayoutParams): LayoutParams = LayoutParams(p)\n\n    @Suppress(\"unused\")\n    class LayoutParams : ViewGroup.MarginLayoutParams {\n        constructor(c: Context, attrs: AttributeSet) : super(c, attrs)\n\n        constructor(width: Int, height: Int) : super(width, height)\n\n        constructor(source: ViewGroup.MarginLayoutParams) : super(source)\n\n        constructor(source: ViewGroup.LayoutParams) : super(source)\n    }\n\n    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {\n\n        mHeaderView?.let {\n            val lp = it.layoutParams as LayoutParams\n            val childLeft = paddingLeft + lp.leftMargin\n            val childTop = paddingTop + lp.topMargin - it.measuredHeight + mCurrentOffset + headerOffset\n            val childRight = childLeft + it.measuredWidth\n            val childBottom = childTop + it.measuredHeight\n            it.layout(childLeft, childTop, childRight, childBottom)\n        }\n\n        mContentView?.let {\n            val lp = it.layoutParams as LayoutParams\n            val childLeft = paddingLeft + lp.leftMargin\n            val childTop = paddingTop + lp.topMargin + if (pinContent) 0 else mCurrentOffset\n            val childRight = childLeft + it.measuredWidth\n            val childBottom = childTop + it.measuredHeight\n            it.layout(childLeft, childTop, childRight, childBottom)\n        }\n    }\n\n    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec)\n        (0 until childCount).map { getChildAt(it) }\n                .forEach { measureChildWithMargins(it, widthMeasureSpec, 0, heightMeasureSpec, 0) }\n    }\n\n    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {\n        when (ev.action) {\n            MotionEvent.ACTION_DOWN -> {\n                cancelAnimator()\n                mIsFling = false\n                mLastFlingY = 0\n            }\n            MotionEvent.ACTION_UP,\n            MotionEvent.ACTION_CANCEL -> {\n                if (!mNestedScrollExecute && !mGestureExecute) {\n                    finishSpinner()\n                }\n            }\n\n        }\n        return super.dispatchTouchEvent(ev)\n    }\n\n    override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {\n        if (!isEnabled || !refreshEnable)\n            return false\n\n        if (mNestedScrollInProgress || canChildScrollUp()) {\n            return false\n        }\n        if (mRefreshing && pinContent && keepHeaderWhenRefresh)\n            return false\n\n        when (ev.action) {\n            MotionEvent.ACTION_DOWN -> {\n                mIsBeingDragged = false\n                mInitialDownY = ev.y\n                mGesture.onTouchEvent(ev)\n            }\n            MotionEvent.ACTION_MOVE -> {\n                if (!mIsBeingDragged && ev.y - mInitialDownY > touchSlop) {\n                    mIsBeingDragged = true\n                }\n\n                if (mCurrentOffset > 0 && !mIsBeingDragged) {\n                    mIsBeingDragged = true\n                }\n            }\n            MotionEvent.ACTION_UP,\n            MotionEvent.ACTION_CANCEL -> mIsBeingDragged = false\n        }\n\n        return mIsBeingDragged\n    }\n\n\n    override fun requestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {\n        if ((android.os.Build.VERSION.SDK_INT < 21 && mContentView is AbsListView) || (mContentView!=null&&!ViewCompat.isNestedScrollingEnabled(mContentView!!))) {\n\n        } else {\n            super.requestDisallowInterceptTouchEvent(disallowIntercept)\n        }\n    }\n\n\n    @SuppressLint(\"ClickableViewAccessibility\")\n    override fun onTouchEvent(event: MotionEvent): Boolean {\n        if (!isEnabled || mNestedScrollExecute || canChildScrollUp())\n            return false\n        mGesture.onTouchEvent(event)\n        if (event.action == MotionEvent.ACTION_UP) {\n            if (!mIsFling && mGestureExecute) {\n                finishSpinner()\n            }\n            mGestureExecute = false\n        }\n        return true\n    }\n\n    /**\n     * 手势处理\n     */\n    private inner class RefreshGestureListener : GestureDetector.SimpleOnGestureListener() {\n        override fun onScroll(e1: MotionEvent, e2: MotionEvent, distanceX: Float, distanceY: Float): Boolean {\n            mGestureExecute = true\n            val maxOffset = mHeader?.maxOffsetHeight() ?: if (defaultMaxOffset == -1) height else defaultMaxOffset\n            if ((mCurrentOffset == 0 && distanceY > 0) || (mCurrentOffset == maxOffset && distanceY < 0))\n                return super.onScroll(e1, e2, distanceX, distanceY)\n            var offset = -calculateOffset(distanceY.toInt())\n            if (mCurrentOffset + offset > maxOffset) {\n                offset = maxOffset - mCurrentOffset\n            } else if (mCurrentOffset + offset < 0) {\n                offset = -mCurrentOffset\n            }\n            moveView(offset)\n            return super.onScroll(e1, e2, distanceX, distanceY)\n        }\n\n        override fun onFling(e1: MotionEvent?, e2: MotionEvent?, velocityX: Float, velocityY: Float): Boolean {\n            mGestureExecute = true\n            val refreshHeight = mHeader?.refreshHeight() ?: defaultRefreshHeight\n            if (velocityY > 0 && (!mRefreshing || !keepHeaderWhenRefresh || mCurrentOffset >= refreshHeight)) {\n                return super.onFling(e1, e2, velocityX, velocityY)\n            }\n            if (Math.abs(velocityY) > flingSlop) {\n                mIsFling = true\n                mScroller.fling(0, 0, velocityX.toInt(), -velocityY.toInt(), Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE)\n                invalidate()\n            }\n            return super.onFling(e1, e2, velocityX, velocityY)\n        }\n    }\n\n    private fun canChildScrollUp(): Boolean = mContentView?.canScrollVertically( -1)?:false\n\n    override fun onStartNestedScroll(child: View, target: View, nestedScrollAxes: Int): Boolean {\n        return isEnabled && refreshEnable && !(mRefreshing && pinContent && keepHeaderWhenRefresh)\n                && nestedScrollAxes and ViewCompat.SCROLL_AXIS_VERTICAL != 0\n    }\n\n    override fun onNestedScrollAccepted(child: View, target: View, axes: Int) {\n        mNestedScrollExecute = false\n        mNestedScrollInProgress = true\n    }\n\n    override fun onNestedPreScroll(target: View, dx: Int, dy: Int, consumed: IntArray) {\n        mNestedScrollExecute = true\n        if (mCurrentOffset > 0 && dy > 0) {\n            val offset = if (dy > mCurrentOffset) mCurrentOffset else dy\n            consumed[1] = if (dy > mCurrentOffset) dy - mCurrentOffset else dy\n            moveView(-offset)\n        }\n    }\n\n    override fun onNestedScroll(target: View, dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int, dyUnconsumed: Int) {\n        var mUnconsumed: Int = dyUnconsumed\n        val maxOffset = mHeader?.maxOffsetHeight() ?: if (defaultMaxOffset == -1) height else defaultMaxOffset\n        if (dyUnconsumed < 0 && !canChildScrollUp() && mCurrentOffset < maxOffset) {\n            if (mCurrentOffset - dyUnconsumed > maxOffset) {\n                mUnconsumed = mCurrentOffset - maxOffset\n            }\n            val offset = -calculateOffset(mUnconsumed)\n            moveView(offset)\n        }\n    }\n\n    override fun onNestedPreFling(target: View, velocityX: Float, velocityY: Float): Boolean {\n        mNestedScrollExecute = true\n\n        //如果当前偏移量大于0，则交给KrefreshLayout处理Fling事件\n        if (mCurrentOffset > 0) {\n            val refreshHeight = mHeader?.refreshHeight() ?: defaultRefreshHeight\n            if (velocityY < 0 && (!mRefreshing || !keepHeaderWhenRefresh || mCurrentOffset >= refreshHeight)) {\n                return true\n            }\n            if (Math.abs(velocityY) > flingSlop) {\n                mIsFling = true\n                mScroller.fling(0, 0, velocityX.toInt(), velocityY.toInt(), Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE)\n                invalidate()\n            }\n            return true\n        } else\n            return false\n    }\n\n    override fun onNestedFling(target: View, velocityX: Float, velocityY: Float, consumed: Boolean): Boolean {\n        //如果向上滚动，且处于刷新过程中，监听Fling过程\n        if (mRefreshing && velocityY < -flingSlop && keepHeaderWhenRefresh) {\n            mIsFling = true\n            mScroller.fling(0, 0, velocityX.toInt(), velocityY.toInt(), Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE)\n            invalidate()\n        }\n        return true\n    }\n\n    override fun onStopNestedScroll(child: View) {\n        if (!mIsFling && mNestedScrollExecute) {\n            finishSpinner()\n        }\n        mNestedScrollExecute = false\n        mNestedScrollInProgress = false\n    }\n\n    override fun computeScroll() {\n        if (mScroller.computeScrollOffset() && mIsFling) {\n            //本次Fling移动距离(<0向下滚动、>0向上滚动)\n            var offset = mLastFlingY - mScroller.currY\n            val refreshHeight = mHeader?.refreshHeight() ?: defaultRefreshHeight\n            val maxOffset = mHeader?.maxOffsetHeight() ?: if (defaultMaxOffset == -1) height else defaultMaxOffset\n            val mFlingMaxHeight = if (offset > 0) refreshHeight else maxOffset\n            //记录上次Fling的Y值\n            mLastFlingY = mScroller.currY\n\n            if (mCurrentOffset > 0 || offset > 0 && !canChildScrollUp()) {\n                offset = if (mCurrentOffset + offset > mFlingMaxHeight) mFlingMaxHeight - mCurrentOffset else if (mCurrentOffset + offset < 0) -mCurrentOffset else offset\n                moveView(offset)\n                if (mCurrentOffset >= mFlingMaxHeight) {\n                    mScroller.forceFinished(true)\n                }\n            } else if (offset < 0) {\n                (mContentView as? RecyclerView)?.fling(0, mScroller.currVelocity.toInt())\n                (mContentView as? NestedScrollView)?.fling(mScroller.currVelocity.toInt())\n                (mContentView as? ScrollView)?.fling(mScroller.currVelocity.toInt())\n                mScroller.forceFinished(true)\n            }\n            invalidate()\n        } else if (mIsFling) {\n            Log.d(LOG_TAG, \"mScroll fling complete mCurrentOffset is \" + mCurrentOffset)\n            mIsFling = false\n            finishSpinner()\n        }\n    }\n\n\n    /**\n     * 计算实际偏移量\n     */\n    private fun calculateOffset(offset: Int): Int {\n        val maxOffset = mHeader?.maxOffsetHeight() ?: if (defaultMaxOffset == -1) height else defaultMaxOffset\n        val mOffset: Int\n        val downResistance: Float\n        downResistance = if (offset > 0) {\n            0.8f\n        } else {\n            //下拉阻力(0f-1f) 越小阻力越大，当前计算公式:1-mCurrentOffset/maxheight\n            1f - mCurrentOffset.toFloat() / maxOffset\n        }\n        mOffset = if (offset > 0) {\n            Math.min(MAX_OFFSET, Math.ceil((downResistance * offset).toDouble()).toInt())\n        } else {\n            Math.max(-MAX_OFFSET, Math.floor((downResistance * offset).toDouble()).toInt())\n        }\n        return mOffset\n    }\n\n    /**\n     * 移动视图\n     * @param offset 偏移量\n     */\n    private fun moveView(offset: Int) {\n        var invalidate = false\n        val refreshHeight = mHeader?.refreshHeight() ?: defaultRefreshHeight\n        if (!mRefreshing && mCurrentOffset == 0 && offset > 0) {\n            mHeader?.onPrepare(this)\n        }\n\n        if (mCurrentOffset > height || mCurrentOffset == 0) {\n            invalidate = true\n        }\n\n        mCurrentOffset += offset\n        mHeaderView?.offsetTopAndBottom(offset)\n        if (!pinContent)\n            mContentView?.offsetTopAndBottom(offset)\n        if (invalidate) invalidate()\n        mHeader?.onScroll(this, mCurrentOffset, mCurrentOffset.toFloat() / refreshHeight, mRefreshing)\n        mScrollListener?.invoke(offset, mCurrentOffset, mCurrentOffset.toFloat() / refreshHeight, mRefreshing)\n\n        if (!mRefreshing && offset < 0 && mCurrentOffset == 0) {\n            mHeader?.onReset(this)\n            mIsReset = true\n        }\n    }\n\n    /**\n     * 取消offset动画\n     */\n    private fun cancelAnimator() {\n        if (mOffsetAnimator.isRunning) {\n            mOffsetAnimator.cancel()\n        }\n    }\n\n    /**\n     * 结束下拉\n     */\n    private fun finishSpinner() {\n        if (mCurrentOffset <= 0) return\n        Log.d(LOG_TAG, \"finishSpinner mCurrentOffset is $mCurrentOffset , mRefreshing is $mRefreshing\")\n        val target: Int\n        val refreshHeight = mHeader?.refreshHeight() ?: defaultRefreshHeight\n        if (mRefreshing) {\n            target = if (mCurrentOffset >= refreshHeight / 2) refreshHeight else 0\n        } else {\n            target = if (mCurrentOffset >= refreshHeight && mIsReset) refreshHeight else 0\n            if (mCurrentOffset >= refreshHeight && mIsReset) {\n                mRefreshing = true//开始刷新\n                mIsReset = false\n                mHeader?.onRefresh(this)\n                mRefreshListener?.invoke(this)\n            }\n        }\n        animTo(target)\n    }\n\n\n    /**\n     * 动画方式移动\n\n     * @param target 目标位置\n     */\n    private fun animTo(target: Int) {\n        cancelAnimator()\n\n        val mTarget: Int = if (keepHeaderWhenRefresh) target else 0\n\n        if (mCurrentOffset == mTarget) {\n            return\n        }\n\n        Log.d(LOG_TAG, \"animTo $mCurrentOffset to $mTarget\")\n        mOffsetAnimator.duration = durationOffset\n        mOffsetAnimator.setIntValues(mCurrentOffset, mTarget)\n        mOffsetAnimator.start()\n    }\n\n    fun setKRefreshListener(refreshListener: (refreshLayout: KRefreshLayout) -> Unit){\n        mRefreshListener = refreshListener\n    }\n\n    /**\n     * offset(本次的偏移量)\n     * distance(总的偏移量)\n     * percent(偏移比率)\n     * refreshing(是否在刷新)\n     */\n    fun setKScrollListener(scrollListener: (offset: Int, distance: Int, percent: Float, refreshing: Boolean) -> Unit){\n        mScrollListener = scrollListener\n    }\n\n    fun setHeader(headerView: KRefreshHeader) {\n        setHeader(headerView, MATCH_PARENT, WRAP_CONTENT)\n    }\n\n    fun setHeader(headerView: KRefreshHeader, width: Int, height: Int) {\n        val params = generateDefaultLayoutParams()\n        params.width = width\n        params.height = height\n        setHeader(headerView, params)\n    }\n\n    fun setHeader(headerView: KRefreshHeader, params: LayoutParams) {\n        removeHeader()\n        mHeader = headerView\n        mHeaderView = mHeader as? View\n        addView(mHeaderView, 0, params)\n        mHeaderView?.bringToFront()\n    }\n\n    fun getHeader(): KRefreshHeader? = mHeader\n\n    fun removeHeader() {\n        removeView(mHeaderView)\n    }\n\n    /**\n     * 自动刷新\n     */\n    fun startRefresh() {\n        if (!mRefreshing && refreshEnable) {\n            postDelayed({\n                mRefreshing = true\n                mIsReset = false\n                mHeader?.onRefresh(this)\n                mRefreshListener?.invoke(this)\n                mContentView?.scrollTo(0, 0)\n                animTo(mHeader?.refreshHeight() ?: defaultRefreshHeight)\n            }, 100)\n        }\n    }\n\n    /**\n     * 刷新完成\n     */\n    fun refreshComplete(isSuccess: Boolean) {\n        if (mRefreshing) {\n            mHeader?.onComplete(this, isSuccess)\n            mRefreshing = false\n            if (mCurrentOffset == 0) {\n                mIsReset = true\n                cancelAnimator()\n                mHeader?.onReset(this)\n            } else {\n                //停滞时间\n                val retention = if (isSuccess) mHeader?.succeedRetention() ?: 0 else mHeader?.failingRetention() ?: 0\n                postDelayed({\n                    animTo(0)\n                }, retention)\n            }\n        }\n    }\n}"
  },
  {
    "path": "refresh-kotlin/src/main/res/values/kattr.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <declare-styleable name=\"KRefreshLayout\">\n        <attr name=\"k_pin_content\" format=\"boolean\" />\n        <attr name=\"k_keep_header\" format=\"boolean\" />\n        <attr name=\"k_refresh_enable\" format=\"boolean\" />\n        <attr name=\"k_duration_offset\" format=\"integer\" />\n        <attr name=\"k_def_refresh_height\" format=\"dimension\"/>\n        <attr name=\"k_def_max_offset\" format=\"dimension|enum\">\n            <enum name=\"match_parent\" value=\"-1\" />\n        </attr>\n    </declare-styleable>\n</resources>"
  },
  {
    "path": "settings.gradle",
    "content": "include ':app_kotlin', ':refresh-kotlin', ':refresh-java', ':app_java'\n"
  }
]