Showing preview only (365K chars total). Download the full file or copy to clipboard to get everything.
Repository: XiaoQiWen/KRefreshLayout
Branch: master
Commit: 510cd29710d1
Files: 103
Total size: 326.7 KB
Directory structure:
gitextract_ue_irtns/
├── .gitattributes
├── .gitignore
├── LICENSE
├── LoadMore.md
├── README.md
├── app_java/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/
│ │ └── gorden/
│ │ └── jrefresh/
│ │ └── demo/
│ │ ├── MainActivity.java
│ │ ├── header/
│ │ │ └── ClassicalHeader.java
│ │ └── util/
│ │ └── DensityUtil.java
│ └── res/
│ ├── layout/
│ │ ├── activity_main.xml
│ │ └── item_sample.xml
│ └── values/
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
├── app_kotlin/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── kotlin/
│ │ └── gorden/
│ │ └── krefreshlayout/
│ │ └── demo/
│ │ ├── App.java
│ │ ├── footer/
│ │ │ └── ClassicalFooter.java
│ │ ├── header/
│ │ │ ├── ClassicalHeader.java
│ │ │ ├── WechatHeader.java
│ │ │ ├── circle/
│ │ │ │ ├── AnimationView.java
│ │ │ │ └── CircleHeader.java
│ │ │ ├── fungame/
│ │ │ │ ├── BattleCityView.java
│ │ │ │ ├── FunGameFactory.java
│ │ │ │ ├── FunGameHeader.java
│ │ │ │ ├── FunGameView.java
│ │ │ │ └── HitBlockView.java
│ │ │ ├── materia/
│ │ │ │ ├── CircleImageView.java
│ │ │ │ ├── MateriaProgressHeader.java
│ │ │ │ └── MaterialProgressDrawable.java
│ │ │ ├── rentals/
│ │ │ │ ├── RentalsSunDrawable.java
│ │ │ │ └── RentalsSunHeaderView.java
│ │ │ └── storehouse/
│ │ │ ├── StoreHouseBarItem.java
│ │ │ ├── StoreHouseHeader.java
│ │ │ └── StoreHousePath.java
│ │ ├── ui/
│ │ │ ├── MainActivity.kt
│ │ │ ├── SampleActivity.kt
│ │ │ ├── SettingActivity.kt
│ │ │ └── fragment/
│ │ │ ├── ISampleFragment.kt
│ │ │ ├── SampleAFragment.kt
│ │ │ ├── SampleBFragment.kt
│ │ │ ├── SampleCFragment.kt
│ │ │ ├── SampleDFragment.kt
│ │ │ ├── SampleEFragment.kt
│ │ │ ├── SampleFFragment.kt
│ │ │ ├── SampleGFragment.kt
│ │ │ ├── SampleHFragment.kt
│ │ │ ├── SampleIFragment.kt
│ │ │ └── SampleJFragment.kt
│ │ ├── util/
│ │ │ ├── CrashHandler.java
│ │ │ ├── DensityUtil.java
│ │ │ └── XLog.java
│ │ └── widget/
│ │ ├── AdViewPager.java
│ │ ├── HeaderFloatBehavior.java
│ │ ├── HeaderScrollingBehavior.java
│ │ └── recyclerview/
│ │ ├── KLoadMoreView.kt
│ │ └── KRecyclerView.kt
│ └── res/
│ ├── drawable/
│ │ ├── bg_main.xml
│ │ └── selector_adpager_point.xml
│ ├── layout/
│ │ ├── activity_header_list.xml
│ │ ├── activity_main.xml
│ │ ├── activity_sample.xml
│ │ ├── activity_setting.xml
│ │ ├── item_main.xml
│ │ ├── item_sample.xml
│ │ ├── layout_coordinatorlayout.xml
│ │ ├── layout_krecyclerview.xml
│ │ ├── layout_nestedscrollview.xml
│ │ ├── layout_recyclerview.xml
│ │ ├── layout_scrollview.xml
│ │ ├── layout_viewpager.xml
│ │ ├── layout_vp_nestedscrollview.xml
│ │ ├── layout_vp_scrollview.xml
│ │ └── layout_webview.xml
│ └── values/
│ ├── attrs.xml
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── bintrayUpload.gradle
├── build.gradle
├── refresh-java/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ ├── project.properties
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── java/
│ │ └── gorden/
│ │ └── refresh/
│ │ ├── JRefreshHeader.java
│ │ └── JRefreshLayout.java
│ └── res/
│ └── values/
│ └── jattr.xml
├── refresh-kotlin/
│ ├── .gitignore
│ ├── build.gradle
│ ├── proguard-rules.pro
│ ├── project.properties
│ └── src/
│ └── main/
│ ├── AndroidManifest.xml
│ ├── kotlin/
│ │ └── gorden/
│ │ └── refresh/
│ │ ├── KRefreshHeader.kt
│ │ └── KRefreshLayout.kt
│ └── res/
│ └── values/
│ └── kattr.xml
└── settings.gradle
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
*.java linguist-language=kotlin
================================================
FILE: .gitignore
================================================
# Built application files
*.apk
*.ap_
# Files for the ART/Dalvik VM
*.dex
# Java class files
*.class
# Generated files
bin/
gen/
out/
# Gradle files
.gradle/
gradle/
build/
gradle.properties
# Local configuration file (sdk path, etc)
local.properties
# Proguard folder generated by Eclipse
proguard/
# Log Files
*.log
# Android Studio Navigation editor temp files
.navigation/
# Android Studio captures folder
captures/
# Intellij
*.idea/
.idea/workspace.xml
.idea/tasks.xml
.idea/gradle.xml
.idea/dictionaries
.idea/libraries
.idea/copyright
.idea/vcs.xml
# Keystore files
*.jks
# External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild
# Google Services (e.g. APIs or Firebase)
google-services.json
# Freeline
freeline.py
freeline/
freeline_project_description.json
gradlew
gradlew.bat
*.iml
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: LoadMore.md
================================================
#### 为什么不将LoadMore功能集成进RefreshLayout
* 实现效果不友好,loadMoreView加载完成后,会有个回弹效果(个人不喜欢)
* 加载更多的触发时机不好控制(比如滚动到内容倒数几条的时候自动加载)
---
[可以参考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>
</br>
Demo中[KLoadMoreView](https://github.com/XiaoQiWen/KRefreshLayout/blob/master/app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/widget/recyclerview/KLoadMoreView.kt)说明
```
interface KLoadMoreView {
/**
* 自定义适当的加载时机
* @return true 自定义生效 false默认的加载时机
*/
fun shouldLoadMore(recyclerView: KRecyclerView):Boolean
/**
* 正在加载
*/
fun onLoadMore(recyclerView: KRecyclerView)
/**
* 加载完成
* @param hasMore 是否还有更多数据
*/
fun onComplete(recyclerView: KRecyclerView, hasMore:Boolean)
/**
* 加载失败
* @param errorCode 错误码,由用户定义
*/
fun onError(recyclerView: KRecyclerView, errorCode:Int)
}
```
[LoadMoreDemo.APK下载](https://github.com/XiaoQiWen/Resources/raw/master/KRefreshLayout/demo_new.apk)
================================================
FILE: README.md
================================================
# KRefreshLayout (JRefreshLayout)
kotlin和java两个版本的下拉刷新框架,支持任意View、支持定制任意header
## Download[](https://github.com/XiaoQiWen/KRefreshLayout/releases)
#### KRefreshLayout
gradle
```
compile 'gorden.refresh:refresh-kotlin:1.3'
```
maven
```
<dependency>
<groupId>gorden.refresh</groupId>
<artifactId>refresh-kotlin</artifactId>
<version>1.3</version>
<type>pom</type>
</dependency>
```
``注意:kotlin版本目前需要下载插件或者使用AndroidStudio3.0+``</br>
#### JRefreshLayout
gradle
```
compile 'gorden.refresh:refresh-java:1.3'
```
maven
```
<dependency>
<groupId>gorden.refresh</groupId>
<artifactId>refresh-java</artifactId>
<version>1.3</version>
<type>pom</type>
</dependency
```
## example
[DEMO下载](https://github.com/XiaoQiWen/Resources/raw/master/KRefreshLayout/demo1.2.apk)</br></br>


</br></br>


</br></br>


## Usage
``KRefreshLayou详细使用说明:``
>* [RefreshHeader接口说明](https://github.com/XiaoQiWen/KRefreshLayout/wiki/RefreshHeader%E6%96%B9%E6%B3%95%E8%AF%B4%E6%98%8E)
>* [RefreshLayout开放Api](https://github.com/XiaoQiWen/KRefreshLayout/wiki/RefreshLayout%E5%BC%80%E6%94%BEApi)
>* [XML参数配置](https://github.com/XiaoQiWen/KRefreshLayout/wiki/RefreshHeader-XML%E5%8F%AF%E9%85%8D%E7%BD%AE%E5%8F%82%E6%95%B0)
>* [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)
>* [微信刷新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)
设置刷新监听
```
refreshLayout.setKRefreshListener {
refreshLayout.postDelayed({
//这里的true是指刷新成功,在header接口中complete能接收到这参数
refreshLayout.refreshComplete(true)
}, 2000)
}
```
---
[关于加载更多](https://github.com/XiaoQiWen/KRefreshLayout/blob/master/LoadMore.md)</br></br>
更多请参考Demo
### 联系方式
* QQ: 354419188
* Email: gordenxqw@gmail.com
### License
Copyright (C) 2017 XiaoQiWen
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: app_java/.gitignore
================================================
/build
================================================
FILE: app_java/build.gradle
================================================
apply plugin: 'com.android.application'
android {
compileSdkVersion 27
buildToolsVersion "27.0.1"
defaultConfig {
applicationId "gorden.jrefresh.demo"
minSdkVersion 15
versionCode 1
versionName "1.1"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:design:27.0.0'
compile 'com.android.support:appcompat-v7:27.0.0'
compile project(':refresh-java')
}
================================================
FILE: app_java/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in F:\AndroidSdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
================================================
FILE: app_java/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="gorden.jrefresh.demo">
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
================================================
FILE: app_java/src/main/java/gorden/jrefresh/demo/MainActivity.java
================================================
package gorden.jrefresh.demo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import gorden.refresh.JRefreshLayout;
public class MainActivity extends AppCompatActivity {
JRefreshLayout refreshLayout;
RecyclerView recyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
refreshLayout = (JRefreshLayout) findViewById(R.id.refreshLayout);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setAdapter(new RecyclerView.Adapter() {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new RecyclerView.ViewHolder(LayoutInflater.from(getBaseContext()).inflate(R.layout.item_sample,null)) {
};
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
}
@Override
public int getItemCount() {
return 20;
}
});
refreshLayout.setJRefreshListener(new JRefreshLayout.JRefreshListener() {
@Override
public void onRefresh(final JRefreshLayout refreshLayout) {
refreshLayout.postDelayed(new Runnable() {
@Override
public void run() {
refreshLayout.refreshComplete(true);
}
},3000);
}
});
}
}
================================================
FILE: app_java/src/main/java/gorden/jrefresh/demo/header/ClassicalHeader.java
================================================
package gorden.jrefresh.demo.header;
import android.content.Context;
import android.graphics.Color;
import android.support.annotation.AttrRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import gorden.jrefresh.demo.R;
import gorden.jrefresh.demo.util.DensityUtil;
import gorden.refresh.JRefreshHeader;
import gorden.refresh.JRefreshLayout;
/**
* 经典下拉刷新
* Created by Gorden on 2017/6/17.
*/
public class ClassicalHeader extends FrameLayout implements JRefreshHeader {
private static final String TAG = "ClassicalHeader";
private ImageView arrawImg;
private TextView textTitle;
private RotateAnimation rotateAnimation = new RotateAnimation(0,360,Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
public ClassicalHeader(@NonNull Context context) {
this(context,null);
}
public ClassicalHeader(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public ClassicalHeader(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
LinearLayout root = new LinearLayout(context);
root.setOrientation(LinearLayout.HORIZONTAL);
root.setGravity(Gravity.CENTER_VERTICAL);
addView(root,LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
((LayoutParams)root.getLayoutParams()).gravity = Gravity.CENTER;
arrawImg = new ImageView(context);
arrawImg.setImageResource(R.drawable.ic_arrow_down);
arrawImg.setScaleType(ImageView.ScaleType.CENTER);
root.addView(arrawImg);
textTitle = new TextView(context);
textTitle.setTextSize(13);
textTitle.setText("下拉刷新...");
textTitle.setTextColor(Color.parseColor("#999999"));
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
params.leftMargin = 20;
root.addView(textTitle,params);
rotateAnimation.setDuration(800);
rotateAnimation.setInterpolator(new LinearInterpolator());
rotateAnimation.setRepeatCount(Animation.INFINITE);
rotateAnimation.setRepeatMode(Animation.RESTART);
setPadding(0, DensityUtil.dip2px(15),0,DensityUtil.dip2px(15));
}
@Override
public long succeedRetention() {
return 200;
}
@Override
public long failingRetention() {
return 0;
}
@Override
public int refreshHeight() {
return getHeight();
}
@Override
public int maxOffsetHeight() {
return 4*getHeight();
}
boolean isReset = true;
@Override
public void onReset( JRefreshLayout refreshLayout) {
Log.e(TAG,"----------------> onReset");
arrawImg.setImageResource(R.drawable.ic_arrow_down);
textTitle.setText("下拉刷新...");
isReset = true;
arrawImg.setVisibility(VISIBLE);
}
@Override
public void onPrepare( JRefreshLayout refreshLayout) {
Log.e(TAG,"----------------> onPrepare");
arrawImg.setImageResource(R.drawable.ic_arrow_down);
textTitle.setText("下拉刷新...");
}
@Override
public void onRefresh( JRefreshLayout refreshLayout) {
Log.e(TAG,"----------------> onRefresh");
arrawImg.setImageResource(R.drawable.ic_loading);
arrawImg.startAnimation(rotateAnimation);
textTitle.setText("加载中...");
isReset = false;
}
@Override
public void onComplete( JRefreshLayout refreshLayout,boolean isSuccess) {
Log.e(TAG,"----------------> onComplete");
arrawImg.clearAnimation();
arrawImg.setVisibility(GONE);
if (isSuccess){
textTitle.setText("刷新完成...");
}else{
textTitle.setText("刷新失败...");
}
}
boolean attain = false;
@Override
public void onScroll( JRefreshLayout refreshLayout, int distance, float percent,boolean refreshing) {
Log.e(TAG,"----------------> onScroll "+percent);
if (!refreshing&&isReset){
if(percent>=1&&!attain){
attain = true;
textTitle.setText("释放刷新...");
arrawImg.animate().rotation(-180).start();
}else if (percent<1&&attain){
attain = false;
arrawImg.animate().rotation(0).start();
textTitle.setText("下拉刷新...");
}
}
}
}
================================================
FILE: app_java/src/main/java/gorden/jrefresh/demo/util/DensityUtil.java
================================================
package gorden.jrefresh.demo.util;
import android.content.res.Resources;
/**
* document
* Created by Gordn on 2017/6/19.
*/
public class DensityUtil {
private static float density = Resources.getSystem().getDisplayMetrics().density;
public static int dip2px(int dp){
return (int) (dp*density);
}
public static int dip2px(float dp){
return (int) (dp*density);
}
public static int appWidth(){
return Resources.getSystem().getDisplayMetrics().widthPixels;
}
}
================================================
FILE: app_java/src/main/res/layout/activity_main.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context="gorden.jrefresh.demo.MainActivity">
<gorden.refresh.JRefreshLayout
android:id="@+id/refreshLayout"
android:layout_width="match_parent"
android:background="#2f5181"
android:layout_height="match_parent">
<gorden.jrefresh.demo.header.ClassicalHeader
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
app:layoutManager="LinearLayoutManager"
android:layout_height="match_parent"/>
</gorden.refresh.JRefreshLayout>
</FrameLayout>
================================================
FILE: app_java/src/main/res/layout/item_sample.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="100dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:background="#ffffff"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/img_java"
/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="This is Sample Item"
android:textColor="#333"
android:textSize="16sp"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="This is Sample Item description"
/>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
================================================
FILE: app_java/src/main/res/values/colors.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
</resources>
================================================
FILE: app_java/src/main/res/values/strings.xml
================================================
<resources>
<string name="app_name">JRefreshLayout</string>
</resources>
================================================
FILE: app_java/src/main/res/values/styles.xml
================================================
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
================================================
FILE: app_kotlin/.gitignore
================================================
/build
================================================
FILE: app_kotlin/build.gradle
================================================
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 27
buildToolsVersion "27.0.1"
defaultConfig {
applicationId "gorden.krefreshlayout.demo"
minSdkVersion 15
versionCode 1
versionName "1.1"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
// compile 'gorden.refresh:refresh-kotlin:1.0'
compile project(path: ':refresh-kotlin')
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
compile 'com.android.support:appcompat-v7:27.0.0'
compile 'com.android.support:design:27.0.0'
testCompile 'junit:junit:4.12'
}
repositories {
mavenCentral()
}
================================================
FILE: app_kotlin/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in D:\Android\sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
================================================
FILE: app_kotlin/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="gorden.krefreshlayout.demo">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name=".App"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".ui.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".ui.SampleActivity">
<intent-filter>
<action android:name="SampleActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name=".ui.SettingActivity">
<intent-filter>
<action android:name="SettingActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/App.java
================================================
package gorden.krefreshlayout.demo;
import android.app.Application;
import android.content.Intent;
import gorden.krefreshlayout.demo.ui.SampleActivity;
import gorden.krefreshlayout.demo.util.CrashHandler;
/**
* Created by Gorden on 2017/6/20.
*/
public class App extends Application{
@Override
public void onCreate() {
super.onCreate();
CrashHandler.getInstance().init(this,true);
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/footer/ClassicalFooter.java
================================================
package gorden.krefreshlayout.demo.footer;
import android.content.Context;
import android.graphics.Color;
import android.support.annotation.AttrRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.jetbrains.annotations.NotNull;
import gorden.krefreshlayout.demo.R;
import gorden.krefreshlayout.demo.util.DensityUtil;
import gorden.krefreshlayout.demo.widget.recyclerview.KLoadMoreView;
import gorden.krefreshlayout.demo.widget.recyclerview.KRecyclerView;
/**
* 经典下拉刷新
* Created by Gorden on 2017/6/17.
*/
public class ClassicalFooter extends FrameLayout implements KLoadMoreView {
private KRecyclerView recyclerView;
private ImageView arrawImg;
private TextView textTitle;
private RotateAnimation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
public ClassicalFooter(@NonNull Context context) {
this(context, null);
}
public ClassicalFooter(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public ClassicalFooter(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
LinearLayout root = new LinearLayout(context);
root.setOrientation(LinearLayout.HORIZONTAL);
root.setGravity(Gravity.CENTER_VERTICAL);
addView(root, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
((LayoutParams) root.getLayoutParams()).gravity = Gravity.CENTER;
arrawImg = new ImageView(context);
arrawImg.setImageResource(R.drawable.ic_loading);
arrawImg.setScaleType(ImageView.ScaleType.CENTER);
root.addView(arrawImg);
textTitle = new TextView(context);
textTitle.setTextSize(13);
textTitle.setText("上拉或点击加载更多...");
textTitle.setTextColor(Color.parseColor("#999999"));
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.leftMargin = 20;
root.addView(textTitle, params);
rotateAnimation.setDuration(800);
rotateAnimation.setInterpolator(new LinearInterpolator());
rotateAnimation.setRepeatCount(Animation.INFINITE);
rotateAnimation.setRepeatMode(Animation.RESTART);
setPadding(0, DensityUtil.dip2px(15), 0, DensityUtil.dip2px(15));
setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
recyclerView.startLoadMore();
}
});
}
@Override
public boolean shouldLoadMore(@NotNull KRecyclerView recyclerView) {
this.recyclerView = recyclerView;
return false;
}
@Override
public void onLoadMore(@NotNull KRecyclerView recyclerView) {
arrawImg.setVisibility(VISIBLE);
arrawImg.startAnimation(rotateAnimation);
textTitle.setText("正在加载...");
}
@Override
public void onComplete(@NotNull KRecyclerView recyclerView, boolean hasMore) {
arrawImg.clearAnimation();
textTitle.setText(hasMore ? "上拉或点击加载更多..." : "没有更多数据");
arrawImg.setVisibility(GONE);
}
@Override
public void onError(@NotNull KRecyclerView recyclerView, int errorCode) {
arrawImg.clearAnimation();
textTitle.setText("加载失败,点击重新加载");
arrawImg.setVisibility(GONE);
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/ClassicalHeader.java
================================================
package gorden.krefreshlayout.demo.header;
import android.content.Context;
import android.graphics.Color;
import android.support.annotation.AttrRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.jetbrains.annotations.NotNull;
import gorden.krefreshlayout.demo.R;
import gorden.krefreshlayout.demo.util.DensityUtil;
import gorden.refresh.KRefreshHeader;
import gorden.refresh.KRefreshLayout;
/**
* 经典下拉刷新
* Created by Gorden on 2017/6/17.
*/
public class ClassicalHeader extends FrameLayout implements KRefreshHeader {
private static final String TAG = "ClassicalHeader";
private ImageView arrawImg;
private TextView textTitle;
private RotateAnimation rotateAnimation = new RotateAnimation(0,360,Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
public ClassicalHeader(@NonNull Context context) {
this(context,null);
}
public ClassicalHeader(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs,0);
}
public ClassicalHeader(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {
super(context, attrs, defStyleAttr);
LinearLayout root = new LinearLayout(context);
root.setOrientation(LinearLayout.HORIZONTAL);
root.setGravity(Gravity.CENTER_VERTICAL);
addView(root,LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
((LayoutParams)root.getLayoutParams()).gravity = Gravity.CENTER;
arrawImg = new ImageView(context);
arrawImg.setImageResource(R.drawable.ic_arrow_down);
arrawImg.setScaleType(ImageView.ScaleType.CENTER);
root.addView(arrawImg);
textTitle = new TextView(context);
textTitle.setTextSize(13);
textTitle.setText("下拉刷新...");
textTitle.setTextColor(Color.parseColor("#999999"));
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
params.leftMargin = 20;
root.addView(textTitle,params);
rotateAnimation.setDuration(800);
rotateAnimation.setInterpolator(new LinearInterpolator());
rotateAnimation.setRepeatCount(Animation.INFINITE);
rotateAnimation.setRepeatMode(Animation.RESTART);
setPadding(0, DensityUtil.dip2px(15),0,DensityUtil.dip2px(15));
}
@Override
public long succeedRetention() {
return 200;
}
@Override
public long failingRetention() {
return 0;
}
@Override
public int refreshHeight() {
return getHeight();
}
@Override
public int maxOffsetHeight() {
return 4*getHeight();
}
boolean isReset = true;
@Override
public void onReset(@NotNull KRefreshLayout refreshLayout) {
Log.e(TAG,"----------------> onReset");
arrawImg.setImageResource(R.drawable.ic_arrow_down);
textTitle.setText("下拉刷新...");
isReset = true;
arrawImg.setVisibility(VISIBLE);
}
@Override
public void onPrepare(@NotNull KRefreshLayout refreshLayout) {
Log.e(TAG,"----------------> onPrepare");
arrawImg.setImageResource(R.drawable.ic_arrow_down);
textTitle.setText("下拉刷新...");
}
@Override
public void onRefresh(@NotNull KRefreshLayout refreshLayout) {
Log.e(TAG,"----------------> onRefresh");
arrawImg.setImageResource(R.drawable.ic_loading);
arrawImg.startAnimation(rotateAnimation);
textTitle.setText("加载中...");
isReset = false;
}
@Override
public void onComplete(@NotNull KRefreshLayout refreshLayout,boolean isSuccess) {
Log.e(TAG,"----------------> onComplete");
arrawImg.clearAnimation();
arrawImg.setVisibility(GONE);
if (isSuccess){
textTitle.setText("刷新完成...");
}else{
textTitle.setText("刷新失败...");
}
}
boolean attain = false;
@Override
public void onScroll(@NotNull KRefreshLayout refreshLayout, int distance, float percent,boolean refreshing) {
Log.e(TAG,"----------------> onScroll "+percent);
if (!refreshing&&isReset){
if(percent>=1&&!attain){
attain = true;
textTitle.setText("释放刷新...");
arrawImg.animate().rotation(-180).start();
}else if (percent<1&&attain){
attain = false;
arrawImg.animate().rotation(0).start();
textTitle.setText("下拉刷新...");
}
}
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/WechatHeader.java
================================================
package gorden.krefreshlayout.demo.header;
import android.animation.ValueAnimator;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.widget.FrameLayout;
import android.widget.ImageView;
import org.jetbrains.annotations.NotNull;
import gorden.krefreshlayout.demo.R;
import gorden.krefreshlayout.demo.util.DensityUtil;
import gorden.refresh.KRefreshHeader;
import gorden.refresh.KRefreshLayout;
/**
* document
* Created by Gordn on 2017/6/26.
*/
public class WechatHeader extends FrameLayout implements KRefreshHeader {
private ImageView imgChat;
private RotateAnimation rotateAnimation = new RotateAnimation(0, 360, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
private ValueAnimator returnAnima = new ValueAnimator();
public WechatHeader(@NonNull Context context) {
this(context, null);
}
public WechatHeader(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
imgChat = new ImageView(context);
imgChat.setImageResource(R.drawable.ic_wechat);
LayoutParams params = new LayoutParams(DensityUtil.dip2px(30), DensityUtil.dip2px(30));
params.leftMargin = DensityUtil.dip2px(20);
addView(imgChat, params);
rotateAnimation.setDuration(800);
rotateAnimation.setInterpolator(new LinearInterpolator());
rotateAnimation.setRepeatCount(Animation.INFINITE);
rotateAnimation.setRepeatMode(Animation.RESTART);
returnAnima.setDuration(800);
returnAnima.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int progress = (int) animation.getAnimatedValue();
offsetTopAndBottom(progress - mDistance);
imgChat.setRotation(progress);
mDistance = progress;
if (getParent() instanceof KRefreshLayout) {
((KRefreshLayout) getParent()).setHeaderOffset(mDistance - lastDistance);
}
}
});
}
@Override
public long succeedRetention() {
return 0;
}
@Override
public long failingRetention() {
return 0;
}
@Override
public int refreshHeight() {
return DensityUtil.dip2px(50);
}
@Override
public int maxOffsetHeight() {
return ((View) getParent()).getHeight();
}
@Override
public void onReset(@NotNull KRefreshLayout refreshLayout) {
}
@Override
public void onPrepare(@NotNull KRefreshLayout refreshLayout) {
}
@Override
public void onRefresh(@NotNull KRefreshLayout refreshLayout) {
imgChat.startAnimation(rotateAnimation);
}
@Override
public void onComplete(@NotNull KRefreshLayout refreshLayout, boolean isSuccess) {
imgChat.clearAnimation();
returnAnima.setIntValues(mDistance, 0);
returnAnima.start();
}
public int mDistance = 0;
private int lastDistance;
@Override
public void onScroll(@NotNull KRefreshLayout refreshLayout, int distance, float percent, boolean refreshing) {
int offset = distance - lastDistance;
if (returnAnima.isRunning())
returnAnima.cancel();
lastDistance = distance;
if (!refreshing) {
imgChat.setRotation(-distance);
if (percent > 1) {
offsetTopAndBottom(-offset);
if (mDistance != refreshHeight()) {
offset = refreshHeight() - mDistance;
offsetTopAndBottom(offset);
mDistance += offset;
}
} else {
if (mDistance + offset != distance) {
offset = distance - (mDistance + offset);
offsetTopAndBottom(offset);
}
mDistance = distance;
}
} else {
offsetTopAndBottom(-offset);
}
refreshLayout.setHeaderOffset(mDistance - distance);
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/circle/AnimationView.java
================================================
package gorden.krefreshlayout.demo.header.circle;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by zhanglei on 15/7/18.
*/
public class AnimationView extends View {
private static final String TAG = "AnimationView";
private int PULL_HEIGHT;
private int PULL_DELTA;
private float mWidthOffset;
private AnimatorStatus mAniStatus = AnimatorStatus.PULL_DOWN;
enum AnimatorStatus {
PULL_DOWN,
DRAG_DOWN,
REL_DRAG,
SPRING_UP, // rebound to up, the position is less than PULL_HEIGHT
POP_BALL,
OUTER_CIR,
REFRESHING,
DONE,
STOP;
@Override
public String toString() {
switch (this) {
case PULL_DOWN:
return "pull down";
case DRAG_DOWN:
return "drag down";
case REL_DRAG:
return "release drag";
case SPRING_UP:
return "spring up";
case POP_BALL:
return "pop ball";
case OUTER_CIR:
return "outer circle";
case REFRESHING:
return "refreshing...";
case DONE:
return "done!";
case STOP:
return "stop";
default:
return "unknown state";
}
}
}
private Paint mBackPaint;
private Paint mBallPaint;
private Paint mOutPaint;
private Path mPath;
public AnimationView(Context context) {
this(context, null, 0);
}
public AnimationView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public AnimationView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context, attrs, defStyleAttr);
}
private void initView(Context context, AttributeSet attrs, int defStyleAttr) {
PULL_HEIGHT = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100, context.getResources().getDisplayMetrics());
PULL_DELTA = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, context.getResources().getDisplayMetrics());
mWidthOffset = 0.5f;
mBackPaint = new Paint();
mBackPaint.setAntiAlias(true);
mBackPaint.setStyle(Paint.Style.FILL);
mBackPaint.setColor(0xff8b90af);
mBallPaint = new Paint();
mBallPaint.setAntiAlias(true);
mBallPaint.setColor(0xffffffff);
mBallPaint.setStyle(Paint.Style.FILL);
mOutPaint = new Paint();
mOutPaint.setAntiAlias(true);
mOutPaint.setColor(0xffffffff);
mOutPaint.setStyle(Paint.Style.STROKE);
mOutPaint.setStrokeWidth(5);
mPath = new Path();
}
private int mRadius;
private int mWidth;
private int mHeight;
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = MeasureSpec.getSize(heightMeasureSpec);
if (height > PULL_DELTA + PULL_HEIGHT) {
heightMeasureSpec = MeasureSpec.makeMeasureSpec(PULL_DELTA + PULL_HEIGHT, MeasureSpec.getMode(heightMeasureSpec));
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
if (changed) {
mRadius = getHeight() / 6;
mWidth = getWidth();
mHeight = getHeight();
if (mHeight < PULL_HEIGHT) {
mAniStatus = AnimatorStatus.PULL_DOWN;
}
switch (mAniStatus) {
case PULL_DOWN:
if (mHeight >= PULL_HEIGHT) {
mAniStatus = AnimatorStatus.DRAG_DOWN;
}
break;
case REL_DRAG:
break;
}
}
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
switch (mAniStatus) {
case PULL_DOWN:
canvas.drawRect(0, 0, mWidth, mHeight, mBackPaint);
break;
case REL_DRAG:
case DRAG_DOWN:
drawDrag(canvas);
break;
case SPRING_UP:
drawSpring(canvas, getSpringDelta());
invalidate();
break;
case POP_BALL:
drawPopBall(canvas);
invalidate();
break;
case OUTER_CIR:
drawOutCir(canvas);
invalidate();
break;
case REFRESHING:
drawRefreshing(canvas);
invalidate();
break;
case DONE:
drawDone(canvas);
invalidate();
break;
case STOP:
drawDone(canvas);
break;
}
if (mAniStatus == AnimatorStatus.REL_DRAG) {
ViewGroup.LayoutParams params = getLayoutParams();
int height;
// NOTICE: If the height equals mLastHeight, then the requestLayout() will not work correctly
do {
height = getRelHeight();
} while (height == mLastHeight && getRelRatio() != 1);
mLastHeight = height;
params.height = PULL_HEIGHT + height;
requestLayout();
}
}
private void drawDrag(Canvas canvas) {
canvas.drawRect(0, 0, mWidth, PULL_HEIGHT, mBackPaint);
mPath.reset();
mPath.moveTo(0, PULL_HEIGHT);
mPath.quadTo(mWidthOffset * mWidth, PULL_HEIGHT + (mHeight - PULL_HEIGHT) * 2,
mWidth, PULL_HEIGHT);
canvas.drawPath(mPath, mBackPaint);
}
private void drawSpring(Canvas canvas, int springDelta) {
mPath.reset();
mPath.moveTo(0, 0);
mPath.lineTo(0, PULL_HEIGHT);
mPath.quadTo(mWidth / 2, PULL_HEIGHT - springDelta,
mWidth, PULL_HEIGHT);
mPath.lineTo(mWidth, 0);
canvas.drawPath(mPath, mBackPaint);
int curH = PULL_HEIGHT - springDelta / 2;
if (curH > PULL_HEIGHT - PULL_DELTA / 2) {
int leftX = (int) (mWidth / 2 - 2 * mRadius + getSprRatio() * mRadius);
mPath.reset();
mPath.moveTo(leftX, curH);
mPath.quadTo(mWidth / 2, curH - mRadius * getSprRatio() * 2,
mWidth - leftX, curH);
canvas.drawPath(mPath, mBallPaint);
} else {
canvas.drawArc(new RectF(mWidth / 2 - mRadius, curH - mRadius, mWidth / 2 + mRadius, curH + mRadius),
180, 180, true, mBallPaint);
}
}
private void drawPopBall(Canvas canvas) {
mPath.reset();
mPath.moveTo(0, 0);
mPath.lineTo(0, PULL_HEIGHT);
mPath.quadTo(mWidth / 2, PULL_HEIGHT - PULL_DELTA,
mWidth, PULL_HEIGHT);
mPath.lineTo(mWidth, 0);
canvas.drawPath(mPath, mBackPaint);
int cirCentStart = PULL_HEIGHT - PULL_DELTA / 2;
int cirCenY = (int) (cirCentStart - mRadius * 2 * getPopRatio());
canvas.drawArc(new RectF(mWidth / 2 - mRadius, cirCenY - mRadius, mWidth / 2 + mRadius, cirCenY + mRadius),
180, 360, true, mBallPaint);
if (getPopRatio() < 1) {
drawTail(canvas, cirCenY, cirCentStart + 1, getPopRatio());
} else {
canvas.drawCircle(mWidth / 2, cirCenY, mRadius, mBallPaint);
}
}
private void drawTail(Canvas canvas, int centerY, int bottom, float fraction) {
int bezier1w = (int) (mWidth / 2 + (mRadius * 3 / 4) * (1 - fraction));
PointF start = new PointF(mWidth / 2 + mRadius, centerY);
PointF bezier1 = new PointF(bezier1w, bottom);
PointF bezier2 = new PointF(bezier1w + mRadius / 2, bottom);
mPath.reset();
mPath.moveTo(start.x, start.y);
mPath.quadTo(bezier1.x, bezier1.y,
bezier2.x, bezier2.y);
mPath.lineTo(mWidth - bezier2.x, bezier2.y);
mPath.quadTo(mWidth - bezier1.x, bezier1.y,
mWidth - start.x, start.y);
canvas.drawPath(mPath, mBallPaint);
}
private void drawOutCir(Canvas canvas) {
mPath.reset();
mPath.moveTo(0, 0);
mPath.lineTo(0, PULL_HEIGHT);
mPath.quadTo(mWidth / 2, PULL_HEIGHT - (1 - getOutRatio()) * PULL_DELTA,
mWidth, PULL_HEIGHT);
mPath.lineTo(mWidth, 0);
canvas.drawPath(mPath, mBackPaint);
int innerY = PULL_HEIGHT - PULL_DELTA / 2 - mRadius * 2;
canvas.drawCircle(mWidth / 2, innerY, mRadius, mBallPaint);
}
private int mRefreshStart = 90;
private int mRefreshStop = 90;
private int TARGET_DEGREE = 270;
private boolean mIsStart = true;
private boolean mIsRefreshing = true;
private void drawRefreshing(Canvas canvas) {
canvas.drawRect(0, 0, mWidth, mHeight, mBackPaint);
int innerY = PULL_HEIGHT - PULL_DELTA / 2 - mRadius * 2;
canvas.drawCircle(mWidth / 2, innerY, mRadius, mBallPaint);
int outerR = mRadius + 10;
mRefreshStart += mIsStart ? 3 : 10;
mRefreshStop += mIsStart ? 10 : 3;
mRefreshStart = mRefreshStart % 360;
mRefreshStop = mRefreshStop % 360;
int swipe = mRefreshStop - mRefreshStart;
swipe = swipe < 0 ? swipe + 360 : swipe;
canvas.drawArc(new RectF(mWidth / 2 - outerR, innerY - outerR, mWidth / 2 + outerR, innerY + outerR),
mRefreshStart, swipe, false, mOutPaint);
if (swipe >= TARGET_DEGREE) {
mIsStart = false;
} else if (swipe <= 10) {
mIsStart = true;
}
if (!mIsRefreshing) {
applyDone();
}
}
// stop refreshing
public void setRefreshing(boolean isFresh) {
mIsRefreshing = isFresh;
}
private void drawDone(Canvas canvas) {
int beforeColor = mOutPaint.getColor();
if (getDoneRatio() < 0.3) {
canvas.drawRect(0, 0, mWidth, mHeight, mBackPaint);
int innerY = PULL_HEIGHT - PULL_DELTA / 2 - mRadius * 2;
canvas.drawCircle(mWidth / 2, innerY, mRadius, mBallPaint);
int outerR = (int) (mRadius + 10 + 10 * getDoneRatio() / 0.3f);
int afterColor = Color.argb((int) (0xff * (1 - getDoneRatio() / 0.3f)), Color.red(beforeColor),
Color.green(beforeColor), Color.blue(beforeColor));
mOutPaint.setColor(afterColor);
canvas.drawArc(new RectF(mWidth / 2 - outerR, innerY - outerR, mWidth / 2 + outerR, innerY + outerR),
0, 360, false, mOutPaint);
}
mOutPaint.setColor(beforeColor);
if (getDoneRatio() >= 0.3 && getDoneRatio() < 0.7) {
canvas.drawRect(0, 0, mWidth, mHeight, mBackPaint);
float fraction = (getDoneRatio() - 0.3f) / 0.4f;
int startCentY = PULL_HEIGHT - PULL_DELTA / 2 - mRadius * 2;
int curCentY = (int) (startCentY + (PULL_DELTA / 2 + mRadius * 2) * fraction);
canvas.drawCircle(mWidth / 2, curCentY, mRadius, mBallPaint);
if (curCentY >= PULL_HEIGHT - mRadius * 2) {
drawTail(canvas, curCentY, PULL_HEIGHT, (1 - fraction));
}
}
if (getDoneRatio() >= 0.7 && getDoneRatio() <= 1) {
float fraction = (getDoneRatio() - 0.7f) / 0.3f;
canvas.drawRect(0, 0, mWidth, mHeight, mBackPaint);
int leftX = (int) (mWidth / 2 - mRadius - 2 * mRadius * fraction);
mPath.reset();
mPath.moveTo(leftX, PULL_HEIGHT);
mPath.quadTo(mWidth / 2, PULL_HEIGHT - (mRadius * (1 - fraction)),
mWidth - leftX, PULL_HEIGHT);
canvas.drawPath(mPath, mBallPaint);
}
}
private int mLastHeight;
private int getRelHeight() {
return (int) (mSpriDeta * (1 - getRelRatio()));
}
private int getSpringDelta() {
return (int) (PULL_DELTA * getSprRatio());
}
private static long REL_DRAG_DUR = 200;
private long mStart;
private long mStop;
private int mSpriDeta;
public void releaseDrag() {
mStart = System.currentTimeMillis();
mStop = mStart + REL_DRAG_DUR;
mAniStatus = AnimatorStatus.REL_DRAG;
mSpriDeta = mHeight - PULL_HEIGHT;
requestLayout();
}
private float getRelRatio() {
if (System.currentTimeMillis() >= mStop) {
springUp();
return 1;
}
float ratio = (System.currentTimeMillis() - mStart) / (float) REL_DRAG_DUR;
return Math.min(ratio, 1);
}
private static long SPRING_DUR = 200;
private long mSprStart;
private long mSprStop;
private void springUp() {
mSprStart = System.currentTimeMillis();
mSprStop = mSprStart + SPRING_DUR;
mAniStatus = AnimatorStatus.SPRING_UP;
invalidate();
}
private float getSprRatio() {
if (System.currentTimeMillis() >= mSprStop) {
popBall();
return 1;
}
float ratio = (System.currentTimeMillis() - mSprStart) / (float) SPRING_DUR;
return Math.min(1, ratio);
}
private static final long POP_BALL_DUR = 300;
private long mPopStart;
private long mPopStop;
private void popBall() {
mPopStart = System.currentTimeMillis();
mPopStop = mPopStart + POP_BALL_DUR;
mAniStatus = AnimatorStatus.POP_BALL;
invalidate();
}
private float getPopRatio() {
if (System.currentTimeMillis() >= mPopStop) {
startOutCir();
return 1;
}
float ratio = (System.currentTimeMillis() - mPopStart) / (float) POP_BALL_DUR;
return Math.min(ratio, 1);
}
private static final long OUTER_DUR = 200;
private long mOutStart;
private long mOutStop;
private void startOutCir() {
mOutStart = System.currentTimeMillis();
mOutStop = mOutStart + OUTER_DUR;
mAniStatus = AnimatorStatus.OUTER_CIR;
mRefreshStart = 90;
mRefreshStop = 90;
TARGET_DEGREE = 270;
mIsStart = true;
mIsRefreshing = true;
invalidate();
}
private float getOutRatio() {
if (System.currentTimeMillis() >= mOutStop) {
mAniStatus = AnimatorStatus.REFRESHING;
mIsRefreshing = true;
return 1;
}
float ratio = (System.currentTimeMillis() - mOutStart) / (float) OUTER_DUR;
return Math.min(ratio, 1);
}
private static final long DONE_DUR = 1000;
private long mDoneStart;
private long mDoneStop;
private void applyDone() {
mDoneStart = System.currentTimeMillis();
mDoneStop = mDoneStart + DONE_DUR;
mAniStatus = AnimatorStatus.DONE;
}
private float getDoneRatio() {
if (System.currentTimeMillis() >= mDoneStop) {
mAniStatus = AnimatorStatus.STOP;
if (onViewAniDone != null) {
onViewAniDone.viewAniDone();
}
return 1;
}
float ratio = (System.currentTimeMillis() - mDoneStart) / (float) DONE_DUR;
return Math.min(ratio, 1);
}
private OnViewAniDone onViewAniDone;
public void setOnViewAniDone(OnViewAniDone onViewAniDone) {
this.onViewAniDone = onViewAniDone;
}
interface OnViewAniDone {
void viewAniDone();
}
public void setAniBackColor(int color) {
mBackPaint.setColor(color);
}
public void setAniForeColor(int color) {
mBallPaint.setColor(color);
mOutPaint.setColor(color);
setBackgroundColor(color);
}
// the height of view is smallTimes times of circle radius
public void setRadius(int smallTimes) {
mRadius = mHeight / smallTimes;
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/circle/CircleHeader.java
================================================
package gorden.krefreshlayout.demo.header.circle;
import android.animation.ValueAnimator;
import android.content.Context;
import android.support.annotation.NonNull;
import android.view.Gravity;
import android.view.View;
import android.widget.FrameLayout;
import org.jetbrains.annotations.NotNull;
import gorden.krefreshlayout.demo.util.DensityUtil;
import gorden.refresh.KRefreshHeader;
import gorden.refresh.KRefreshLayout;
/**
* document
* Created by Gordn on 2017/6/22.
*/
public class CircleHeader extends FrameLayout implements KRefreshHeader {
AnimationView mHeader;
private ValueAnimator mUpTopAnimator;
public CircleHeader(@NonNull Context context) {
super(context);
mHeader = new AnimationView(context);
LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, 0);
params.gravity = Gravity.TOP;
mHeader.setLayoutParams(params);
addView(mHeader);
mHeader.setAniBackColor(0xff8b90af);
mHeader.setAniForeColor(0xffffffff);
mHeader.setRadius(7);
mHeader.setOnViewAniDone(new AnimationView.OnViewAniDone() {
@Override
public void viewAniDone() {
mUpTopAnimator.start();
}
});
mUpTopAnimator = ValueAnimator.ofFloat(refreshHeight(), 0);
mUpTopAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float val = (float) animation.getAnimatedValue();
mHeader.getLayoutParams().height = (int) val;
mHeader.requestLayout();
}
});
mUpTopAnimator.setDuration(200);
}
@Override
public long succeedRetention() {
return 1000;
}
@Override
public long failingRetention() {
return 0;
}
@Override
public int refreshHeight() {
return DensityUtil.dip2px(100);
}
@Override
public int maxOffsetHeight() {
return DensityUtil.dip2px(150);
}
@Override
public void onReset(@NotNull KRefreshLayout refreshLayout) {
}
@Override
public void onPrepare(@NotNull KRefreshLayout refreshLayout) {
}
@Override
public void onRefresh(@NotNull KRefreshLayout refreshLayout) {
mHeader.releaseDrag();
}
@Override
public void onComplete(@NotNull KRefreshLayout refreshLayout, boolean isSuccess) {
mHeader.setRefreshing(false);
}
@Override
public void onScroll(@NotNull KRefreshLayout refreshLayout, int distance, float percent, boolean refreshing) {
if (!refreshing){
mHeader.getLayoutParams().height = distance;
mHeader.requestLayout();
}
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/fungame/BattleCityView.java
================================================
package gorden.krefreshlayout.demo.header.fungame;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.SparseArray;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;
/**
* Created by Hitomis on 2016/3/09.
* email:196425254@qq.com
*/
public class BattleCityView extends FunGameView {
/**
* 轨道数量
*/
private static int TANK_ROW_NUM = 3;
/**
* 炮管尺寸所在tank尺寸的比率
*/
private static final float TANK_BARREL_RATIO = 1/3.f;
/**
* 默认子弹之间空隙间距
*/
private static final int DEFAULT_BULLET_NUM_SPACING = 360;
/**
* 默认敌方坦克之间间距
*/
private static final int DEFAULT_ENEMY_TANK_NUM_SPACING = 60;
/**
* 表示运行漏掉的敌方坦克总数量 和 升级后消灭坦克总数量的增量
*/
private static final int DEFAULT_TANK_MAGIC_TOTAL_NUM = 8;
/**
* 所有轨道上敌方坦克矩阵集合
*/
private SparseArray<Queue<RectF>> eTankSparseArray;
/**
* 屏幕上所有子弹坐标点集合
*/
private Queue<Point> mBulletList;
/**
* 击中敌方坦克的子弹坐标点
*/
private Point usedBullet;
/**
* 用于随机定位一个轨道下标值
*/
private Random random;
/**
* 子弹半径
*/
private float bulletRadius;
/**
* 敌方坦克间距、子弹间距
*/
private int enemyTankSpace, bulletSpace;
/**
* 炮筒尺寸
*/
private int barrelSize;
/**
* 敌方坦克速度、子弹速度
*/
private int enemySpeed = 2, bulletSpeed = 7;
/**
* 当前前一辆敌方坦克和后一辆已经存在的间距值
* 用于确定是否要派出新的一辆敌方坦克
*/
private int offsetETankX;
/**
* 当前前一颗子弹和后一颗子弹的间距值
* 用于确定是否要发射新的一颗子弹
*/
private int offsetMBulletX;
/**
* 当前漏掉的坦克数量
*/
private int overstepNum;
/**
* 当前难度等级需要消灭坦克数量
*/
private int levelNum;
/**
* 当前难度等级内消灭的敌方坦克数量
*/
private int wipeOutNum;
/**
* 表示第一次标示值,用于添加第一辆敌方坦克逻辑
*/
private boolean once = true;
public BattleCityView(Context context) {
this(context, null);
}
public BattleCityView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BattleCityView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void initConcreteView() {
random = new Random();
controllerSize = (int) (Math.floor((screenHeight * VIEW_HEIGHT_RATIO - (TANK_ROW_NUM + 1) * DIVIDING_LINE_SIZE) / TANK_ROW_NUM + .5f));
barrelSize = (int) Math.floor(controllerSize * TANK_BARREL_RATIO + .5f);
bulletRadius = (barrelSize - 2 * DIVIDING_LINE_SIZE) * .5f;
resetConfigParams();
}
@Override
protected void drawGame(Canvas canvas) {
drawSelfTank(canvas);
if (status == STATUS_GAME_PLAY || status == STATUS_GAME_FINISHED) {
drawEnemyTank(canvas);
makeBulletPath(canvas);
}
}
@Override
protected void resetConfigParams() {
controllerPosition = DIVIDING_LINE_SIZE;
status = FunGameView.STATUS_GAME_PREPAR;
enemySpeed = 2;
bulletSpeed = 7;
levelNum = DEFAULT_TANK_MAGIC_TOTAL_NUM;
wipeOutNum = 0;
once = true;
enemyTankSpace = controllerSize + barrelSize + DEFAULT_ENEMY_TANK_NUM_SPACING;
bulletSpace = DEFAULT_BULLET_NUM_SPACING;
eTankSparseArray = new SparseArray<>();
for (int i = 0; i < TANK_ROW_NUM; i++) {
Queue<RectF> rectFQueue = new LinkedList<>();
eTankSparseArray.put(i, rectFQueue);
}
mBulletList = new LinkedList<>();
}
/**
* 由index轨道下标从左边起始位置生成一个用于绘制敌方坦克的Rect
* @param index 轨道下标
* @return 敌方坦克矩阵
*/
private RectF generateEnemyTank(int index) {
float left = - (controllerSize + barrelSize);
float top = index * (controllerSize + DIVIDING_LINE_SIZE) + DIVIDING_LINE_SIZE;
return new RectF(left, top, left + barrelSize * 2.5f, top + controllerSize);
}
/**
* 绘制子弹路径
* @param canvas 默认画布
*/
private void makeBulletPath(Canvas canvas) {
mPaint.setColor(mModelColor);
offsetMBulletX += bulletSpeed;
if (offsetMBulletX / bulletSpace == 1) {
offsetMBulletX = 0;
}
if (offsetMBulletX == 0) {
Point bulletPoint = new Point();
bulletPoint.x = screenWidth - controllerSize - barrelSize;
bulletPoint.y = (int) (controllerPosition + controllerSize * .5f);
mBulletList.offer(bulletPoint);
}
boolean isOversetp = false;
for (Point point : mBulletList) {
if (checkWipeOutETank(point)) {
usedBullet = point;
continue;
}
if (point.x + bulletRadius <= 0) {
isOversetp = true;
}
drawBullet(canvas, point);
}
if (isOversetp) {
mBulletList.poll();
}
mBulletList.remove(usedBullet);
usedBullet = null;
}
/**
* 由Y坐标获取该坐标所在轨道的下标
* @param y 坐标Y值
* @return 轨道下标
*/
private int getTrackIndex(int y) {
int index = y / (getMeasuredHeight() / TANK_ROW_NUM);
index = index >= TANK_ROW_NUM ? TANK_ROW_NUM - 1 : index;
index = index < 0 ? 0 : index;
return index;
}
/**
* 判断是否消灭敌方坦克
* @param point 单签子弹坐标点
* @return 消灭:true, 反之:false
*/
private boolean checkWipeOutETank(Point point) {
boolean beHit = false;
int trackIndex = getTrackIndex(point.y);
RectF rectF = eTankSparseArray.get(trackIndex).peek();
if (rectF != null && rectF.contains(point.x, point.y)) { // 击中
if (++wipeOutNum == levelNum) {
upLevel();
}
eTankSparseArray.get(trackIndex).poll();
beHit = true;
}
return beHit;
}
/**
* 难度升级
*/
private void upLevel() {
levelNum += DEFAULT_TANK_MAGIC_TOTAL_NUM;
enemySpeed++;
bulletSpeed += 2;
wipeOutNum = 0;
if (enemyTankSpace > 12)
enemyTankSpace -= 12;
if (bulletSpace > 30)
bulletSpace -= 30;
}
/**
* 绘制子弹
* @param canvas 默认画布
* @param point 子弹圆心坐标点
*/
private void drawBullet(Canvas canvas, Point point) {
point.x -= bulletSpeed;
canvas.drawCircle(point.x, point.y, bulletRadius, mPaint);
}
/**
* 判断我方坦克是否与敌方坦克相撞
* @param index 轨道下标
* @param selfX 我方坦克所在坐标X值
* @param selfY 我方坦克矩阵的top 或者 bottom 值
* @return true:相撞,反之:false
*/
private boolean checkTankCrash(int index, float selfX, float selfY) {
boolean isCrash = false;
RectF rectF = eTankSparseArray.get(index).peek();
if (rectF != null && rectF.contains(selfX, selfY)) {
isCrash = true;
}
return isCrash;
}
/**
* 绘制我方坦克
* @param canvas 默认画布
*/
private void drawSelfTank(Canvas canvas) {
mPaint.setColor(rModelColor);
boolean isAboveCrash = checkTankCrash(getTrackIndex((int) controllerPosition),
screenWidth - controllerSize,
controllerPosition);
boolean isBelowCrash = checkTankCrash(getTrackIndex((int) (controllerPosition + controllerSize)),
screenWidth - controllerSize,
controllerPosition + controllerSize);
if (isAboveCrash || isBelowCrash) {
status = STATUS_GAME_OVER;
}
canvas.drawRect(screenWidth - controllerSize,
controllerPosition,
screenWidth,
controllerPosition + controllerSize,
mPaint);
canvas.drawRect(screenWidth - controllerSize - barrelSize,
controllerPosition + (controllerSize - barrelSize) * .5f,
screenWidth - controllerSize,
controllerPosition + (controllerSize - barrelSize) * .5f + barrelSize,
mPaint);
}
/**
* 绘制三条轨道上的敌方坦克
* @param canvas 默认画布
*/
private void drawEnemyTank(Canvas canvas) {
mPaint.setColor(lModelColor);
offsetETankX += enemySpeed;
if (offsetETankX / enemyTankSpace == 1 || once) {
offsetETankX = 0;
once = false;
}
boolean isOverstep = false;
int option = apperanceOption();
for (int i = 0; i < TANK_ROW_NUM; i++) {
Queue<RectF> rectFQueue = eTankSparseArray.get(i);
if (offsetETankX == 0 && i == option) {
rectFQueue.offer(generateEnemyTank(i));
}
for (RectF rectF : rectFQueue) {
if (rectF.left >= screenWidth) {
isOverstep = true;
if (++overstepNum >= DEFAULT_TANK_MAGIC_TOTAL_NUM) {
status = STATUS_GAME_OVER;
break;
}
continue;
}
drawTank(canvas, rectF);
}
if (status == STATUS_GAME_OVER) break;
if (isOverstep) {
rectFQueue.poll();
isOverstep = false;
}
}
invalidate();
}
/**
* 绘制一辆敌方坦克
* @param canvas 默认画布
* @param rectF 坦克矩阵
*/
private void drawTank(Canvas canvas, RectF rectF) {
rectF.set(rectF.left + enemySpeed, rectF.top, rectF.right + enemySpeed, rectF.bottom);
canvas.drawRect(rectF, mPaint);
float barrelTop = rectF.top + (controllerSize - barrelSize) * .5f;
canvas.drawRect(rectF.right, barrelTop, rectF.right + barrelSize, barrelTop + barrelSize, mPaint);
}
/**
* 随机定位一个轨道下标值
* @return 轨道下标
*/
private int apperanceOption() {
return random.nextInt(TANK_ROW_NUM);
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/fungame/FunGameFactory.java
================================================
package gorden.krefreshlayout.demo.header.fungame;
import android.content.Context;
import android.util.AttributeSet;
/**
* Created by Hitomis on 2016/3/10.
* email:196425254@qq.com
*/
public class FunGameFactory {
// Refused to use enum
static final int HITBLOCK = 0;
static final int BATTLECITY = 1;
static FunGameView createFunGameView(Context context, AttributeSet attributeSet, int type) {
FunGameView funGameView = null;
switch (type) {
case HITBLOCK:
funGameView = new HitBlockView(context, attributeSet);
break;
case BATTLECITY:
funGameView = new BattleCityView(context, attributeSet);
break;
default:
funGameView = new HitBlockView(context, attributeSet);
}
return funGameView;
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/fungame/FunGameHeader.java
================================================
package gorden.krefreshlayout.demo.header.fungame;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import org.jetbrains.annotations.NotNull;
import gorden.refresh.KRefreshHeader;
import gorden.refresh.KRefreshLayout;
/**
* Created by Hitomis on 2016/3/1.
*/
public class FunGameHeader extends FrameLayout implements KRefreshHeader {
private Context mContext;
private int headerType;
private FunGameView funGameView;
private RelativeLayout curtainReLayout, maskReLayout;
private TextView topMaskView, bottomMaskView;
private int halfHitBlockHeight;
private boolean isStart = false;
private String topMaskViewText = "Pull To Break Out!";
private String bottomMaskViewText = "Scrooll to move handle";
private String loadingText = "Loading...";
private String loadingFinishedText = "Loading Finished";
private String gameOverText = "Game Over";
private int topMaskTextSize = 16;
private int bottomMaskTextSize = 16;
public FunGameHeader(Context context) {
this(context, null);
}
public FunGameHeader(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FunGameHeader(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContext = context;
headerType = FunGameFactory.HITBLOCK;
initView(attrs);
}
private void initView(AttributeSet attrs) {
funGameView = FunGameFactory.createFunGameView(mContext, attrs, headerType);
setHeaderLodingStr(loadingText);
setHeaderLoadingFinishedStr(loadingFinishedText);
setHeaderGameOverStr(gameOverText);
funGameView.postStatus(FunGameView.STATUS_GAME_PREPAR);
addView(funGameView);
curtainReLayout = new RelativeLayout(mContext);
maskReLayout = new RelativeLayout(mContext);
maskReLayout.setBackgroundColor(Color.parseColor("#3A3A3A"));
topMaskView = createMaskTextView(topMaskViewText, topMaskTextSize, Gravity.BOTTOM);
bottomMaskView = createMaskTextView(bottomMaskViewText, bottomMaskTextSize, Gravity.TOP);
coverMaskView();
funGameView.getViewTreeObserver().addOnGlobalLayoutListener(new MeasureListener());
}
private TextView createMaskTextView(String text, int textSize, int gravity) {
TextView maskTextView = new TextView(mContext);
maskTextView.setTextColor(Color.BLACK);
maskTextView.setBackgroundColor(Color.WHITE);
maskTextView.setGravity(gravity | Gravity.CENTER_HORIZONTAL);
maskTextView.setTextSize(textSize);
maskTextView.setText(text);
return maskTextView;
}
private void coverMaskView() {
LayoutParams maskLp = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
maskLp.topMargin = (int) FunGameView.DIVIDING_LINE_SIZE;
maskLp.bottomMargin = (int) FunGameView.DIVIDING_LINE_SIZE;
addView(maskReLayout, maskLp);
addView(curtainReLayout, maskLp);
}
@Override
public long succeedRetention() {
return 200;
}
@Override
public long failingRetention() {
return 0;
}
@Override
public int refreshHeight() {
return getHeight();
}
@Override
public int maxOffsetHeight() {
return 2 * getHeight();
}
@Override
public void onReset(@NotNull KRefreshLayout refreshLayout) {
postEnd();
}
@Override
public void onPrepare(@NotNull KRefreshLayout refreshLayout) {
}
@Override
public void onRefresh(@NotNull KRefreshLayout refreshLayout) {
postStart();
}
@Override
public void onComplete(@NotNull KRefreshLayout refreshLayout, boolean isSuccess) {
postComplete();
}
@Override
public void onScroll(@NotNull KRefreshLayout refreshLayout, int distance, float percent, boolean refreshing) {
if (refreshing) {
moveRacket(distance - refreshHeight());
}
}
private class MeasureListener implements ViewTreeObserver.OnGlobalLayoutListener {
@Override
public void onGlobalLayout() {
halfHitBlockHeight = (int) ((funGameView.getHeight() - 2 * FunGameView.DIVIDING_LINE_SIZE) * .5f);
RelativeLayout.LayoutParams topRelayLayoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, halfHitBlockHeight);
RelativeLayout.LayoutParams bottomRelayLayoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, halfHitBlockHeight);
bottomRelayLayoutParams.topMargin = halfHitBlockHeight;
curtainReLayout.removeAllViews();
curtainReLayout.addView(topMaskView, 0, topRelayLayoutParams);
curtainReLayout.addView(bottomMaskView, 1, bottomRelayLayoutParams);
getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
}
private void doStart(long delay) {
ObjectAnimator topMaskAnimator = ObjectAnimator.ofFloat(topMaskView, "translationY", topMaskView.getTranslationY(), -halfHitBlockHeight);
ObjectAnimator bottomMaskAnimator = ObjectAnimator.ofFloat(bottomMaskView, "translationY", bottomMaskView.getTranslationY(), halfHitBlockHeight);
ObjectAnimator maskShadowAnimator = ObjectAnimator.ofFloat(maskReLayout, "alpha", maskReLayout.getAlpha(), 0);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(topMaskAnimator).with(bottomMaskAnimator).with(maskShadowAnimator);
animatorSet.setDuration(800);
animatorSet.setStartDelay(delay);
animatorSet.start();
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
topMaskView.setVisibility(View.GONE);
bottomMaskView.setVisibility(View.GONE);
maskReLayout.setVisibility(View.GONE);
funGameView.postStatus(FunGameView.STATUS_GAME_PLAY);
}
});
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int width = 0, height = 0;
int count = getChildCount();
for (int i = 0; i < count; i++) {
View childView = getChildAt(i);
measureChild(childView, widthMeasureSpec, heightMeasureSpec);
if (childView instanceof FunGameView) {
width = childView.getMeasuredWidth();
height = childView.getMeasuredHeight();
}
}
if (heightMode == MeasureSpec.UNSPECIFIED || heightMode == MeasureSpec.EXACTLY) {
widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public void postStart() {
if (!isStart) {
doStart(200);
isStart = true;
}
}
public void postEnd() {
isStart = false;
funGameView.postStatus(FunGameView.STATUS_GAME_PREPAR);
topMaskView.setTranslationY(topMaskView.getTranslationY() + halfHitBlockHeight);
bottomMaskView.setTranslationY(bottomMaskView.getTranslationY() - halfHitBlockHeight);
maskReLayout.setAlpha(1.f);
topMaskView.setVisibility(View.VISIBLE);
bottomMaskView.setVisibility(View.VISIBLE);
maskReLayout.setVisibility(View.VISIBLE);
}
public void postComplete() {
funGameView.postStatus(FunGameView.STATUS_GAME_FINISHED);
}
public void moveRacket(float distance) {
if (isStart)
funGameView.moveController(distance);
}
public void back2StartPoint(long duration) {
funGameView.moveController2StartPoint(duration);
}
public int getGameStatus() {
return funGameView.getCurrStatus();
}
public void setTopMaskViewText(String topMaskViewText) {
this.topMaskViewText = topMaskViewText;
topMaskView.setText(topMaskViewText);
}
public void setBottomMaskViewText(String bottomMaskViewText) {
this.bottomMaskViewText = bottomMaskViewText;
bottomMaskView.setText(bottomMaskViewText);
}
public void setHeaderLodingStr(String loadingStr) {
funGameView.setTextLoading(loadingStr);
}
public void setHeaderGameOverStr(String gameOverStr) {
funGameView.setTextGameOver(gameOverStr);
}
public void setHeaderLoadingFinishedStr(String loadingFinishedStr) {
funGameView.setTextLoadingFinished(loadingFinishedStr);
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/fungame/FunGameView.java
================================================
package gorden.krefreshlayout.demo.header.fungame;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.AccelerateDecelerateInterpolator;
/**
* Created by Hitomis on 2016/3/9.
* email:196425254@qq.com
*/
abstract class FunGameView extends View {
static final int STATUS_GAME_PREPAR = 0;
static final int STATUS_GAME_PLAY = 1;
static final int STATUS_GAME_OVER = 2;
static final int STATUS_GAME_FINISHED = 3;
/**
* 分割线默认宽度大小
*/
static final float DIVIDING_LINE_SIZE = 1.f;
/**
* 控件高度占屏幕高度比率
*/
static final float VIEW_HEIGHT_RATIO = .161f;
private String textGameOver;
private String textLoading;
private String textLoadingFinished;
protected Paint mPaint;
protected TextPaint textPaint;
protected float controllerPosition;
protected int controllerSize;
protected int screenWidth, screenHeight;
protected int status = STATUS_GAME_PREPAR;
protected int lModelColor, rModelColor, mModelColor;
public FunGameView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
lModelColor =Color.rgb(0, 0, 0);
mModelColor =Color.BLACK;
rModelColor =Color.parseColor("#A5A5A5");
initBaseTools();
initBaseConfigParams(context);
initConcreteView();
}
protected void initBaseTools() {
textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
textPaint.setColor(Color.parseColor("#C1C2C2"));
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setStrokeWidth(1.f);
}
protected void initBaseConfigParams(Context context) {
controllerPosition = DIVIDING_LINE_SIZE;
screenWidth = getScreenMetrics(context).widthPixels;
screenHeight = getScreenMetrics(context).heightPixels;
}
protected abstract void initConcreteView();
protected abstract void drawGame(Canvas canvas);
protected abstract void resetConfigParams();
/**
* 绘制分割线
* @param canvas 默认画布
*/
private void drawBoundary(Canvas canvas) {
mPaint.setColor(Color.parseColor("#606060"));
canvas.drawLine(0, 0, screenWidth, 0, mPaint);
canvas.drawLine(0, getMeasuredHeight(), screenWidth, getMeasuredHeight(), mPaint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(screenWidth, (int) (screenHeight * VIEW_HEIGHT_RATIO));
}
@Override
protected void onDraw(Canvas canvas) {
drawBoundary(canvas);
drawText(canvas);
drawGame(canvas);
}
/**
* 绘制文字内容
* @param canvas 默认画布
*/
private void drawText(Canvas canvas) {
switch (status) {
case STATUS_GAME_PREPAR:
case STATUS_GAME_PLAY:
textPaint.setTextSize(50);
promptText(canvas, textLoading);
break;
case STATUS_GAME_FINISHED:
textPaint.setTextSize(40);
promptText(canvas, textLoadingFinished);
break;
case STATUS_GAME_OVER:
textPaint.setTextSize(50);
promptText(canvas, textGameOver);
break;
}
}
/**
* 提示文字信息
* @param canvas 默认画布
* @param text 相关文字字符串
*/
private void promptText(Canvas canvas, String text) {
float textX = (canvas.getWidth() - textPaint.measureText(text)) * .5f;
float textY = canvas.getHeight() * .5f - (textPaint.ascent() + textPaint.descent()) * .5f;
canvas.drawText(text, textX, textY, textPaint);
}
/**
* 移动控制器(控制器对象为具体控件中的右边图像模型)
* @param distance 移动的距离
*/
public void moveController(float distance) {
float maxDistance = (getMeasuredHeight() - 2 * DIVIDING_LINE_SIZE - controllerSize);
if (distance > maxDistance) {
distance = maxDistance;
}
controllerPosition = distance;
postInvalidate();
}
/**
* 移动控制器到起点位置
* @param duration
*/
public void moveController2StartPoint(long duration) {
ValueAnimator moveAnimator = ValueAnimator.ofFloat(controllerPosition, DIVIDING_LINE_SIZE);
moveAnimator.setDuration(duration);
moveAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
moveAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
controllerPosition = Float.parseFloat(animation.getAnimatedValue().toString());
postInvalidate();
}
});
moveAnimator.start();
}
/**
* 更新当前控件状态
* @param status 状态码
*/
public void postStatus(int status) {
this.status = status;
if (status == STATUS_GAME_PREPAR) {
resetConfigParams();
}
postInvalidate();
}
/**
* 获取当前控件状态
* @return
*/
public int getCurrStatus() {
return status;
}
public String getTextGameOver() {
return textGameOver;
}
public void setTextGameOver(String textGameOver) {
this.textGameOver = textGameOver;
}
public String getTextLoading() {
return textLoading;
}
public void setTextLoading(String textLoading) {
this.textLoading = textLoading;
}
public String getTextLoadingFinished() {
return textLoadingFinished;
}
public void setTextLoadingFinished(String textLoadingFinished) {
this.textLoadingFinished = textLoadingFinished;
}
/**
* 获取屏幕尺寸
*
* @param context context
* @return 手机屏幕尺寸
*/
private DisplayMetrics getScreenMetrics(Context context) {
WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(dm);
return dm;
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/fungame/HitBlockView.java
================================================
package gorden.krefreshlayout.demo.header.fungame;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.util.AttributeSet;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Hitomis on 2016/2/29.
* email:196425254@qq.com
*/
public class HitBlockView extends FunGameView {
/**
* 默认矩形块竖向排列的数目
*/
private static final int BLOCK_VERTICAL_NUM = 5;
/**
* 默认矩形块横向排列的数目
*/
private static final int BLOCK_HORIZONTAL_NUM = 3;
/**
* 矩形块的高度占屏幕高度比率
*/
private static final float BLOCK_HEIGHT_RATIO = .03125f;
/**
* 矩形块的宽度占屏幕宽度比率
*/
private static final float BLOCK_WIDTH_RATIO = .01806f;
/**
* 挡板所在位置占屏幕宽度的比率
*/
private static final float RACKET_POSITION_RATIO = .8f;
/**
* 矩形块所在位置占屏幕宽度的比率
*/
private static final float BLOCK_POSITION_RATIO = .08f;
/**
* 小球默认其实弹射角度
*/
private static final int DEFAULT_ANGLE = 30;
/**
* 分割线默认宽度大小
*/
static final float DIVIDING_LINE_SIZE = 1.f;
/**
* 小球移动速度
*/
private static final int SPEED = 6;
/**
* 矩形砖块的高度、宽度
*/
private float blockHeight, blockWidth;
/**
* 小球半径
*/
private static final float BALL_RADIUS = 8.f;
private Paint blockPaint;
private float blockLeft, racketLeft;
private float cx, cy;
private List<Point> pointList;
private boolean isleft;
private int angle;
private int blockHorizontalNum;
private int speed;
public HitBlockView(Context context) {
this(context, null);
}
public HitBlockView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public HitBlockView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initAttrs(context, attrs);
}
private void initAttrs(Context context, AttributeSet attrs) {
blockHorizontalNum = BLOCK_HORIZONTAL_NUM;
speed = SPEED;
}
@Override
protected void initConcreteView() {
blockPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
blockPaint.setStyle(Paint.Style.FILL);
blockHeight = screenHeight * BLOCK_HEIGHT_RATIO;
blockWidth = screenWidth * BLOCK_WIDTH_RATIO;
blockLeft = screenWidth * BLOCK_POSITION_RATIO;
racketLeft = screenWidth * RACKET_POSITION_RATIO;
controllerSize = (int) (blockHeight * 1.6f);
}
@Override
protected void drawGame(Canvas canvas) {
drawColorBlock(canvas);
drawRacket(canvas);
if (status == STATUS_GAME_PLAY || status == STATUS_GAME_FINISHED)
makeBallPath(canvas);
}
@Override
protected void resetConfigParams() {
cx = racketLeft - 2 * BALL_RADIUS;
cy = (int) (getHeight() * .5f);
controllerPosition = DIVIDING_LINE_SIZE;
angle = DEFAULT_ANGLE;
isleft = true;
if (pointList == null) {
pointList = new ArrayList<>();
} else {
pointList.clear();
}
}
/**
* 绘制挡板
* @param canvas 默认画布
*/
private void drawRacket(Canvas canvas) {
mPaint.setColor(rModelColor);
canvas.drawRect(racketLeft, controllerPosition, racketLeft + blockWidth, controllerPosition + controllerSize, mPaint);
}
/**
* 绘制并处理小球运动的轨迹
* @param canvas 默认画布
*/
private void makeBallPath(Canvas canvas) {
mPaint.setColor(mModelColor);
if (cx <= blockLeft + blockHorizontalNum * blockWidth + (blockHorizontalNum - 1) * DIVIDING_LINE_SIZE + BALL_RADIUS) { // 小球进入到色块区域
if (checkTouchBlock(cx, cy)) { // 反弹回来
isleft = false;
}
}
if (cx <= blockLeft + BALL_RADIUS ) { // 小球穿过色块区域
isleft = false;
}
if (cx + BALL_RADIUS >= racketLeft && cx - BALL_RADIUS < racketLeft + blockWidth) { //小球当前坐标X值在挡板X值区域范围内
if (checkTouchRacket(cy)) { // 小球与挡板接触
if (pointList.size() == blockHorizontalNum * BLOCK_VERTICAL_NUM) { // 矩形块全部被消灭,游戏结束
status = STATUS_GAME_OVER;
return;
}
isleft = true;
}
} else if (cx > canvas.getWidth()) { // 小球超出挡板区域
status = STATUS_GAME_OVER;
}
if (cy <= BALL_RADIUS + DIVIDING_LINE_SIZE) { // 小球撞到上边界
angle = 180 - DEFAULT_ANGLE;
} else if (cy >= getMeasuredHeight() - BALL_RADIUS - DIVIDING_LINE_SIZE) { // 小球撞到下边界
angle = 180 + DEFAULT_ANGLE;
}
if (isleft) {
cx -= speed;
} else {
cx += speed;
}
cy -= (float) Math.tan(Math.toRadians(angle)) * speed;
canvas.drawCircle(cx, cy, BALL_RADIUS, mPaint);
invalidate();
}
/**
* 检查小球是否撞击到挡板
* @param y 小球当前坐标Y值
* @return 小球位于挡板Y值区域范围内:true,反之:false
*/
private boolean checkTouchRacket(float y) {
boolean flag = false;
float diffVal = y - controllerPosition;
if (diffVal >= 0 && diffVal <= controllerSize) { // 小球位于挡板Y值区域范围内
flag = true;
}
return flag;
}
/**
* 检查小球是否撞击到矩形块
* @param x 小球坐标X值
* @param y 小球坐标Y值
* @return 撞击到:true,反之:false
*/
private boolean checkTouchBlock(float x, float y) {
int columnX = (int) ((x - blockLeft - BALL_RADIUS - speed ) / blockWidth);
columnX = columnX == blockHorizontalNum ? columnX - 1 : columnX;
int rowY = (int) (y / blockHeight);
rowY = rowY == BLOCK_VERTICAL_NUM ? rowY - 1 : rowY;
Point p = new Point();
p.set(columnX, rowY);
boolean flag = false;
for (Point point : pointList) {
if (point.equals(p.x, p.y)) {
flag = true;
break;
}
}
if (!flag) {
pointList.add(p);
}
return !flag;
}
/**
* 绘制矩形色块
* @param canvas 默认画布
*/
private void drawColorBlock(Canvas canvas) {
float left, top;
int column, row, redCode, greenCode, blueCode;
for (int i = 0; i < blockHorizontalNum * BLOCK_VERTICAL_NUM; i++) {
row = i / blockHorizontalNum;
column = i % blockHorizontalNum;
boolean flag = false;
for (Point point : pointList) {
if (point.equals(column, row)) {
flag = true;
break;
}
}
if (flag) {
continue;
}
redCode = 255 - (255 - Color.red(lModelColor)) / (column + 1);
greenCode = 255 - (255 - Color.green(lModelColor)) / (column + 1);
blueCode = 255 - (255 - Color.blue(lModelColor)) / (column + 1);
blockPaint.setColor(Color.rgb(redCode, greenCode, blueCode));
left = blockLeft + column * (blockWidth + DIVIDING_LINE_SIZE);
top = DIVIDING_LINE_SIZE + row * (blockHeight + DIVIDING_LINE_SIZE);
canvas.drawRect(left, top, left + blockWidth, top + blockHeight, blockPaint);
}
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/materia/CircleImageView.java
================================================
package gorden.krefreshlayout.demo.header.materia;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RadialGradient;
import android.graphics.Shader;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.support.v4.view.ViewCompat;
import android.view.animation.Animation;
import android.widget.ImageView;
/**
* Private class created to work around issues with AnimationListeners being
* called before the animation is actually complete and support shadows on older
* platforms.
*
*/
public class CircleImageView extends ImageView {
private static final int KEY_SHADOW_COLOR = 0x1E000000;
private static final int FILL_SHADOW_COLOR = 0x3D000000;
// PX
private static final float X_OFFSET = 0f;
private static final float Y_OFFSET = 1.75f;
private static final float SHADOW_RADIUS = 3.5f;
private static final int SHADOW_ELEVATION = 4;
private Animation.AnimationListener mListener;
private int mShadowRadius;
public CircleImageView(Context context, int color, final float radius) {
super(context);
final float density = getContext().getResources().getDisplayMetrics().density;
final int diameter = (int) (radius * density * 2);
final int shadowYOffset = (int) (density * Y_OFFSET);
final int shadowXOffset = (int) (density * X_OFFSET);
mShadowRadius = (int) (density * SHADOW_RADIUS);
ShapeDrawable circle;
if (elevationSupported()) {
circle = new ShapeDrawable(new OvalShape());
ViewCompat.setElevation(this, SHADOW_ELEVATION * density);
} else {
OvalShape oval = new OvalShadow(mShadowRadius, diameter);
circle = new ShapeDrawable(oval);
ViewCompat.setLayerType(this, ViewCompat.LAYER_TYPE_SOFTWARE, circle.getPaint());
circle.getPaint().setShadowLayer(mShadowRadius, shadowXOffset, shadowYOffset,
KEY_SHADOW_COLOR);
final int padding = mShadowRadius;
// set padding so the inner image sits correctly within the shadow.
setPadding(padding, padding, padding, padding);
}
circle.getPaint().setColor(color);
setBackgroundDrawable(circle);
}
private boolean elevationSupported() {
return android.os.Build.VERSION.SDK_INT >= 21;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (!elevationSupported()) {
setMeasuredDimension(getMeasuredWidth() + mShadowRadius*2, getMeasuredHeight()
+ mShadowRadius*2);
}
}
public void setAnimationListener(Animation.AnimationListener listener) {
mListener = listener;
}
@Override
public void onAnimationStart() {
super.onAnimationStart();
if (mListener != null) {
mListener.onAnimationStart(getAnimation());
}
}
@Override
public void onAnimationEnd() {
super.onAnimationEnd();
if (mListener != null) {
mListener.onAnimationEnd(getAnimation());
}
}
/**
* Update the background color of the circle image view.
*
* @param colorRes Id of a color resource.
*/
public void setBackgroundColorRes(int colorRes) {
setBackgroundColor(getContext().getResources().getColor(colorRes));
}
@Override
public void setBackgroundColor(int color) {
if (getBackground() instanceof ShapeDrawable) {
((ShapeDrawable) getBackground()).getPaint().setColor(color);
}
}
private class OvalShadow extends OvalShape {
private RadialGradient mRadialGradient;
private Paint mShadowPaint;
private int mCircleDiameter;
public OvalShadow(int shadowRadius, int circleDiameter) {
super();
mShadowPaint = new Paint();
mShadowRadius = shadowRadius;
mCircleDiameter = circleDiameter;
mRadialGradient = new RadialGradient(mCircleDiameter / 2, mCircleDiameter / 2,
mShadowRadius, new int[] {
FILL_SHADOW_COLOR, Color.TRANSPARENT
}, null, Shader.TileMode.CLAMP);
mShadowPaint.setShader(mRadialGradient);
}
@Override
public void draw(Canvas canvas, Paint paint) {
final int viewWidth = CircleImageView.this.getWidth();
final int viewHeight = CircleImageView.this.getHeight();
canvas.drawCircle(viewWidth / 2, viewHeight / 2, (mCircleDiameter / 2 + mShadowRadius),
mShadowPaint);
canvas.drawCircle(viewWidth / 2, viewHeight / 2, (mCircleDiameter / 2), paint);
}
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/materia/MateriaProgressHeader.java
================================================
package gorden.krefreshlayout.demo.header.materia;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Color;
import android.support.annotation.ColorInt;
import android.support.annotation.ColorRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import org.jetbrains.annotations.NotNull;
import gorden.krefreshlayout.demo.R;
import gorden.refresh.KRefreshHeader;
import gorden.refresh.KRefreshLayout;
/**
* document
* Created by Gordn on 2017/6/20.
*/
public class MateriaProgressHeader extends FrameLayout implements KRefreshHeader {
private int mCircleWidth;
private int mCircleHeight;
private static final int CIRCLE_DIAMETER = 40;
private static final int CIRCLE_DIAMETER_LARGE = 56;
// Maps to ProgressBar.Large style
public static final int LARGE = MaterialProgressDrawable.LARGE;
// Maps to ProgressBar default style
public static final int DEFAULT = MaterialProgressDrawable.DEFAULT;
// Default background for the progress spinner
private static final int CIRCLE_BG_LIGHT = 0xFFFAFAFA;
// Default offset in dips from the top of the view to where the progress spinner should stop
private static final int DEFAULT_CIRCLE_TARGET = 64;
private static final float MAX_PROGRESS_ANGLE = .8f;
private static final int MAX_ALPHA = 255;
private static final int STARTING_PROGRESS_ALPHA = (int) (.3f * MAX_ALPHA);
private CircleImageView mCircleView;
private MaterialProgressDrawable mProgress;
public MateriaProgressHeader(@NonNull Context context) {
this(context, null);
}
public MateriaProgressHeader(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
final DisplayMetrics metrics = getResources().getDisplayMetrics();
mCircleWidth = (int) (CIRCLE_DIAMETER * metrics.density);
mCircleHeight = (int) (CIRCLE_DIAMETER * metrics.density);
createProgressView();
ViewCompat.setChildrenDrawingOrderEnabled(this, true);
setColorSchemeColors(getResources().getIntArray(R.array.refresh_color));
}
private void createProgressView() {
mCircleView = new CircleImageView(getContext(), CIRCLE_BG_LIGHT, CIRCLE_DIAMETER / 2);
mProgress = new MaterialProgressDrawable(getContext(), this);
mProgress.setBackgroundColor(CIRCLE_BG_LIGHT);
mCircleView.setImageDrawable(mProgress);
mCircleView.setVisibility(View.GONE);
LayoutParams params = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER);
mCircleView.setLayoutParams(params);
addView(mCircleView);
}
/**
* Set the background color of the progress spinner disc.
*
* @param color
*/
public void setProgressBackgroundColorSchemeColor(@ColorInt int color) {
mCircleView.setBackgroundColor(color);
mProgress.setBackgroundColor(color);
}
public void setColorSchemeResources(@ColorRes int... colorResIds) {
final Resources res = getResources();
int[] colorRes = new int[colorResIds.length];
for (int i = 0; i < colorResIds.length; i++) {
colorRes[i] = res.getColor(colorResIds[i]);
}
setColorSchemeColors(colorRes);
}
public void setColorSchemeColors(int... colors) {
mProgress.setColorSchemeColors(colors);
}
public void setSize(int size) {
if (size != MaterialProgressDrawable.LARGE && size != MaterialProgressDrawable.DEFAULT) {
return;
}
final DisplayMetrics metrics = getResources().getDisplayMetrics();
if (size == MaterialProgressDrawable.LARGE) {
mCircleHeight = mCircleWidth = (int) (CIRCLE_DIAMETER_LARGE * metrics.density);
} else {
mCircleHeight = mCircleWidth = (int) (CIRCLE_DIAMETER * metrics.density);
}
// force the bounds of the progress circle inside the circle view to
// update by setting it to null before updating its size and then
// re-setting it
mCircleView.setImageDrawable(null);
mProgress.updateSizes(size);
mCircleView.setImageDrawable(mProgress);
}
@Override
public long succeedRetention() {
return 200;
}
@Override
public long failingRetention() {
return 0;
}
@Override
public int refreshHeight() {
return getHeight();
}
@Override
public int maxOffsetHeight() {
return 2 * getHeight();
}
boolean isReset = true;
@Override
public void onReset(@NotNull KRefreshLayout refreshLayout) {
mCircleView.clearAnimation();
mCircleView.animate().cancel();
mProgress.stop();
mCircleView.setVisibility(View.GONE);
mCircleView.getBackground().setAlpha(MAX_ALPHA);
mProgress.setAlpha(MAX_ALPHA);
ViewCompat.setScaleX(mCircleView, 0);
ViewCompat.setScaleY(mCircleView, 0);
ViewCompat.setAlpha(mCircleView, 1);
isReset = true;
}
@Override
public void onPrepare(@NotNull KRefreshLayout refreshLayout) {
mProgress.setAlpha(STARTING_PROGRESS_ALPHA);
}
@Override
public void onRefresh(@NotNull KRefreshLayout refreshLayout) {
mCircleView.setVisibility(View.VISIBLE);
mCircleView.getBackground().setAlpha(MAX_ALPHA);
mProgress.setAlpha(MAX_ALPHA);
ViewCompat.setScaleX(mCircleView, 1f);
ViewCompat.setScaleY(mCircleView, 1f);
mProgress.setArrowScale(1f);
mProgress.start();
isReset = false;
}
@Override
public void onComplete(@NotNull KRefreshLayout refreshLayout, boolean isSuccess) {
mCircleView.animate().scaleX(0).scaleY(0).alpha(0).start();
}
@Override
public void onScroll(@NotNull KRefreshLayout refreshLayout, int distance, float percent, boolean refreshing) {
if (!refreshing && isReset) {
if (mCircleView.getVisibility() != View.VISIBLE) {
mCircleView.setVisibility(View.VISIBLE);
}
if (percent >= 1f) {
ViewCompat.setScaleX(mCircleView, 1f);
ViewCompat.setScaleY(mCircleView, 1f);
} else {
ViewCompat.setScaleX(mCircleView, percent);
ViewCompat.setScaleY(mCircleView, percent);
}
if (percent <= 1f) {
mProgress.setAlpha((int) (STARTING_PROGRESS_ALPHA + (MAX_ALPHA - STARTING_PROGRESS_ALPHA) * percent));
}
float adjustedPercent = (float) Math.max(percent - .4, 0) * 5 / 3;
float strokeStart = adjustedPercent * .8f;
mProgress.setStartEndTrim(0f, Math.min(MAX_PROGRESS_ANGLE, strokeStart));
mProgress.setArrowScale(Math.min(1f, adjustedPercent));
float rotation = (-0.25f + .4f * adjustedPercent) * .5f;
mProgress.setProgressRotation(rotation);
}
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/materia/MaterialProgressDrawable.java
================================================
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package gorden.krefreshlayout.demo.header.materia;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.Transformation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
/**
* Fancy progress indicator for Material theme.
*/
class MaterialProgressDrawable extends Drawable implements Animatable {
private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
static final Interpolator MATERIAL_INTERPOLATOR = new FastOutSlowInInterpolator();
private static final float FULL_ROTATION = 1080.0f;
@Retention(RetentionPolicy.SOURCE)
@IntDef({LARGE, DEFAULT})
public @interface ProgressDrawableSize {}
// Maps to ProgressBar.Large style
static final int LARGE = 0;
// Maps to ProgressBar default style
static final int DEFAULT = 1;
// Maps to ProgressBar default style
private static final int CIRCLE_DIAMETER = 40;
private static final float CENTER_RADIUS = 8.75f; //should add up to 10 when + stroke_width
private static final float STROKE_WIDTH = 2.5f;
// Maps to ProgressBar.Large style
private static final int CIRCLE_DIAMETER_LARGE = 56;
private static final float CENTER_RADIUS_LARGE = 12.5f;
private static final float STROKE_WIDTH_LARGE = 3f;
private static final int[] COLORS = new int[] {
Color.BLACK
};
/**
* The value in the linear interpolator for animating the drawable at which
* the color transition should start
*/
private static final float COLOR_START_DELAY_OFFSET = 0.75f;
private static final float END_TRIM_START_DELAY_OFFSET = 0.5f;
private static final float START_TRIM_DURATION_OFFSET = 0.5f;
/** The duration of a single progress spin in milliseconds. */
private static final int ANIMATION_DURATION = 1332;
/** The number of points in the progress "star". */
private static final float NUM_POINTS = 5f;
/** The list of animators operating on this drawable. */
private final ArrayList<Animation> mAnimators = new ArrayList<Animation>();
/** The indicator ring, used to manage animation state. */
private final Ring mRing;
/** Canvas rotation in degrees. */
private float mRotation;
/** Layout info for the arrowhead in dp */
private static final int ARROW_WIDTH = 10;
private static final int ARROW_HEIGHT = 5;
private static final float ARROW_OFFSET_ANGLE = 5;
/** Layout info for the arrowhead for the large spinner in dp */
private static final int ARROW_WIDTH_LARGE = 12;
private static final int ARROW_HEIGHT_LARGE = 6;
private static final float MAX_PROGRESS_ARC = .8f;
private Resources mResources;
private View mParent;
private Animation mAnimation;
float mRotationCount;
private double mWidth;
private double mHeight;
boolean mFinishing;
MaterialProgressDrawable(Context context, View parent) {
mParent = parent;
mResources = context.getResources();
mRing = new Ring(mCallback);
mRing.setColors(COLORS);
updateSizes(DEFAULT);
setupAnimators();
}
private void setSizeParameters(double progressCircleWidth, double progressCircleHeight,
double centerRadius, double strokeWidth, float arrowWidth, float arrowHeight) {
final Ring ring = mRing;
final DisplayMetrics metrics = mResources.getDisplayMetrics();
final float screenDensity = metrics.density;
mWidth = progressCircleWidth * screenDensity;
mHeight = progressCircleHeight * screenDensity;
ring.setStrokeWidth((float) strokeWidth * screenDensity);
ring.setCenterRadius(centerRadius * screenDensity);
ring.setColorIndex(0);
ring.setArrowDimensions(arrowWidth * screenDensity, arrowHeight * screenDensity);
ring.setInsets((int) mWidth, (int) mHeight);
}
/**
* Set the overall size for the progress spinner. This updates the radius
* and stroke width of the ring.
*
* @param size One of {@link MaterialProgressDrawable.LARGE} or
* {@link MaterialProgressDrawable.DEFAULT}
*/
public void updateSizes(@ProgressDrawableSize int size) {
if (size == LARGE) {
setSizeParameters(CIRCLE_DIAMETER_LARGE, CIRCLE_DIAMETER_LARGE, CENTER_RADIUS_LARGE,
STROKE_WIDTH_LARGE, ARROW_WIDTH_LARGE, ARROW_HEIGHT_LARGE);
} else {
setSizeParameters(CIRCLE_DIAMETER, CIRCLE_DIAMETER, CENTER_RADIUS, STROKE_WIDTH,
ARROW_WIDTH, ARROW_HEIGHT);
}
}
/**
* @param show Set to true to display the arrowhead on the progress spinner.
*/
public void showArrow(boolean show) {
mRing.setShowArrow(show);
}
/**
* @param scale Set the scale of the arrowhead for the spinner.
*/
public void setArrowScale(float scale) {
mRing.setArrowScale(scale);
}
/**
* Set the start and end trim for the progress spinner arc.
*
* @param startAngle start angle
* @param endAngle end angle
*/
public void setStartEndTrim(float startAngle, float endAngle) {
mRing.setStartTrim(startAngle);
mRing.setEndTrim(endAngle);
}
/**
* Set the amount of rotation to apply to the progress spinner.
*
* @param rotation Rotation is from [0..1]
*/
public void setProgressRotation(float rotation) {
mRing.setRotation(rotation);
}
/**
* Update the background color of the circle image view.
*/
public void setBackgroundColor(int color) {
mRing.setBackgroundColor(color);
}
/**
* Set the colors used in the progress animation from color resources.
* The first color will also be the color of the bar that grows in response
* to a user swipe gesture.
*
* @param colors
*/
public void setColorSchemeColors(int... colors) {
mRing.setColors(colors);
mRing.setColorIndex(0);
}
@Override
public int getIntrinsicHeight() {
return (int) mHeight;
}
@Override
public int getIntrinsicWidth() {
return (int) mWidth;
}
@Override
public void draw(Canvas c) {
final Rect bounds = getBounds();
final int saveCount = c.save();
c.rotate(mRotation, bounds.exactCenterX(), bounds.exactCenterY());
mRing.draw(c, bounds);
c.restoreToCount(saveCount);
}
@Override
public void setAlpha(int alpha) {
mRing.setAlpha(alpha);
}
public int getAlpha() {
return mRing.getAlpha();
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
mRing.setColorFilter(colorFilter);
}
@SuppressWarnings("unused")
void setRotation(float rotation) {
mRotation = rotation;
invalidateSelf();
}
@SuppressWarnings("unused")
private float getRotation() {
return mRotation;
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
public boolean isRunning() {
final ArrayList<Animation> animators = mAnimators;
final int N = animators.size();
for (int i = 0; i < N; i++) {
final Animation animator = animators.get(i);
if (animator.hasStarted() && !animator.hasEnded()) {
return true;
}
}
return false;
}
@Override
public void start() {
mAnimation.reset();
mRing.storeOriginals();
// Already showing some part of the ring
if (mRing.getEndTrim() != mRing.getStartTrim()) {
mFinishing = true;
mAnimation.setDuration(ANIMATION_DURATION / 2);
mParent.startAnimation(mAnimation);
} else {
mRing.setColorIndex(0);
mRing.resetOriginals();
mAnimation.setDuration(ANIMATION_DURATION);
mParent.startAnimation(mAnimation);
}
}
@Override
public void stop() {
mParent.clearAnimation();
setRotation(0);
mRing.setShowArrow(false);
mRing.setColorIndex(0);
mRing.resetOriginals();
}
float getMinProgressArc(Ring ring) {
return (float) Math.toRadians(
ring.getStrokeWidth() / (2 * Math.PI * ring.getCenterRadius()));
}
// Adapted from ArgbEvaluator.java
private int evaluateColorChange(float fraction, int startValue, int endValue) {
int startInt = (Integer) startValue;
int startA = (startInt >> 24) & 0xff;
int startR = (startInt >> 16) & 0xff;
int startG = (startInt >> 8) & 0xff;
int startB = startInt & 0xff;
int endInt = (Integer) endValue;
int endA = (endInt >> 24) & 0xff;
int endR = (endInt >> 16) & 0xff;
int endG = (endInt >> 8) & 0xff;
int endB = endInt & 0xff;
return (int) ((startA + (int) (fraction * (endA - startA))) << 24)
| (int) ((startR + (int) (fraction * (endR - startR))) << 16)
| (int) ((startG + (int) (fraction * (endG - startG))) << 8)
| (int) ((startB + (int) (fraction * (endB - startB))));
}
/**
* Update the ring color if this is within the last 25% of the animation.
* The new ring color will be a translation from the starting ring color to
* the next color.
*/
void updateRingColor(float interpolatedTime, Ring ring) {
if (interpolatedTime > COLOR_START_DELAY_OFFSET) {
// scale the interpolatedTime so that the full
// transformation from 0 - 1 takes place in the
// remaining time
ring.setColor(evaluateColorChange((interpolatedTime - COLOR_START_DELAY_OFFSET)
/ (1.0f - COLOR_START_DELAY_OFFSET), ring.getStartingColor(),
ring.getNextColor()));
}
}
void applyFinishTranslation(float interpolatedTime, Ring ring) {
// shrink back down and complete a full rotation before
// starting other circles
// Rotation goes between [0..1].
updateRingColor(interpolatedTime, ring);
float targetRotation = (float) (Math.floor(ring.getStartingRotation() / MAX_PROGRESS_ARC)
+ 1f);
final float minProgressArc = getMinProgressArc(ring);
final float startTrim = ring.getStartingStartTrim()
+ (ring.getStartingEndTrim() - minProgressArc - ring.getStartingStartTrim())
* interpolatedTime;
ring.setStartTrim(startTrim);
ring.setEndTrim(ring.getStartingEndTrim());
final float rotation = ring.getStartingRotation()
+ ((targetRotation - ring.getStartingRotation()) * interpolatedTime);
ring.setRotation(rotation);
}
private void setupAnimators() {
final Ring ring = mRing;
final Animation animation = new Animation() {
@Override
public void applyTransformation(float interpolatedTime, Transformation t) {
if (mFinishing) {
applyFinishTranslation(interpolatedTime, ring);
} else {
// The minProgressArc is calculated from 0 to create an
// angle that matches the stroke width.
final float minProgressArc = getMinProgressArc(ring);
final float startingEndTrim = ring.getStartingEndTrim();
final float startingTrim = ring.getStartingStartTrim();
final float startingRotation = ring.getStartingRotation();
updateRingColor(interpolatedTime, ring);
// Moving the start trim only occurs in the first 50% of a
// single ring animation
if (interpolatedTime <= START_TRIM_DURATION_OFFSET) {
// scale the interpolatedTime so that the full
// transformation from 0 - 1 takes place in the
// remaining time
final float scaledTime = (interpolatedTime)
/ (1.0f - START_TRIM_DURATION_OFFSET);
final float startTrim = startingTrim
+ ((MAX_PROGRESS_ARC - minProgressArc) * MATERIAL_INTERPOLATOR
.getInterpolation(scaledTime));
ring.setStartTrim(startTrim);
}
// Moving the end trim starts after 50% of a single ring
// animation completes
if (interpolatedTime > END_TRIM_START_DELAY_OFFSET) {
// scale the interpolatedTime so that the full
// transformation from 0 - 1 takes place in the
// remaining time
final float minArc = MAX_PROGRESS_ARC - minProgressArc;
float scaledTime = (interpolatedTime - START_TRIM_DURATION_OFFSET)
/ (1.0f - START_TRIM_DURATION_OFFSET);
final float endTrim = startingEndTrim
+ (minArc * MATERIAL_INTERPOLATOR.getInterpolation(scaledTime));
ring.setEndTrim(endTrim);
}
final float rotation = startingRotation + (0.25f * interpolatedTime);
ring.setRotation(rotation);
float groupRotation = ((FULL_ROTATION / NUM_POINTS) * interpolatedTime)
+ (FULL_ROTATION * (mRotationCount / NUM_POINTS));
setRotation(groupRotation);
}
}
};
animation.setRepeatCount(Animation.INFINITE);
animation.setRepeatMode(Animation.RESTART);
animation.setInterpolator(LINEAR_INTERPOLATOR);
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
mRotationCount = 0;
}
@Override
public void onAnimationEnd(Animation animation) {
// do nothing
}
@Override
public void onAnimationRepeat(Animation animation) {
ring.storeOriginals();
ring.goToNextColor();
ring.setStartTrim(ring.getEndTrim());
if (mFinishing) {
// finished closing the last ring from the swipe gesture; go
// into progress mode
mFinishing = false;
animation.setDuration(ANIMATION_DURATION);
ring.setShowArrow(false);
} else {
mRotationCount = (mRotationCount + 1) % (NUM_POINTS);
}
}
});
mAnimation = animation;
}
private final Callback mCallback = new Callback() {
@Override
public void invalidateDrawable(Drawable d) {
invalidateSelf();
}
@Override
public void scheduleDrawable(Drawable d, Runnable what, long when) {
scheduleSelf(what, when);
}
@Override
public void unscheduleDrawable(Drawable d, Runnable what) {
unscheduleSelf(what);
}
};
private static class Ring {
private final RectF mTempBounds = new RectF();
private final Paint mPaint = new Paint();
private final Paint mArrowPaint = new Paint();
private final Callback mCallback;
private float mStartTrim = 0.0f;
private float mEndTrim = 0.0f;
private float mRotation = 0.0f;
private float mStrokeWidth = 5.0f;
private float mStrokeInset = 2.5f;
private int[] mColors;
// mColorIndex represents the offset into the available mColors that the
// progress circle should currently display. As the progress circle is
// animating, the mColorIndex moves by one to the next available color.
private int mColorIndex;
private float mStartingStartTrim;
private float mStartingEndTrim;
private float mStartingRotation;
private boolean mShowArrow;
private Path mArrow;
private float mArrowScale;
private double mRingCenterRadius;
private int mArrowWidth;
private int mArrowHeight;
private int mAlpha;
private final Paint mCirclePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private int mBackgroundColor;
private int mCurrentColor;
Ring(Callback callback) {
mCallback = callback;
mPaint.setStrokeCap(Paint.Cap.SQUARE);
mPaint.setAntiAlias(true);
mPaint.setStyle(Style.STROKE);
mArrowPaint.setStyle(Style.FILL);
mArrowPaint.setAntiAlias(true);
}
public void setBackgroundColor(int color) {
mBackgroundColor = color;
}
/**
* Set the dimensions of the arrowhead.
*
* @param width Width of the hypotenuse of the arrow head
* @param height Height of the arrow point
*/
public void setArrowDimensions(float width, float height) {
mArrowWidth = (int) width;
mArrowHeight = (int) height;
}
/**
* Draw the progress spinner
*/
public void draw(Canvas c, Rect bounds) {
final RectF arcBounds = mTempBounds;
arcBounds.set(bounds);
arcBounds.inset(mStrokeInset, mStrokeInset);
final float startAngle = (mStartTrim + mRotation) * 360;
final float endAngle = (mEndTrim + mRotation) * 360;
float sweepAngle = endAngle - startAngle;
mPaint.setColor(mCurrentColor);
c.drawArc(arcBounds, startAngle, sweepAngle, false, mPaint);
drawTriangle(c, startAngle, sweepAngle, bounds);
if (mAlpha < 255) {
mCirclePaint.setColor(mBackgroundColor);
mCirclePaint.setAlpha(255 - mAlpha);
c.drawCircle(bounds.exactCenterX(), bounds.exactCenterY(), bounds.width() / 2,
mCirclePaint);
}
}
private void drawTriangle(Canvas c, float startAngle, float sweepAngle, Rect bounds) {
if (mShowArrow) {
if (mArrow == null) {
mArrow = new Path();
mArrow.setFillType(Path.FillType.EVEN_ODD);
} else {
mArrow.reset();
}
// Adjust the position of the triangle so that it is inset as
// much as the arc, but also centered on the arc.
float inset = (int) mStrokeInset / 2 * mArrowScale;
float x = (float) (mRingCenterRadius * Math.cos(0) + bounds.exactCenterX());
float y = (float) (mRingCenterRadius * Math.sin(0) + bounds.exactCenterY());
// Update the path each time. This works around an issue in SKIA
// where concatenating a rotation matrix to a scale matrix
// ignored a starting negative rotation. This appears to have
// been fixed as of API 21.
mArrow.moveTo(0, 0);
mArrow.lineTo(mArrowWidth * mArrowScale, 0);
mArrow.lineTo((mArrowWidth * mArrowScale / 2), (mArrowHeight
* mArrowScale));
mArrow.offset(x - inset, y);
mArrow.close();
// draw a triangle
mArrowPaint.setColor(mCurrentColor);
c.rotate(startAngle + sweepAngle - ARROW_OFFSET_ANGLE, bounds.exactCenterX(),
bounds.exactCenterY());
c.drawPath(mArrow, mArrowPaint);
}
}
/**
* Set the colors the progress spinner alternates between.
*
* @param colors Array of integers describing the colors. Must be non-<code>null</code>.
*/
public void setColors(@NonNull int[] colors) {
mColors = colors;
// if colors are reset, make sure to reset the color index as well
setColorIndex(0);
}
/**
* Set the absolute color of the progress spinner. This is should only
* be used when animating between current and next color when the
* spinner is rotating.
*
* @param color int describing the color.
*/
public void setColor(int color) {
mCurrentColor = color;
}
/**
* @param index Index into the color array of the color to display in
* the progress spinner.
*/
public void setColorIndex(int index) {
mColorIndex = index;
mCurrentColor = mColors[mColorIndex];
}
/**
* @return int describing the next color the progress spinner should use when drawing.
*/
public int getNextColor() {
return mColors[getNextColorIndex()];
}
private int getNextColorIndex() {
return (mColorIndex + 1) % (mColors.length);
}
/**
* Proceed to the next available ring color. This will automatically
* wrap back to the beginning of colors.
*/
public void goToNextColor() {
setColorIndex(getNextColorIndex());
}
public void setColorFilter(ColorFilter filter) {
mPaint.setColorFilter(filter);
invalidateSelf();
}
/**
* @param alpha Set the alpha of the progress spinner and associated arrowhead.
*/
public void setAlpha(int alpha) {
mAlpha = alpha;
}
/**
* @return Current alpha of the progress spinner and arrowhead.
*/
public int getAlpha() {
return mAlpha;
}
/**
* @param strokeWidth Set the stroke width of the progress spinner in pixels.
*/
public void setStrokeWidth(float strokeWidth) {
mStrokeWidth = strokeWidth;
mPaint.setStrokeWidth(strokeWidth);
invalidateSelf();
}
@SuppressWarnings("unused")
public float getStrokeWidth() {
return mStrokeWidth;
}
@SuppressWarnings("unused")
public void setStartTrim(float startTrim) {
mStartTrim = startTrim;
invalidateSelf();
}
@SuppressWarnings("unused")
public float getStartTrim() {
return mStartTrim;
}
public float getStartingStartTrim() {
return mStartingStartTrim;
}
public float getStartingEndTrim() {
return mStartingEndTrim;
}
public int getStartingColor() {
return mColors[mColorIndex];
}
@SuppressWarnings("unused")
public void setEndTrim(float endTrim) {
mEndTrim = endTrim;
invalidateSelf();
}
@SuppressWarnings("unused")
public float getEndTrim() {
return mEndTrim;
}
@SuppressWarnings("unused")
public void setRotation(float rotation) {
mRotation = rotation;
invalidateSelf();
}
@SuppressWarnings("unused")
public float getRotation() {
return mRotation;
}
public void setInsets(int width, int height) {
final float minEdge = (float) Math.min(width, height);
float insets;
if (mRingCenterRadius <= 0 || minEdge < 0) {
insets = (float) Math.ceil(mStrokeWidth / 2.0f);
} else {
insets = (float) (minEdge / 2.0f - mRingCenterRadius);
}
mStrokeInset = insets;
}
@SuppressWarnings("unused")
public float getInsets() {
return mStrokeInset;
}
/**
* @param centerRadius Inner radius in px of the circle the progress
* spinner arc traces.
*/
public void setCenterRadius(double centerRadius) {
mRingCenterRadius = centerRadius;
}
public double getCenterRadius() {
return mRingCenterRadius;
}
/**
* @param show Set to true to show the arrow head on the progress spinner.
*/
public void setShowArrow(boolean show) {
if (mShowArrow != show) {
mShowArrow = show;
invalidateSelf();
}
}
/**
* @param scale Set the scale of the arrowhead for the spinner.
*/
public void setArrowScale(float scale) {
if (scale != mArrowScale) {
mArrowScale = scale;
invalidateSelf();
}
}
/**
* @return The amount the progress spinner is currently rotated, between [0..1].
*/
public float getStartingRotation() {
return mStartingRotation;
}
/**
* If the start / end trim are offset to begin with, store them so that
* animation starts from that offset.
*/
public void storeOriginals() {
mStartingStartTrim = mStartTrim;
mStartingEndTrim = mEndTrim;
mStartingRotation = mRotation;
}
/**
* Reset the progress spinner to default rotation, start and end angles.
*/
public void resetOriginals() {
mStartingStartTrim = 0;
mStartingEndTrim = 0;
mStartingRotation = 0;
setStartTrim(0);
setEndTrim(0);
setRotation(0);
}
private void invalidateSelf() {
mCallback.invalidateDrawable(null);
}
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/rentals/RentalsSunDrawable.java
================================================
package gorden.krefreshlayout.demo.header.rentals;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.PixelFormat;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.view.animation.Transformation;
import gorden.krefreshlayout.demo.R;
import gorden.krefreshlayout.demo.util.DensityUtil;
public class RentalsSunDrawable extends Drawable implements Animatable {
private static final float SCALE_START_PERCENT = 0.3f;
private static final int ANIMATION_DURATION = 1000;
private final static float SKY_RATIO = 0.65f;
private static final float SKY_INITIAL_SCALE = 1.05f;
private final static float TOWN_RATIO = 0.22f;
private static final float TOWN_INITIAL_SCALE = 1.20f;
private static final float TOWN_FINAL_SCALE = 1.30f;
private static final float SUN_FINAL_SCALE = 0.75f;
private static final float SUN_INITIAL_ROTATE_GROWTH = 1.2f;
private static final float SUN_FINAL_ROTATE_GROWTH = 1.5f;
private static final Interpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
private View mParent;
private Matrix mMatrix;
private Animation mAnimation;
private int mTop;
private int mScreenWidth;
private int mSkyHeight;
private float mSkyTopOffset;
private float mSkyMoveOffset;
private int mTownHeight;
private float mTownInitialTopOffset;
private float mTownFinalTopOffset;
private float mTownMoveOffset;
private int mSunSize = 100;
private float mSunLeftOffset;
private float mSunTopOffset;
private float mPercent = 0.0f;
private float mRotate = 0.0f;
private Bitmap mSky;
private Bitmap mSun;
private Bitmap mTown;
private boolean isRefreshing = false;
private Context mContext;
private int mTotalDragDistance;
public RentalsSunDrawable(Context context, View parent) {
mContext = context;
mParent = parent;
mMatrix = new Matrix();
initiateDimens();
createBitmaps();
setupAnimations();
}
private Context getContext() {
return mContext;
}
private void initiateDimens() {
DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
mTotalDragDistance = DensityUtil.dip2px(120);
mScreenWidth = getContext().getResources().getDisplayMetrics().widthPixels;
mSkyHeight = (int) (SKY_RATIO * mScreenWidth);
mSkyTopOffset = -(mSkyHeight * 0.28f);
mSkyMoveOffset = DensityUtil.dip2px(15);
mTownHeight = (int) (TOWN_RATIO * mScreenWidth);
mTownInitialTopOffset = (mTotalDragDistance - mTownHeight * TOWN_INITIAL_SCALE) + mTotalDragDistance * .42f;
mTownFinalTopOffset = (mTotalDragDistance - mTownHeight * TOWN_FINAL_SCALE) + mTotalDragDistance * .42f;
mTownMoveOffset = DensityUtil.dip2px(10);
mSunLeftOffset = 0.3f * (float) mScreenWidth;
mSunTopOffset = (mTotalDragDistance * 0.5f);
mTop = 0;
}
private void createBitmaps() {
mSky = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.sky);
mSky = Bitmap.createScaledBitmap(mSky, mScreenWidth, mSkyHeight, true);
mTown = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.buildings);
mTown = Bitmap.createScaledBitmap(mTown, mScreenWidth, (int) (mScreenWidth * TOWN_RATIO), true);
mSun = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.sun);
mSun = Bitmap.createScaledBitmap(mSun, mSunSize, mSunSize, true);
}
public void offsetTopAndBottom(int offset) {
mTop = offset;
invalidateSelf();
}
@Override
public void draw(Canvas canvas) {
final int saveCount = canvas.save();
canvas.translate(0, mTotalDragDistance - mTop);
drawSky(canvas);
drawSun(canvas);
drawTown(canvas);
canvas.restoreToCount(saveCount);
}
private void drawSky(Canvas canvas) {
Matrix matrix = mMatrix;
matrix.reset();
int y = Math.max(0, mTop - mTotalDragDistance);
// 0 ~ 1
float dragPercent = Math.min(1f, Math.abs(mPercent));
/** Change skyScale between {@link #SKY_INITIAL_SCALE} and 1.0f depending on {@link #mPercent} */
float skyScale;
float scalePercentDelta = dragPercent - SCALE_START_PERCENT;
/** less than {@link SCALE_START_PERCENT} will be {@link SKY_INITIAL_SCALE} */
if (scalePercentDelta > 0) {
/** will change from 0 ~ 1 **/
float scalePercent = scalePercentDelta / (1.0f - SCALE_START_PERCENT);
skyScale = SKY_INITIAL_SCALE - (SKY_INITIAL_SCALE - 1.0f) * scalePercent;
} else {
skyScale = SKY_INITIAL_SCALE;
}
float offsetX = -(mScreenWidth * skyScale - mScreenWidth) / 2.0f;
float offsetY = y + 50 + mSkyTopOffset // Offset canvas moving, goes lower when goes down
- mSkyHeight * (skyScale - 1.0f) / 2 // Offset sky scaling, lower than 0, will go greater when goes down
+ mSkyMoveOffset * dragPercent; // Give it a little move top -> bottom // will go greater when goes down
matrix.postScale(skyScale, skyScale);
matrix.postTranslate(offsetX, offsetY);
canvas.drawBitmap(mSky, matrix, null);
}
private void drawTown(Canvas canvas) {
Matrix matrix = mMatrix;
matrix.reset();
int y = Math.max(0, mTop - mTotalDragDistance);
float dragPercent = Math.min(1f, Math.abs(mPercent));
float townScale;
float townTopOffset;
float townMoveOffset;
float scalePercentDelta = dragPercent - SCALE_START_PERCENT;
if (scalePercentDelta > 0) {
/**
* Change townScale between {@link #TOWN_INITIAL_SCALE} and {@link #TOWN_FINAL_SCALE} depending on {@link #mPercent}
* Change townTopOffset between {@link #mTownInitialTopOffset} and {@link #mTownFinalTopOffset} depending on {@link #mPercent}
*/
float scalePercent = scalePercentDelta / (1.0f - SCALE_START_PERCENT);
townScale = TOWN_INITIAL_SCALE + (TOWN_FINAL_SCALE - TOWN_INITIAL_SCALE) * scalePercent;
townTopOffset = mTownInitialTopOffset - (mTownFinalTopOffset - mTownInitialTopOffset) * scalePercent;
townMoveOffset = mTownMoveOffset * (1.0f - scalePercent);
} else {
float scalePercent = dragPercent / SCALE_START_PERCENT;
townScale = TOWN_INITIAL_SCALE;
townTopOffset = mTownInitialTopOffset;
townMoveOffset = mTownMoveOffset * scalePercent;
}
float offsetX = -(mScreenWidth * townScale - mScreenWidth) / 2.0f;
// float offsetY = (1.0f - dragPercent) * mTotalDragDistance // Offset canvas moving
float offsetY = y +
+townTopOffset
- mTownHeight * (townScale - 1.0f) / 2 // Offset town scaling
+ townMoveOffset; // Give it a little move
matrix.postScale(townScale, townScale);
matrix.postTranslate(offsetX, offsetY);
canvas.drawBitmap(mTown, matrix, null);
}
private void drawSun(Canvas canvas) {
Matrix matrix = mMatrix;
matrix.reset();
float dragPercent = mPercent;
if (dragPercent > 1.0f) { // Slow down if pulling over set height
dragPercent = (dragPercent + 9.0f) / 10;
}
float sunRadius = (float) mSunSize / 2.0f;
float sunRotateGrowth = SUN_INITIAL_ROTATE_GROWTH;
float offsetX = mSunLeftOffset;
float offsetY = mSunTopOffset
+ (mTotalDragDistance / 2) * (1.0f - dragPercent); // Move the sun up
float scalePercentDelta = dragPercent - SCALE_START_PERCENT;
if (scalePercentDelta > 0) {
float scalePercent = scalePercentDelta / (1.0f - SCALE_START_PERCENT);
float sunScale = 1.0f - (1.0f - SUN_FINAL_SCALE) * scalePercent;
sunRotateGrowth += (SUN_FINAL_ROTATE_GROWTH - SUN_INITIAL_ROTATE_GROWTH) * scalePercent;
matrix.preTranslate(offsetX + (sunRadius - sunRadius * sunScale), offsetY * (2.0f - sunScale));
matrix.preScale(sunScale, sunScale);
offsetX += sunRadius;
offsetY = offsetY * (2.0f - sunScale) + sunRadius * sunScale;
} else {
matrix.postTranslate(offsetX, offsetY);
offsetX += sunRadius;
offsetY += sunRadius;
}
float r = (isRefreshing ? -360 : 360) * mRotate * (isRefreshing ? 1 : sunRotateGrowth);
matrix.postRotate(r, offsetX, offsetY);
canvas.drawBitmap(mSun, matrix, null);
}
public void setPercent(float percent) {
mPercent = percent;
setRotate(percent);
}
public void setRotate(float rotate) {
mRotate = rotate;
mParent.invalidate();
invalidateSelf();
}
public void resetOriginals() {
setPercent(0);
setRotate(0);
}
@Override
public void setBounds(int left, int top, int right, int bottom) {
super.setBounds(left, top, right, mSkyHeight + top);
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
public boolean isRunning() {
return false;
}
@Override
public void start() {
mAnimation.reset();
isRefreshing = true;
mParent.startAnimation(mAnimation);
}
@Override
public void stop() {
mParent.clearAnimation();
isRefreshing = false;
resetOriginals();
}
private void setupAnimations() {
mAnimation = new Animation() {
@Override
public void applyTransformation(float interpolatedTime, Transformation t) {
setRotate(interpolatedTime);
}
};
mAnimation.setRepeatCount(Animation.INFINITE);
mAnimation.setRepeatMode(Animation.RESTART);
mAnimation.setInterpolator(LINEAR_INTERPOLATOR);
mAnimation.setDuration(ANIMATION_DURATION);
}
public int getTotalDragDistance() {
return mTotalDragDistance;
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/rentals/RentalsSunHeaderView.java
================================================
package gorden.krefreshlayout.demo.header.rentals;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import org.jetbrains.annotations.NotNull;
import gorden.krefreshlayout.demo.util.DensityUtil;
import gorden.refresh.KRefreshHeader;
import gorden.refresh.KRefreshLayout;
/*
* 一个经典的太阳升起刷新Header
*/
public class RentalsSunHeaderView extends View implements KRefreshHeader {
private RentalsSunDrawable mDrawable;
private float mPercent;
private int mDistance;
public RentalsSunHeaderView(Context context) {
super(context);
init();
}
public RentalsSunHeaderView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public RentalsSunHeaderView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mDrawable = new RentalsSunDrawable(getContext(), this);
setPadding(0, DensityUtil.dip2px(15), 0, DensityUtil.dip2px(10));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = mDrawable.getTotalDragDistance() * 5 / 4;
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height + getPaddingTop() + getPaddingBottom(), MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
int pl = getPaddingLeft();
int pt = getPaddingTop();
mDrawable.setBounds(pl, pt, pl + right - left, pt + bottom - top);
}
@Override
public long succeedRetention() {
return 300;
}
@Override
public long failingRetention() {
return 0;
}
@Override
public int refreshHeight() {
return mDrawable.getTotalDragDistance()+DensityUtil.dip2px(15);
}
@Override
public int maxOffsetHeight() {
return getHeight();
}
@Override
public void onReset(@NotNull KRefreshLayout refreshLayout) {
mDrawable.resetOriginals();
}
@Override
protected void onDraw(Canvas canvas) {
mDrawable.draw(canvas);
}
@Override
public void onPrepare(@NotNull KRefreshLayout refreshLayout) {
}
@Override
public void onRefresh(@NotNull KRefreshLayout refreshLayout) {
mDrawable.start();
mDrawable.offsetTopAndBottom(mDistance);
mDrawable.setPercent(mPercent);
invalidate();
}
@Override
public void onComplete(@NotNull KRefreshLayout refreshLayout,boolean isSuccess) {
mDrawable.stop();
mDrawable.offsetTopAndBottom(mDistance);
mDrawable.setPercent(mPercent);
invalidate();
}
@Override
public void onScroll(@NotNull KRefreshLayout refreshLayout, int distance, float percent, boolean refreshing) {
mPercent = percent;
mDistance = distance;
mDrawable.offsetTopAndBottom(distance);
mDrawable.setPercent(percent);
invalidate();
}
@Override
public void invalidateDrawable(@NonNull Drawable drawable) {
if (drawable == mDrawable) {
invalidate();
} else {
super.invalidateDrawable(drawable);
}
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/storehouse/StoreHouseBarItem.java
================================================
package gorden.krefreshlayout.demo.header.storehouse;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import java.util.Random;
/**
* Created by srain on 11/6/14.
*/
public class StoreHouseBarItem extends Animation {
public PointF midPoint;
public float translationX;
public int index;
private final Paint mPaint = new Paint();
private float mFromAlpha = 1.0f;
private float mToAlpha = 0.4f;
private PointF mCStartPoint;
private PointF mCEndPoint;
public StoreHouseBarItem(int index, PointF start, PointF end, int color, int lineWidth) {
this.index = index;
midPoint = new PointF((start.x + end.x) / 2, (start.y + end.y) / 2);
mCStartPoint = new PointF(start.x - midPoint.x, start.y - midPoint.y);
mCEndPoint = new PointF(end.x - midPoint.x, end.y - midPoint.y);
setColor(color);
setLineWidth(lineWidth);
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.STROKE);
}
public void setLineWidth(int width) {
mPaint.setStrokeWidth(width);
}
public void setColor(int color) {
mPaint.setColor(color);
}
public void resetPosition(int horizontalRandomness) {
Random random = new Random();
int randomNumber = -random.nextInt(horizontalRandomness) + horizontalRandomness;
translationX = randomNumber;
}
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
float alpha = mFromAlpha;
alpha = alpha + ((mToAlpha - alpha) * interpolatedTime);
setAlpha(alpha);
}
public void start(float fromAlpha, float toAlpha) {
mFromAlpha = fromAlpha;
mToAlpha = toAlpha;
super.start();
}
public void setAlpha(float alpha) {
mPaint.setAlpha((int) (alpha * 255));
}
public void draw(Canvas canvas) {
canvas.drawLine(mCStartPoint.x, mCStartPoint.y, mCEndPoint.x, mCEndPoint.y, mPaint);
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/storehouse/StoreHouseHeader.java
================================================
package gorden.krefreshlayout.demo.header.storehouse;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Transformation;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import gorden.krefreshlayout.demo.util.DensityUtil;
import gorden.refresh.KRefreshHeader;
import gorden.refresh.KRefreshLayout;
public class StoreHouseHeader extends View implements KRefreshHeader {
public ArrayList<StoreHouseBarItem> mItemList = new ArrayList<StoreHouseBarItem>();
private int mLineWidth = -1;
private float mScale = 1;
private int mDropHeight = -1;
private float mInternalAnimationFactor = 0.7f;
private int mHorizontalRandomness = -1;
private float mProgress = 0;
private int mDrawZoneWidth = 0;
private int mDrawZoneHeight = 0;
private int mOffsetX = 0;
private int mOffsetY = 0;
private float mBarDarkAlpha = 0.4f;
private float mFromAlpha = 1.0f;
private float mToAlpha = 0.4f;
private int mLoadingAniDuration = 1000;
private int mLoadingAniSegDuration = 1000;
private int mLoadingAniItemDuration = 400;
private Transformation mTransformation = new Transformation();
private boolean mIsInLoading = false;
private AniController mAniController = new AniController();
private int mTextColor = Color.WHITE;
public StoreHouseHeader(Context context) {
super(context);
initView();
}
public StoreHouseHeader(Context context, AttributeSet attrs) {
super(context, attrs);
initView();
}
public StoreHouseHeader(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() {
mLineWidth = DensityUtil.dip2px(1);
mDropHeight = DensityUtil.dip2px(40);
mHorizontalRandomness =DensityUtil.appWidth() / 2;
initWithString("KREFRESHLAYOUT",25);
setPadding(0,20,0,20);
}
private void setProgress(float progress) {
mProgress = progress;
}
public int getLoadingAniDuration() {
return mLoadingAniDuration;
}
public void setLoadingAniDuration(int duration) {
mLoadingAniDuration = duration;
mLoadingAniSegDuration = duration;
}
public StoreHouseHeader setLineWidth(int width) {
mLineWidth = width;
for (int i = 0; i < mItemList.size(); i++) {
mItemList.get(i).setLineWidth(width);
}
return this;
}
public StoreHouseHeader setTextColor(int color) {
mTextColor = color;
for (int i = 0; i < mItemList.size(); i++) {
mItemList.get(i).setColor(color);
}
return this;
}
public StoreHouseHeader setDropHeight(int height) {
mDropHeight = height;
return this;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = getTopOffset() + mDrawZoneHeight + getBottomOffset();
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mOffsetX = (getMeasuredWidth() - mDrawZoneWidth) / 2;
mOffsetY = getTopOffset();
mDropHeight = getTopOffset();
}
private int getTopOffset() {
return getPaddingTop() + DensityUtil.dip2px(10);
}
private int getBottomOffset() {
return getPaddingBottom() + DensityUtil.dip2px(10);
}
public void initWithString(String str) {
initWithString(str, 25);
}
public void initWithString(String str, int fontSize) {
ArrayList<float[]> pointList = StoreHousePath.getPath(str, fontSize * 0.01f, 14);
initWithPointList(pointList);
}
public void initWithStringArray(int id) {
String[] points = getResources().getStringArray(id);
ArrayList<float[]> pointList = new ArrayList<float[]>();
for (int i = 0; i < points.length; i++) {
String[] x = points[i].split(",");
float[] f = new float[4];
for (int j = 0; j < 4; j++) {
f[j] = Float.parseFloat(x[j]);
}
pointList.add(f);
}
initWithPointList(pointList);
}
public float getScale() {
return mScale;
}
public void setScale(float scale) {
mScale = scale;
}
public void initWithPointList(ArrayList<float[]> pointList) {
float drawWidth = 0;
float drawHeight = 0;
boolean shouldLayout = mItemList.size() > 0;
mItemList.clear();
for (int i = 0; i < pointList.size(); i++) {
float[] line = pointList.get(i);
PointF startPoint = new PointF(DensityUtil.dip2px(line[0]) * mScale, DensityUtil.dip2px(line[1]) * mScale);
PointF endPoint = new PointF(DensityUtil.dip2px(line[2]) * mScale, DensityUtil.dip2px(line[3]) * mScale);
drawWidth = Math.max(drawWidth, startPoint.x);
drawWidth = Math.max(drawWidth, endPoint.x);
drawHeight = Math.max(drawHeight, startPoint.y);
drawHeight = Math.max(drawHeight, endPoint.y);
StoreHouseBarItem item = new StoreHouseBarItem(i, startPoint, endPoint, mTextColor, mLineWidth);
item.resetPosition(mHorizontalRandomness);
mItemList.add(item);
}
mDrawZoneWidth = (int) Math.ceil(drawWidth);
mDrawZoneHeight = (int) Math.ceil(drawHeight);
if (shouldLayout) {
requestLayout();
}
}
private void beginLoading() {
mIsInLoading = true;
mAniController.start();
invalidate();
}
private void loadFinish() {
mIsInLoading = false;
mAniController.stop();
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
float progress = mProgress;
int c1 = canvas.save();
int len = mItemList.size();
for (int i = 0; i < len; i++) {
canvas.save();
StoreHouseBarItem storeHouseBarItem = mItemList.get(i);
float offsetX = mOffsetX + storeHouseBarItem.midPoint.x;
float offsetY = mOffsetY + storeHouseBarItem.midPoint.y;
if (mIsInLoading) {
storeHouseBarItem.getTransformation(getDrawingTime(), mTransformation);
canvas.translate(offsetX, offsetY);
} else {
if (progress == 0) {
storeHouseBarItem.resetPosition(mHorizontalRandomness);
continue;
}
float startPadding = (1 - mInternalAnimationFactor) * i / len;
float endPadding = 1 - mInternalAnimationFactor - startPadding;
// done
if (progress == 1 || progress >= 1 - endPadding) {
canvas.translate(offsetX, offsetY);
storeHouseBarItem.setAlpha(mBarDarkAlpha);
} else {
float realProgress;
if (progress <= startPadding) {
realProgress = 0;
} else {
realProgress = Math.min(1, (progress - startPadding) / mInternalAnimationFactor);
}
offsetX += storeHouseBarItem.translationX * (1 - realProgress);
offsetY += -mDropHeight * (1 - realProgress);
Matrix matrix = new Matrix();
matrix.postRotate(360 * realProgress);
matrix.postScale(realProgress, realProgress);
matrix.postTranslate(offsetX, offsetY);
storeHouseBarItem.setAlpha(mBarDarkAlpha * realProgress);
canvas.concat(matrix);
}
}
storeHouseBarItem.draw(canvas);
canvas.restore();
}
if (mIsInLoading) {
invalidate();
}
canvas.restoreToCount(c1);
}
@Override
public long succeedRetention() {
return 200;
}
@Override
public long failingRetention() {
return 200;
}
@Override
public int refreshHeight() {
return getHeight();
}
@Override
public int maxOffsetHeight() {
return 2*getHeight();
}
@Override
public void onReset(@NotNull KRefreshLayout refreshLayout) {
loadFinish();
for (int i = 0; i < mItemList.size(); i++) {
mItemList.get(i).resetPosition(mHorizontalRandomness);
}
}
@Override
public void onPrepare(@NotNull KRefreshLayout refreshLayout) {
}
@Override
public void onRefresh(@NotNull KRefreshLayout refreshLayout) {
beginLoading();
}
@Override
public void onComplete(@NotNull KRefreshLayout refreshLayout, boolean isSuccess) {
loadFinish();
}
@Override
public void onScroll(@NotNull KRefreshLayout refreshLayout, int distance, float percent, boolean refreshing) {
float currentPercent = Math.min(1f, percent);
setProgress(currentPercent);
invalidate();
}
private class AniController implements Runnable {
private int mTick = 0;
private int mCountPerSeg = 0;
private int mSegCount = 0;
private int mInterval = 0;
private boolean mRunning = true;
private void start() {
mRunning = true;
mTick = 0;
mInterval = mLoadingAniDuration / mItemList.size();
mCountPerSeg = mLoadingAniSegDuration / mInterval;
mSegCount = mItemList.size() / mCountPerSeg + 1;
run();
}
@Override
public void run() {
int pos = mTick % mCountPerSeg;
for (int i = 0; i < mSegCount; i++) {
int index = i * mCountPerSeg + pos;
if (index > mTick) {
continue;
}
index = index % mItemList.size();
StoreHouseBarItem item = mItemList.get(index);
item.setFillAfter(false);
item.setFillEnabled(true);
item.setFillBefore(false);
item.setDuration(mLoadingAniItemDuration);
item.start(mFromAlpha, mToAlpha);
}
mTick++;
if (mRunning) {
postDelayed(this, mInterval);
}
}
private void stop() {
mRunning = false;
removeCallbacks(this);
}
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/storehouse/StoreHousePath.java
================================================
package gorden.krefreshlayout.demo.header.storehouse;
import android.util.SparseArray;
import java.util.ArrayList;
/**
* Created by srain on 11/7/14.
*/
public class StoreHousePath {
private static final SparseArray<float[]> sPointList;
static {
sPointList = new SparseArray<float[]>();
float[][] LETTERS = new float[][]{
new float[]{
// A
24, 0, 1, 22,
1, 22, 1, 72,
24, 0, 47, 22,
47, 22, 47, 72,
1, 48, 47, 48
},
new float[]{
// B
0, 0, 0, 72,
0, 0, 37, 0,
37, 0, 47, 11,
47, 11, 47, 26,
47, 26, 38, 36,
38, 36, 0, 36,
38, 36, 47, 46,
47, 46, 47, 61,
47, 61, 38, 71,
37, 72, 0, 72,
},
new float[]{
// C
47, 0, 0, 0,
0, 0, 0, 72,
0, 72, 47, 72,
},
new float[]{
// D
0, 0, 0, 72,
0, 0, 24, 0,
24, 0, 47, 22,
47, 22, 47, 48,
47, 48, 23, 72,
23, 72, 0, 72,
},
new float[]{
// E
0, 0, 0, 72,
0, 0, 47, 0,
0, 36, 37, 36,
0, 72, 47, 72,
},
new float[]{
// F
0, 0, 0, 72,
0, 0, 47, 0,
0, 36, 37, 36,
},
new float[]{
// G
47, 23, 47, 0,
47, 0, 0, 0,
0, 0, 0, 72,
0, 72, 47, 72,
47, 72, 47, 48,
47, 48, 24, 48,
},
new float[]{
// H
0, 0, 0, 72,
0, 36, 47, 36,
47, 0, 47, 72,
},
new float[]{
// I
0, 0, 47, 0,
24, 0, 24, 72,
0, 72, 47, 72,
},
new float[]{
// J
47, 0, 47, 72,
47, 72, 24, 72,
24, 72, 0, 48,
},
new float[]{
// K
0, 0, 0, 72,
47, 0, 3, 33,
3, 38, 47, 72,
},
new float[]{
// L
0, 0, 0, 72,
0, 72, 47, 72,
},
new float[]{
// M
0, 0, 0, 72,
0, 0, 24, 23,
24, 23, 47, 0,
47, 0, 47, 72,
},
new float[]{
// N
0, 0, 0, 72,
0, 0, 47, 72,
47, 72, 47, 0,
},
new float[]{
// O
0, 0, 0, 72,
0, 72, 47, 72,
47, 72, 47, 0,
47, 0, 0, 0,
},
new float[]{
// P
0, 0, 0, 72,
0, 0, 47, 0,
47, 0, 47, 36,
47, 36, 0, 36,
},
new float[]{
// Q
0, 0, 0, 72,
0, 72, 23, 72,
23, 72, 47, 48,
47, 48, 47, 0,
47, 0, 0, 0,
24, 28, 47, 71,
},
new float[]{
// R
0, 0, 0, 72,
0, 0, 47, 0,
47, 0, 47, 36,
47, 36, 0, 36,
0, 37, 47, 72,
},
new float[]{
// S
47, 0, 0, 0,
0, 0, 0, 36,
0, 36, 47, 36,
47, 36, 47, 72,
47, 72, 0, 72,
},
new float[]{
// T
0, 0, 47, 0,
24, 0, 24, 72,
},
new float[]{
// U
0, 0, 0, 72,
0, 72, 47, 72,
47, 72, 47, 0,
},
new float[]{
// V
0, 0, 24, 72,
24, 72, 47, 0,
},
new float[]{
// W
0, 0, 0, 72,
0, 72, 24, 49,
24, 49, 47, 72,
47, 72, 47, 0
},
new float[]{
// X
0, 0, 47, 72,
47, 0, 0, 72
},
new float[]{
// Y
0, 0, 24, 23,
47, 0, 24, 23,
24, 23, 24, 72
},
new float[]{
// Z
0, 0, 47, 0,
47, 0, 0, 72,
0, 72, 47, 72
},
};
final float[][] NUMBERS = new float[][]{
new float[]{
// 0
0, 0, 0, 72,
0, 72, 47, 72,
47, 72, 47, 0,
47, 0, 0, 0,
},
new float[]{
// 1
24, 0, 24, 72,
},
new float[]{
// 2
0, 0, 47, 0,
47, 0, 47, 36,
47, 36, 0, 36,
0, 36, 0, 72,
0, 72, 47, 72
},
new float[]{
// 3
0, 0, 47, 0,
47, 0, 47, 36,
47, 36, 0, 36,
47, 36, 47, 72,
47, 72, 0, 72,
},
new float[]{
// 4
0, 0, 0, 36,
0, 36, 47, 36,
47, 0, 47, 72,
},
new float[]{
// 5
0, 0, 0, 36,
0, 36, 47, 36,
47, 36, 47, 72,
47, 72, 0, 72,
0, 0, 47, 0
},
new float[]{
// 6
0, 0, 0, 72,
0, 72, 47, 72,
47, 72, 47, 36,
47, 36, 0, 36
},
new float[]{
// 7
0, 0, 47, 0,
47, 0, 47, 72
},
new float[]{
// 8
0, 0, 0, 72,
0, 72, 47, 72,
47, 72, 47, 0,
47, 0, 0, 0,
0, 36, 47, 36
},
new float[]{
// 9
47, 0, 0, 0,
0, 0, 0, 36,
0, 36, 47, 36,
47, 0, 47, 72,
}
};
// A - Z
for (int i = 0; i < LETTERS.length; i++) {
sPointList.append(i + 65, LETTERS[i]);
}
// a - z
for (int i = 0; i < LETTERS.length; i++) {
sPointList.append(i + 65 + 32, LETTERS[i]);
}
// 0 - 9
for (int i = 0; i < NUMBERS.length; i++) {
sPointList.append(i + 48, NUMBERS[i]);
}
// blank
addChar(' ', new float[]{});
// -
addChar('-', new float[]{
0, 36, 47, 36
});
// .
addChar('.', new float[]{
24, 60, 24, 72
});
}
public static void addChar(char c, float[] points) {
sPointList.append(c, points);
}
public static ArrayList<float[]> getPath(String str) {
return getPath(str, 1, 14);
}
/**
* @param str
* @param scale
* @param gapBetweenLetter
* @return ArrayList of float[] {x1, y1, x2, y2}
*/
public static ArrayList<float[]> getPath(String str, float scale, int gapBetweenLetter) {
ArrayList<float[]> list = new ArrayList<float[]>();
float offsetForWidth = 0;
for (int i = 0; i < str.length(); i++) {
int pos = str.charAt(i);
int key = sPointList.indexOfKey(pos);
if (key == -1) {
continue;
}
float[] points = sPointList.get(pos);
int pointCount = points.length / 4;
for (int j = 0; j < pointCount; j++) {
float[] line = new float[4];
for (int k = 0; k < 4; k++) {
float l = points[j * 4 + k];
// x
if (k % 2 == 0) {
line[k] = (l + offsetForWidth) * scale;
}
// y
else {
line[k] = l * scale;
}
}
list.add(line);
}
offsetForWidth += 57 + gapBetweenLetter;
}
return list;
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/MainActivity.kt
================================================
package gorden.krefreshlayout.demo.ui
import android.content.Intent
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.widget.SimpleAdapter
import gorden.krefreshlayout.demo.R
import gorden.krefreshlayout.demo.util.XLog
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
val gridItems = arrayOf("RecyclerView", "ScrollView", "NestedScrollView", "ViewPager in NestedScrollView", "ViewPager in ScrollView"
, "WebView ", "Fragment in ViewPager", "CoordinatorLayout", "Wechat_Refresh","LoadMoreView","gordenxqw@gmail.com", "QQ:354419188")
val dataList = ArrayList<Map<String, String>>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
for (item in gridItems) {
val map = HashMap<String, String>()
map.put("name", item)
dataList.add(map)
}
gridView.adapter = SimpleAdapter(this, dataList, R.layout.item_main, arrayOf("name"), intArrayOf(R.id.textView))
gridView.setOnItemClickListener { parent, view, position, id ->
val intent = Intent("SampleActivity")
intent.putExtra("position", position);
intent.putExtra("name", gridItems[position])
startActivity(intent)
}
refreshLayout.setKRefreshListener {
XLog.e("xxx","开始刷新")
refreshLayout.postDelayed({
refreshLayout.refreshComplete(true)
}, 2000)
}
// refreshLayout.startRefresh()
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/SampleActivity.kt
================================================
package gorden.krefreshlayout.demo.ui
import android.app.Activity
import android.content.Intent
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.v4.app.FragmentManager
import gorden.krefreshlayout.demo.R
import gorden.krefreshlayout.demo.ui.fragment.*
import kotlinx.android.synthetic.main.activity_sample.*
class SampleActivity : AppCompatActivity() {
private var mFragment:ISampleFragment? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sample)
text_title.text = intent.getStringExtra("name")
btn_back.setOnClickListener {
finish()
}
btn_setting.setOnClickListener {
val intent = Intent("SettingActivity")
intent.putExtra("header",mFragment?.headerPosition)
intent.putExtra("pincontent",mFragment?.pinContent)
intent.putExtra("keepheader",mFragment?.keepHeaderWhenRefresh)
intent.putExtra("durationoffset",mFragment?.durationOffset)
intent.putExtra("refreshtime",mFragment?.refreshTime)
startActivityForResult(intent,612)
}
val position = intent.getIntExtra("position",0)
val manager:FragmentManager = supportFragmentManager
when(position){
0-> mFragment = SampleAFragment()
1-> mFragment = SampleBFragment()
2-> mFragment = SampleCFragment()
3-> mFragment = SampleDFragment()
4-> mFragment = SampleEFragment()
5-> mFragment = SampleFFragment()
6-> mFragment = SampleGFragment()
7-> mFragment = SampleHFragment()
8-> mFragment = SampleIFragment()
9-> mFragment = SampleJFragment()
else ->mFragment = SampleAFragment()
}
manager.beginTransaction().replace(R.id.frame_content,mFragment).commit()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 612&&resultCode == Activity.RESULT_OK){
mFragment?.headerPosition = data!!.getIntExtra("header",mFragment!!.headerPosition)
mFragment?.pinContent = data.getBooleanExtra("pincontent",mFragment!!.pinContent)
mFragment?.keepHeaderWhenRefresh = data.getBooleanExtra("keepheader",mFragment!!.keepHeaderWhenRefresh)
mFragment?.durationOffset = data.getLongExtra("durationoffset",mFragment!!.durationOffset)
mFragment?.refreshTime = data.getLongExtra("refreshtime",mFragment!!.refreshTime)
}
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/SettingActivity.kt
================================================
package gorden.krefreshlayout.demo.ui
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.text.TextUtils
import android.view.View
import android.widget.AdapterView
import gorden.krefreshlayout.demo.R
import kotlinx.android.synthetic.main.activity_setting.*
class SettingActivity : AppCompatActivity() {
private var headerPosition = 0
private var pinContent = false
private var keepHeaderWhenRefresh = true
private var durationOffset = 200L
private var refreshTime = 2000L
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_setting)
btn_back.setOnClickListener {
finish()
}
headerPosition = intent.getIntExtra("header", 0)
pinContent = intent.getBooleanExtra("pincontent", false)
keepHeaderWhenRefresh = intent.getBooleanExtra("keepheader", true)
durationOffset = intent.getLongExtra("durationoffset", 200)
refreshTime = intent.getLongExtra("refreshtime", 2000)
spinner.setSelection(headerPosition)
togglePinContent.isChecked = pinContent
toggleKeepHeader.isChecked = keepHeaderWhenRefresh
edit_offset.setText(durationOffset.toString())
edit_refresh.setText(refreshTime.toString())
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onNothingSelected(parent: AdapterView<*>?) {
}
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
headerPosition = position
}
}
}
override fun finish() {
val data = Intent()
pinContent = togglePinContent.isChecked
keepHeaderWhenRefresh = toggleKeepHeader.isChecked
durationOffset = if (TextUtils.isEmpty(edit_offset.text)) 200 else edit_offset.text.toString().toLong()
refreshTime = if (TextUtils.isEmpty(edit_refresh.text)) 2000 else edit_refresh.text.toString().toLong()
data.putExtra("header", headerPosition)
data.putExtra("pincontent", pinContent)
data.putExtra("keepheader", keepHeaderWhenRefresh)
data.putExtra("durationoffset", durationOffset)
data.putExtra("refreshtime", refreshTime)
setResult(Activity.RESULT_OK, data)
super.finish()
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/ISampleFragment.kt
================================================
package gorden.krefreshlayout.demo.ui.fragment
import android.support.v4.app.Fragment
import android.view.ViewGroup
import gorden.krefreshlayout.demo.header.ClassicalHeader
import gorden.krefreshlayout.demo.header.WechatHeader
import gorden.krefreshlayout.demo.header.circle.CircleHeader
import gorden.krefreshlayout.demo.header.fungame.FunGameHeader
import gorden.krefreshlayout.demo.header.materia.MateriaProgressHeader
import gorden.krefreshlayout.demo.header.rentals.RentalsSunHeaderView
import gorden.krefreshlayout.demo.header.storehouse.StoreHouseHeader
import gorden.krefreshlayout.demo.util.DensityUtil
import gorden.refresh.KRefreshLayout
/**
* document
* Created by Gordn on 2017/6/21.
*/
abstract class ISampleFragment : Fragment() {
abstract val mRefreshLayout: KRefreshLayout
var headerPosition: Int = 0
get() = field
set(value) {
if (field != value) {
field = value
header()
}
}
var pinContent: Boolean = false
get() = field
set(value) {
if (field != value) {
field = value
mRefreshLayout.pinContent = field
}
}
var keepHeaderWhenRefresh: Boolean = true
get() = field
set(value) {
if (field != value) {
field = value
mRefreshLayout.keepHeaderWhenRefresh = field
}
}
var durationOffset: Long = 200
get() = field
set(value) {
if (field != value) {
field = value
mRefreshLayout.durationOffset=field
}
}
var refreshTime: Long = 2000
get() = field
set(value) {
field = value
}
fun header(): Unit {
when (headerPosition) {
0 -> mRefreshLayout.setHeader(ClassicalHeader(context))
1 -> mRefreshLayout.setHeader(MateriaProgressHeader(context), ViewGroup.LayoutParams.MATCH_PARENT, DensityUtil.dip2px(80))
2 -> mRefreshLayout.setHeader(RentalsSunHeaderView(context))
3 -> mRefreshLayout.setHeader(StoreHouseHeader(context))
4 -> mRefreshLayout.setHeader(CircleHeader(context))
5 -> mRefreshLayout.setHeader(FunGameHeader(context))
6 -> mRefreshLayout.setHeader(WechatHeader(context))
else -> mRefreshLayout.removeHeader()
}
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleAFragment.kt
================================================
package gorden.krefreshlayout.demo.ui.fragment
import android.os.Bundle
import android.support.v7.widget.DividerItemDecoration
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import gorden.krefreshlayout.demo.R
import gorden.krefreshlayout.demo.header.ClassicalHeader
import gorden.refresh.KRefreshLayout
import kotlinx.android.synthetic.main.layout_recyclerview.*
/**
* document
* Created by Gordn on 2017/6/21.
*/
class SampleAFragment : ISampleFragment() {
override val mRefreshLayout: KRefreshLayout
get() = refreshLayout
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.layout_recyclerview,container,false)
}
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
refreshLayout.setHeader(ClassicalHeader(context))
recyclerView.layoutManager = LinearLayoutManager(context)
recyclerView.addItemDecoration(DividerItemDecoration(context,DividerItemDecoration.VERTICAL))
recyclerView.adapter = object : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onBindViewHolder(holder: RecyclerView.ViewHolder?, position: Int) {
}
override fun getItemCount(): Int {
return 20
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): RecyclerView.ViewHolder {
return object :RecyclerView.ViewHolder(LayoutInflater.from(context).inflate(R.layout.item_sample,parent,false)){}
}
}
refreshLayout.setKRefreshListener {
refreshLayout.postDelayed({
refreshLayout?.refreshComplete(true)
},refreshTime)
}
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleBFragment.kt
================================================
package gorden.krefreshlayout.demo.ui.fragment
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import gorden.krefreshlayout.demo.R
import gorden.krefreshlayout.demo.header.ClassicalHeader
import gorden.refresh.KRefreshLayout
import kotlinx.android.synthetic.main.layout_scrollview.*
/**
* document
* Created by Gordn on 2017/6/21.
*/
class SampleBFragment : ISampleFragment() {
override val mRefreshLayout: KRefreshLayout
get() = refreshLayout
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.layout_scrollview,container,false)
}
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
refreshLayout.setHeader(ClassicalHeader(context))
refreshLayout.setKRefreshListener {
refreshLayout.postDelayed({
refreshLayout?.refreshComplete(true)
},refreshTime)
}
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleCFragment.kt
================================================
package gorden.krefreshlayout.demo.ui.fragment
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import gorden.krefreshlayout.demo.R
import gorden.krefreshlayout.demo.header.ClassicalHeader
import gorden.refresh.KRefreshLayout
import kotlinx.android.synthetic.main.layout_nestedscrollview.*
/**
* document
* Created by Gordn on 2017/6/21.
*/
class SampleCFragment : ISampleFragment() {
override val mRefreshLayout: KRefreshLayout
get() = refreshLayout
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.layout_nestedscrollview,container,false)
}
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
refreshLayout.setHeader(ClassicalHeader(context))
refreshLayout.setKRefreshListener {
refreshLayout.postDelayed({
refreshLayout?.refreshComplete(true)
},refreshTime)
}
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleDFragment.kt
================================================
package gorden.krefreshlayout.demo.ui.fragment
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import gorden.krefreshlayout.demo.R
import gorden.krefreshlayout.demo.header.ClassicalHeader
import gorden.refresh.KRefreshLayout
import kotlinx.android.synthetic.main.layout_vp_nestedscrollview.*
/**
* document
* Created by Gordn on 2017/6/21.
*/
class SampleDFragment : ISampleFragment() {
override val mRefreshLayout: KRefreshLayout
get() = refreshLayout
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.layout_vp_nestedscrollview, container, false)
}
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
refreshLayout.setHeader(ClassicalHeader(context))
viewPager.setImages(arrayListOf<Int>(R.drawable.img_pager1, R.drawable.img_pager2, R.drawable.img_pager3))
refreshLayout.setKRefreshListener {
refreshLayout.postDelayed({
refreshLayout?.refreshComplete(true)
}, refreshTime)
}
}
}
================================================
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleEFragment.kt
================================================
package gorden.krefreshlayout.demo.ui.fragment
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import gorden.krefreshlayout.demo.R
import gorden.krefreshlayout.demo.header.ClassicalHeader
import gorden.refresh.KRefreshLayout
import kotlinx.android.synthetic.main.layout_vp_scroll
gitextract_ue_irtns/ ├── .gitattributes ├── .gitignore ├── LICENSE ├── LoadMore.md ├── README.md ├── app_java/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── java/ │ │ └── gorden/ │ │ └── jrefresh/ │ │ └── demo/ │ │ ├── MainActivity.java │ │ ├── header/ │ │ │ └── ClassicalHeader.java │ │ └── util/ │ │ └── DensityUtil.java │ └── res/ │ ├── layout/ │ │ ├── activity_main.xml │ │ └── item_sample.xml │ └── values/ │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── app_kotlin/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── kotlin/ │ │ └── gorden/ │ │ └── krefreshlayout/ │ │ └── demo/ │ │ ├── App.java │ │ ├── footer/ │ │ │ └── ClassicalFooter.java │ │ ├── header/ │ │ │ ├── ClassicalHeader.java │ │ │ ├── WechatHeader.java │ │ │ ├── circle/ │ │ │ │ ├── AnimationView.java │ │ │ │ └── CircleHeader.java │ │ │ ├── fungame/ │ │ │ │ ├── BattleCityView.java │ │ │ │ ├── FunGameFactory.java │ │ │ │ ├── FunGameHeader.java │ │ │ │ ├── FunGameView.java │ │ │ │ └── HitBlockView.java │ │ │ ├── materia/ │ │ │ │ ├── CircleImageView.java │ │ │ │ ├── MateriaProgressHeader.java │ │ │ │ └── MaterialProgressDrawable.java │ │ │ ├── rentals/ │ │ │ │ ├── RentalsSunDrawable.java │ │ │ │ └── RentalsSunHeaderView.java │ │ │ └── storehouse/ │ │ │ ├── StoreHouseBarItem.java │ │ │ ├── StoreHouseHeader.java │ │ │ └── StoreHousePath.java │ │ ├── ui/ │ │ │ ├── MainActivity.kt │ │ │ ├── SampleActivity.kt │ │ │ ├── SettingActivity.kt │ │ │ └── fragment/ │ │ │ ├── ISampleFragment.kt │ │ │ ├── SampleAFragment.kt │ │ │ ├── SampleBFragment.kt │ │ │ ├── SampleCFragment.kt │ │ │ ├── SampleDFragment.kt │ │ │ ├── SampleEFragment.kt │ │ │ ├── SampleFFragment.kt │ │ │ ├── SampleGFragment.kt │ │ │ ├── SampleHFragment.kt │ │ │ ├── SampleIFragment.kt │ │ │ └── SampleJFragment.kt │ │ ├── util/ │ │ │ ├── CrashHandler.java │ │ │ ├── DensityUtil.java │ │ │ └── XLog.java │ │ └── widget/ │ │ ├── AdViewPager.java │ │ ├── HeaderFloatBehavior.java │ │ ├── HeaderScrollingBehavior.java │ │ └── recyclerview/ │ │ ├── KLoadMoreView.kt │ │ └── KRecyclerView.kt │ └── res/ │ ├── drawable/ │ │ ├── bg_main.xml │ │ └── selector_adpager_point.xml │ ├── layout/ │ │ ├── activity_header_list.xml │ │ ├── activity_main.xml │ │ ├── activity_sample.xml │ │ ├── activity_setting.xml │ │ ├── item_main.xml │ │ ├── item_sample.xml │ │ ├── layout_coordinatorlayout.xml │ │ ├── layout_krecyclerview.xml │ │ ├── layout_nestedscrollview.xml │ │ ├── layout_recyclerview.xml │ │ ├── layout_scrollview.xml │ │ ├── layout_viewpager.xml │ │ ├── layout_vp_nestedscrollview.xml │ │ ├── layout_vp_scrollview.xml │ │ └── layout_webview.xml │ └── values/ │ ├── attrs.xml │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── bintrayUpload.gradle ├── build.gradle ├── refresh-java/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ ├── project.properties │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── java/ │ │ └── gorden/ │ │ └── refresh/ │ │ ├── JRefreshHeader.java │ │ └── JRefreshLayout.java │ └── res/ │ └── values/ │ └── jattr.xml ├── refresh-kotlin/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ ├── project.properties │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── kotlin/ │ │ └── gorden/ │ │ └── refresh/ │ │ ├── KRefreshHeader.kt │ │ └── KRefreshLayout.kt │ └── res/ │ └── values/ │ └── kattr.xml └── settings.gradle
SYMBOL INDEX (532 symbols across 30 files)
FILE: app_java/src/main/java/gorden/jrefresh/demo/MainActivity.java
class MainActivity (line 11) | public class MainActivity extends AppCompatActivity {
method onCreate (line 14) | @Override
FILE: app_java/src/main/java/gorden/jrefresh/demo/header/ClassicalHeader.java
class ClassicalHeader (line 32) | public class ClassicalHeader extends FrameLayout implements JRefreshHead...
method ClassicalHeader (line 40) | public ClassicalHeader(@NonNull Context context) {
method ClassicalHeader (line 44) | public ClassicalHeader(@NonNull Context context, @Nullable AttributeSe...
method ClassicalHeader (line 48) | public ClassicalHeader(@NonNull Context context, @Nullable AttributeSe...
method succeedRetention (line 77) | @Override
method failingRetention (line 82) | @Override
method refreshHeight (line 87) | @Override
method maxOffsetHeight (line 92) | @Override
method onReset (line 100) | @Override
method onPrepare (line 109) | @Override
method onRefresh (line 116) | @Override
method onComplete (line 125) | @Override
method onScroll (line 139) | @Override
FILE: app_java/src/main/java/gorden/jrefresh/demo/util/DensityUtil.java
class DensityUtil (line 10) | public class DensityUtil {
method dip2px (line 13) | public static int dip2px(int dp){
method dip2px (line 16) | public static int dip2px(float dp){
method appWidth (line 19) | public static int appWidth(){
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/App.java
class App (line 13) | public class App extends Application{
method onCreate (line 14) | @Override
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/footer/ClassicalFooter.java
class ClassicalFooter (line 32) | public class ClassicalFooter extends FrameLayout implements KLoadMoreView {
method ClassicalFooter (line 39) | public ClassicalFooter(@NonNull Context context) {
method ClassicalFooter (line 43) | public ClassicalFooter(@NonNull Context context, @Nullable AttributeSe...
method ClassicalFooter (line 47) | public ClassicalFooter(@NonNull Context context, @Nullable AttributeSe...
method shouldLoadMore (line 83) | @Override
method onLoadMore (line 89) | @Override
method onComplete (line 96) | @Override
method onError (line 103) | @Override
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/ClassicalHeader.java
class ClassicalHeader (line 33) | public class ClassicalHeader extends FrameLayout implements KRefreshHead...
method ClassicalHeader (line 41) | public ClassicalHeader(@NonNull Context context) {
method ClassicalHeader (line 45) | public ClassicalHeader(@NonNull Context context, @Nullable AttributeSe...
method ClassicalHeader (line 49) | public ClassicalHeader(@NonNull Context context, @Nullable AttributeSe...
method succeedRetention (line 78) | @Override
method failingRetention (line 83) | @Override
method refreshHeight (line 88) | @Override
method maxOffsetHeight (line 93) | @Override
method onReset (line 101) | @Override
method onPrepare (line 110) | @Override
method onRefresh (line 117) | @Override
method onComplete (line 126) | @Override
method onScroll (line 140) | @Override
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/WechatHeader.java
class WechatHeader (line 27) | public class WechatHeader extends FrameLayout implements KRefreshHeader {
method WechatHeader (line 32) | public WechatHeader(@NonNull Context context) {
method WechatHeader (line 36) | public WechatHeader(@NonNull Context context, @Nullable AttributeSet a...
method succeedRetention (line 65) | @Override
method failingRetention (line 70) | @Override
method refreshHeight (line 75) | @Override
method maxOffsetHeight (line 80) | @Override
method onReset (line 85) | @Override
method onPrepare (line 90) | @Override
method onRefresh (line 94) | @Override
method onComplete (line 99) | @Override
method onScroll (line 109) | @Override
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/circle/AnimationView.java
class AnimationView (line 18) | public class AnimationView extends View {
type AnimatorStatus (line 30) | enum AnimatorStatus {
method toString (line 41) | @Override
method AnimationView (line 75) | public AnimationView(Context context) {
method AnimationView (line 79) | public AnimationView(Context context, AttributeSet attrs) {
method AnimationView (line 83) | public AnimationView(Context context, AttributeSet attrs, int defStyle...
method initView (line 88) | private void initView(Context context, AttributeSet attrs, int defStyl...
method onMeasure (line 118) | @Override
method onLayout (line 127) | @Override
method onDraw (line 153) | @Override
method drawDrag (line 206) | private void drawDrag(Canvas canvas) {
method drawSpring (line 216) | private void drawSpring(Canvas canvas, int springDelta) {
method drawPopBall (line 241) | private void drawPopBall(Canvas canvas) {
method drawTail (line 265) | private void drawTail(Canvas canvas, int centerY, int bottom, float fr...
method drawOutCir (line 281) | private void drawOutCir(Canvas canvas) {
method drawRefreshing (line 299) | private void drawRefreshing(Canvas canvas) {
method setRefreshing (line 328) | public void setRefreshing(boolean isFresh) {
method drawDone (line 332) | private void drawDone(Canvas canvas) {
method getRelHeight (line 376) | private int getRelHeight() {
method getSpringDelta (line 380) | private int getSpringDelta() {
method releaseDrag (line 391) | public void releaseDrag() {
method getRelRatio (line 399) | private float getRelRatio() {
method springUp (line 413) | private void springUp() {
method getSprRatio (line 421) | private float getSprRatio() {
method popBall (line 434) | private void popBall() {
method getPopRatio (line 441) | private float getPopRatio() {
method startOutCir (line 455) | private void startOutCir() {
method getOutRatio (line 467) | private float getOutRatio() {
method applyDone (line 481) | private void applyDone() {
method getDoneRatio (line 487) | private float getDoneRatio() {
method setOnViewAniDone (line 503) | public void setOnViewAniDone(OnViewAniDone onViewAniDone) {
type OnViewAniDone (line 507) | interface OnViewAniDone {
method viewAniDone (line 508) | void viewAniDone();
method setAniBackColor (line 512) | public void setAniBackColor(int color) {
method setAniForeColor (line 516) | public void setAniForeColor(int color) {
method setRadius (line 523) | public void setRadius(int smallTimes) {
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/circle/CircleHeader.java
class CircleHeader (line 21) | public class CircleHeader extends FrameLayout implements KRefreshHeader {
method CircleHeader (line 24) | public CircleHeader(@NonNull Context context) {
method succeedRetention (line 54) | @Override
method failingRetention (line 59) | @Override
method refreshHeight (line 64) | @Override
method maxOffsetHeight (line 69) | @Override
method onReset (line 74) | @Override
method onPrepare (line 79) | @Override
method onRefresh (line 83) | @Override
method onComplete (line 88) | @Override
method onScroll (line 93) | @Override
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/fungame/BattleCityView.java
class BattleCityView (line 18) | public class BattleCityView extends FunGameView {
method BattleCityView (line 117) | public BattleCityView(Context context) {
method BattleCityView (line 121) | public BattleCityView(Context context, AttributeSet attrs) {
method BattleCityView (line 125) | public BattleCityView(Context context, AttributeSet attrs, int defStyl...
method initConcreteView (line 129) | @Override
method drawGame (line 140) | @Override
method resetConfigParams (line 150) | @Override
method generateEnemyTank (line 181) | private RectF generateEnemyTank(int index) {
method makeBulletPath (line 191) | private void makeBulletPath(Canvas canvas) {
method getTrackIndex (line 230) | private int getTrackIndex(int y) {
method checkWipeOutETank (line 242) | private boolean checkWipeOutETank(Point point) {
method upLevel (line 259) | private void upLevel() {
method drawBullet (line 277) | private void drawBullet(Canvas canvas, Point point) {
method checkTankCrash (line 289) | private boolean checkTankCrash(int index, float selfX, float selfY) {
method drawSelfTank (line 302) | private void drawSelfTank(Canvas canvas) {
method drawEnemyTank (line 331) | private void drawEnemyTank(Canvas canvas) {
method drawTank (line 374) | private void drawTank(Canvas canvas, RectF rectF) {
method apperanceOption (line 386) | private int apperanceOption() {
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/fungame/FunGameFactory.java
class FunGameFactory (line 10) | public class FunGameFactory {
method createFunGameView (line 18) | static FunGameView createFunGameView(Context context, AttributeSet att...
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/fungame/FunGameHeader.java
class FunGameHeader (line 27) | public class FunGameHeader extends FrameLayout implements KRefreshHeader {
method FunGameHeader (line 53) | public FunGameHeader(Context context) {
method FunGameHeader (line 57) | public FunGameHeader(Context context, AttributeSet attrs) {
method FunGameHeader (line 61) | public FunGameHeader(Context context, AttributeSet attrs, int defStyle...
method initView (line 68) | private void initView(AttributeSet attrs) {
method createMaskTextView (line 88) | private TextView createMaskTextView(String text, int textSize, int gra...
method coverMaskView (line 98) | private void coverMaskView() {
method succeedRetention (line 107) | @Override
method failingRetention (line 112) | @Override
method refreshHeight (line 117) | @Override
method maxOffsetHeight (line 122) | @Override
method onReset (line 127) | @Override
method onPrepare (line 132) | @Override
method onRefresh (line 137) | @Override
method onComplete (line 142) | @Override
method onScroll (line 147) | @Override
class MeasureListener (line 154) | private class MeasureListener implements ViewTreeObserver.OnGlobalLayo...
method onGlobalLayout (line 156) | @Override
method doStart (line 171) | private void doStart(long delay) {
method onMeasure (line 194) | @Override
method postStart (line 216) | public void postStart() {
method postEnd (line 223) | public void postEnd() {
method postComplete (line 236) | public void postComplete() {
method moveRacket (line 240) | public void moveRacket(float distance) {
method back2StartPoint (line 245) | public void back2StartPoint(long duration) {
method getGameStatus (line 249) | public int getGameStatus() {
method setTopMaskViewText (line 253) | public void setTopMaskViewText(String topMaskViewText) {
method setBottomMaskViewText (line 258) | public void setBottomMaskViewText(String bottomMaskViewText) {
method setHeaderLodingStr (line 263) | public void setHeaderLodingStr(String loadingStr) {
method setHeaderGameOverStr (line 267) | public void setHeaderGameOverStr(String gameOverStr) {
method setHeaderLoadingFinishedStr (line 271) | public void setHeaderLoadingFinishedStr(String loadingFinishedStr) {
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/fungame/FunGameView.java
class FunGameView (line 20) | abstract class FunGameView extends View {
method FunGameView (line 58) | public FunGameView(Context context, AttributeSet attrs, int defStyleAt...
method initBaseTools (line 70) | protected void initBaseTools() {
method initBaseConfigParams (line 78) | protected void initBaseConfigParams(Context context) {
method initConcreteView (line 85) | protected abstract void initConcreteView();
method drawGame (line 87) | protected abstract void drawGame(Canvas canvas);
method resetConfigParams (line 89) | protected abstract void resetConfigParams();
method drawBoundary (line 95) | private void drawBoundary(Canvas canvas) {
method onMeasure (line 101) | @Override
method onDraw (line 106) | @Override
method drawText (line 117) | private void drawText(Canvas canvas) {
method promptText (line 140) | private void promptText(Canvas canvas, String text) {
method moveController (line 151) | public void moveController(float distance) {
method moveController2StartPoint (line 166) | public void moveController2StartPoint(long duration) {
method postStatus (line 184) | public void postStatus(int status) {
method getCurrStatus (line 198) | public int getCurrStatus() {
method getTextGameOver (line 202) | public String getTextGameOver() {
method setTextGameOver (line 206) | public void setTextGameOver(String textGameOver) {
method getTextLoading (line 210) | public String getTextLoading() {
method setTextLoading (line 214) | public void setTextLoading(String textLoading) {
method getTextLoadingFinished (line 218) | public String getTextLoadingFinished() {
method setTextLoadingFinished (line 222) | public void setTextLoadingFinished(String textLoadingFinished) {
method getScreenMetrics (line 232) | private DisplayMetrics getScreenMetrics(Context context) {
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/fungame/HitBlockView.java
class HitBlockView (line 17) | public class HitBlockView extends FunGameView {
method HitBlockView (line 90) | public HitBlockView(Context context) {
method HitBlockView (line 94) | public HitBlockView(Context context, AttributeSet attrs) {
method HitBlockView (line 98) | public HitBlockView(Context context, AttributeSet attrs, int defStyle) {
method initAttrs (line 103) | private void initAttrs(Context context, AttributeSet attrs) {
method initConcreteView (line 108) | @Override
method drawGame (line 122) | @Override
method resetConfigParams (line 131) | @Override
method drawRacket (line 153) | private void drawRacket(Canvas canvas) {
method makeBallPath (line 162) | private void makeBallPath(Canvas canvas) {
method checkTouchRacket (line 211) | private boolean checkTouchRacket(float y) {
method checkTouchBlock (line 226) | private boolean checkTouchBlock(float x, float y) {
method drawColorBlock (line 252) | private void drawColorBlock(Canvas canvas) {
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/materia/CircleImageView.java
class CircleImageView (line 21) | public class CircleImageView extends ImageView {
method CircleImageView (line 34) | public CircleImageView(Context context, int color, final float radius) {
method elevationSupported (line 61) | private boolean elevationSupported() {
method onMeasure (line 65) | @Override
method setAnimationListener (line 74) | public void setAnimationListener(Animation.AnimationListener listener) {
method onAnimationStart (line 78) | @Override
method onAnimationEnd (line 86) | @Override
method setBackgroundColorRes (line 99) | public void setBackgroundColorRes(int colorRes) {
method setBackgroundColor (line 103) | @Override
class OvalShadow (line 110) | private class OvalShadow extends OvalShape {
method OvalShadow (line 115) | public OvalShadow(int shadowRadius, int circleDiameter) {
method draw (line 127) | @Override
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/materia/MateriaProgressHeader.java
class MateriaProgressHeader (line 29) | public class MateriaProgressHeader extends FrameLayout implements KRefre...
method MateriaProgressHeader (line 51) | public MateriaProgressHeader(@NonNull Context context) {
method MateriaProgressHeader (line 55) | public MateriaProgressHeader(@NonNull Context context, @Nullable Attri...
method createProgressView (line 66) | private void createProgressView() {
method setProgressBackgroundColorSchemeColor (line 82) | public void setProgressBackgroundColorSchemeColor(@ColorInt int color) {
method setColorSchemeResources (line 87) | public void setColorSchemeResources(@ColorRes int... colorResIds) {
method setColorSchemeColors (line 96) | public void setColorSchemeColors(int... colors) {
method setSize (line 100) | public void setSize(int size) {
method succeedRetention (line 118) | @Override
method failingRetention (line 123) | @Override
method refreshHeight (line 128) | @Override
method maxOffsetHeight (line 133) | @Override
method onReset (line 140) | @Override
method onPrepare (line 155) | @Override
method onRefresh (line 160) | @Override
method onComplete (line 172) | @Override
method onScroll (line 177) | @Override
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/materia/MaterialProgressDrawable.java
class MaterialProgressDrawable (line 49) | class MaterialProgressDrawable extends Drawable implements Animatable {
method MaterialProgressDrawable (line 118) | MaterialProgressDrawable(Context context, View parent) {
method setSizeParameters (line 129) | private void setSizeParameters(double progressCircleWidth, double prog...
method updateSizes (line 151) | public void updateSizes(@ProgressDrawableSize int size) {
method showArrow (line 164) | public void showArrow(boolean show) {
method setArrowScale (line 171) | public void setArrowScale(float scale) {
method setStartEndTrim (line 181) | public void setStartEndTrim(float startAngle, float endAngle) {
method setProgressRotation (line 191) | public void setProgressRotation(float rotation) {
method setBackgroundColor (line 198) | public void setBackgroundColor(int color) {
method setColorSchemeColors (line 209) | public void setColorSchemeColors(int... colors) {
method getIntrinsicHeight (line 214) | @Override
method getIntrinsicWidth (line 219) | @Override
method draw (line 224) | @Override
method setAlpha (line 233) | @Override
method getAlpha (line 238) | public int getAlpha() {
method setColorFilter (line 242) | @Override
method setRotation (line 247) | @SuppressWarnings("unused")
method getRotation (line 253) | @SuppressWarnings("unused")
method getOpacity (line 258) | @Override
method isRunning (line 263) | @Override
method start (line 276) | @Override
method stop (line 293) | @Override
method getMinProgressArc (line 302) | float getMinProgressArc(Ring ring) {
method evaluateColorChange (line 308) | private int evaluateColorChange(float fraction, int startValue, int en...
method updateRingColor (line 332) | void updateRingColor(float interpolatedTime, Ring ring) {
method applyFinishTranslation (line 343) | void applyFinishTranslation(float interpolatedTime, Ring ring) {
method setupAnimators (line 361) | private void setupAnimators() {
method invalidateDrawable (line 450) | @Override
method scheduleDrawable (line 455) | @Override
method unscheduleDrawable (line 460) | @Override
class Ring (line 466) | private static class Ring {
method Ring (line 498) | Ring(Callback callback) {
method setBackgroundColor (line 509) | public void setBackgroundColor(int color) {
method setArrowDimensions (line 519) | public void setArrowDimensions(float width, float height) {
method draw (line 527) | public void draw(Canvas c, Rect bounds) {
method drawTriangle (line 549) | private void drawTriangle(Canvas c, float startAngle, float sweepAng...
method setColors (line 587) | public void setColors(@NonNull int[] colors) {
method setColor (line 600) | public void setColor(int color) {
method setColorIndex (line 608) | public void setColorIndex(int index) {
method getNextColor (line 616) | public int getNextColor() {
method getNextColorIndex (line 620) | private int getNextColorIndex() {
method goToNextColor (line 628) | public void goToNextColor() {
method setColorFilter (line 632) | public void setColorFilter(ColorFilter filter) {
method setAlpha (line 640) | public void setAlpha(int alpha) {
method getAlpha (line 647) | public int getAlpha() {
method setStrokeWidth (line 654) | public void setStrokeWidth(float strokeWidth) {
method getStrokeWidth (line 660) | @SuppressWarnings("unused")
method setStartTrim (line 665) | @SuppressWarnings("unused")
method getStartTrim (line 671) | @SuppressWarnings("unused")
method getStartingStartTrim (line 676) | public float getStartingStartTrim() {
method getStartingEndTrim (line 680) | public float getStartingEndTrim() {
method getStartingColor (line 684) | public int getStartingColor() {
method setEndTrim (line 688) | @SuppressWarnings("unused")
method getEndTrim (line 694) | @SuppressWarnings("unused")
method setRotation (line 699) | @SuppressWarnings("unused")
method getRotation (line 705) | @SuppressWarnings("unused")
method setInsets (line 710) | public void setInsets(int width, int height) {
method getInsets (line 721) | @SuppressWarnings("unused")
method setCenterRadius (line 730) | public void setCenterRadius(double centerRadius) {
method getCenterRadius (line 734) | public double getCenterRadius() {
method setShowArrow (line 741) | public void setShowArrow(boolean show) {
method setArrowScale (line 751) | public void setArrowScale(float scale) {
method getStartingRotation (line 761) | public float getStartingRotation() {
method storeOriginals (line 769) | public void storeOriginals() {
method resetOriginals (line 778) | public void resetOriginals() {
method invalidateSelf (line 787) | private void invalidateSelf() {
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/rentals/RentalsSunDrawable.java
class RentalsSunDrawable (line 22) | public class RentalsSunDrawable extends Drawable implements Animatable {
method RentalsSunDrawable (line 72) | public RentalsSunDrawable(Context context, View parent) {
method getContext (line 83) | private Context getContext() {
method initiateDimens (line 88) | private void initiateDimens() {
method createBitmaps (line 108) | private void createBitmaps() {
method offsetTopAndBottom (line 117) | public void offsetTopAndBottom(int offset) {
method draw (line 122) | @Override
method drawSky (line 134) | private void drawSky(Canvas canvas) {
method drawTown (line 166) | private void drawTown(Canvas canvas) {
method drawSun (line 206) | private void drawSun(Canvas canvas) {
method setPercent (line 246) | public void setPercent(float percent) {
method setRotate (line 251) | public void setRotate(float rotate) {
method resetOriginals (line 257) | public void resetOriginals() {
method setBounds (line 262) | @Override
method setAlpha (line 267) | @Override
method setColorFilter (line 272) | @Override
method getOpacity (line 277) | @Override
method isRunning (line 282) | @Override
method start (line 287) | @Override
method stop (line 294) | @Override
method setupAnimations (line 301) | private void setupAnimations() {
method getTotalDragDistance (line 314) | public int getTotalDragDistance() {
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/rentals/RentalsSunHeaderView.java
class RentalsSunHeaderView (line 21) | public class RentalsSunHeaderView extends View implements KRefreshHeader {
method RentalsSunHeaderView (line 26) | public RentalsSunHeaderView(Context context) {
method RentalsSunHeaderView (line 31) | public RentalsSunHeaderView(Context context, @Nullable AttributeSet at...
method RentalsSunHeaderView (line 36) | public RentalsSunHeaderView(Context context, @Nullable AttributeSet at...
method init (line 41) | private void init() {
method onMeasure (line 46) | @Override
method onLayout (line 53) | @Override
method succeedRetention (line 60) | @Override
method failingRetention (line 65) | @Override
method refreshHeight (line 70) | @Override
method maxOffsetHeight (line 75) | @Override
method onReset (line 80) | @Override
method onDraw (line 85) | @Override
method onPrepare (line 90) | @Override
method onRefresh (line 94) | @Override
method onComplete (line 102) | @Override
method onScroll (line 111) | @Override
method invalidateDrawable (line 120) | @Override
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/storehouse/StoreHouseBarItem.java
class StoreHouseBarItem (line 14) | public class StoreHouseBarItem extends Animation {
method StoreHouseBarItem (line 26) | public StoreHouseBarItem(int index, PointF start, PointF end, int colo...
method setLineWidth (line 40) | public void setLineWidth(int width) {
method setColor (line 44) | public void setColor(int color) {
method resetPosition (line 48) | public void resetPosition(int horizontalRandomness) {
method applyTransformation (line 54) | @Override
method start (line 61) | public void start(float fromAlpha, float toAlpha) {
method setAlpha (line 67) | public void setAlpha(float alpha) {
method draw (line 71) | public void draw(Canvas canvas) {
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/storehouse/StoreHouseHeader.java
class StoreHouseHeader (line 20) | public class StoreHouseHeader extends View implements KRefreshHeader {
method StoreHouseHeader (line 49) | public StoreHouseHeader(Context context) {
method StoreHouseHeader (line 54) | public StoreHouseHeader(Context context, AttributeSet attrs) {
method StoreHouseHeader (line 59) | public StoreHouseHeader(Context context, AttributeSet attrs, int defSt...
method initView (line 64) | private void initView() {
method setProgress (line 72) | private void setProgress(float progress) {
method getLoadingAniDuration (line 76) | public int getLoadingAniDuration() {
method setLoadingAniDuration (line 80) | public void setLoadingAniDuration(int duration) {
method setLineWidth (line 85) | public StoreHouseHeader setLineWidth(int width) {
method setTextColor (line 93) | public StoreHouseHeader setTextColor(int color) {
method setDropHeight (line 101) | public StoreHouseHeader setDropHeight(int height) {
method onMeasure (line 106) | @Override
method getTopOffset (line 117) | private int getTopOffset() {
method getBottomOffset (line 121) | private int getBottomOffset() {
method initWithString (line 125) | public void initWithString(String str) {
method initWithString (line 129) | public void initWithString(String str, int fontSize) {
method initWithStringArray (line 134) | public void initWithStringArray(int id) {
method getScale (line 148) | public float getScale() {
method setScale (line 152) | public void setScale(float scale) {
method initWithPointList (line 156) | public void initWithPointList(ArrayList<float[]> pointList) {
method beginLoading (line 184) | private void beginLoading() {
method loadFinish (line 190) | private void loadFinish() {
method onDraw (line 195) | @Override
method succeedRetention (line 252) | @Override
method failingRetention (line 257) | @Override
method refreshHeight (line 262) | @Override
method maxOffsetHeight (line 267) | @Override
method onReset (line 272) | @Override
method onPrepare (line 281) | @Override
method onRefresh (line 286) | @Override
method onComplete (line 291) | @Override
method onScroll (line 296) | @Override
class AniController (line 303) | private class AniController implements Runnable {
method start (line 311) | private void start() {
method run (line 321) | @Override
method stop (line 348) | private void stop() {
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/storehouse/StoreHousePath.java
class StoreHousePath (line 10) | public class StoreHousePath {
method addChar (line 324) | public static void addChar(char c, float[] points) {
method getPath (line 328) | public static ArrayList<float[]> getPath(String str) {
method getPath (line 338) | public static ArrayList<float[]> getPath(String str, float scale, int ...
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/util/CrashHandler.java
class CrashHandler (line 24) | @SuppressWarnings("unused")
method CrashHandler (line 39) | private CrashHandler() {
method getInstance (line 42) | public static CrashHandler getInstance() {
method uncaughtException (line 46) | @Override
method init (line 77) | public void init(Context context, boolean isDebug) {
method saveExceptionToSDCard (line 86) | private void saveExceptionToSDCard(Throwable ex) throws IOException {
method uploadExceptionToServer (line 120) | private void uploadExceptionToServer(Throwable ex) {
method dumpPhoneInfo (line 125) | private void dumpPhoneInfo(PrintWriter pw) throws PackageManager.NameN...
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/util/DensityUtil.java
class DensityUtil (line 10) | public class DensityUtil {
method dip2px (line 13) | public static int dip2px(int dp){
method dip2px (line 16) | public static int dip2px(float dp){
method appWidth (line 19) | public static int appWidth(){
method appHeight (line 22) | public static int appHeight(){
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/util/XLog.java
class XLog (line 13) | public class XLog {
method init (line 37) | public static void init(boolean showLog){
method init (line 41) | public static void init(boolean showLog,String tag){
method v (line 47) | public static void v() {
method v (line 51) | public static void v(Object msg) {
method v (line 55) | public static void v(String tag, Object... objects) {
method d (line 59) | public static void d() {
method d (line 63) | public static void d(Object msg) {
method d (line 67) | public static void d(String tag, Object... objects) {
method i (line 71) | public static void i() {
method i (line 75) | public static void i(Object msg) {
method i (line 79) | public static void i(String tag, Object... objects) {
method w (line 83) | public static void w() {
method w (line 87) | public static void w(Object msg) {
method w (line 91) | public static void w(String tag, Object... objects) {
method e (line 95) | public static void e() {
method e (line 99) | public static void e(Object msg) {
method e (line 103) | public static void e(String tag, Object... objects) {
method exception (line 107) | public static void exception(Exception ex){
method a (line 115) | public static void a() {
method a (line 119) | public static void a(Object msg) {
method a (line 123) | public static void a(String tag, Object... objects) {
method printLog (line 128) | private static void printLog(int type,String tagStr,Object... objects) {
method printDefault (line 150) | public static void printDefault(int type, String tag, String msg) {
method printSub (line 168) | private static void printSub(int type, String tag, String sub) {
method wrapperContent (line 193) | private static String[] wrapperContent(String tagStr, Object... object...
method getObjectsString (line 231) | private static String getObjectsString(Object... objects) {
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/widget/AdViewPager.java
class AdViewPager (line 31) | @SuppressWarnings("unused")
method handleMessage (line 80) | @Override
method AdViewPager (line 89) | public AdViewPager(Context context) {
method AdViewPager (line 93) | public AdViewPager(Context context, AttributeSet attrs) {
method init (line 98) | private void init(Context context, AttributeSet attrs) {
method setLayout (line 112) | private void setLayout(Context context) {
method setImages (line 154) | public void setImages(List<Integer> images) {
method setImagesUrl (line 170) | public void setImagesUrl(List<String> urls) {
method setPointsIsVisible (line 185) | public void setPointsIsVisible(boolean isVisible) {
method setPoinstPosition (line 198) | public void setPoinstPosition(int position) {
method initViewPager (line 209) | private void initViewPager() {
method toRealPosition (line 233) | private int toRealPosition(int position) {
method onPageScrolled (line 249) | @Override
method onPageSelected (line 254) | @Override
method onPageScrollStateChanged (line 264) | @Override
class AdPageAdapter (line 286) | private class AdPageAdapter extends PagerAdapter {
method getCount (line 288) | @Override
method isViewFromObject (line 301) | @Override
method instantiateItem (line 306) | @Override
method destroyItem (line 328) | @Override
method addPoints (line 337) | private void addPoints() {
method switchToPoint (line 359) | private void switchToPoint(final int currentPoint) {
method dispatchTouchEvent (line 367) | @Override
method startAutoPlay (line 387) | public void startAutoPlay() {
method stopAutoPlay (line 397) | public void stopAutoPlay() {
method setOnItemClickListener (line 406) | public void setOnItemClickListener(OnItemClickListener listener) {
type OnItemClickListener (line 410) | public interface OnItemClickListener {
method onItemClick (line 411) | void onItemClick(int position);
method onVisibilityChanged (line 414) | @Override
method onDetachedFromWindow (line 428) | @Override
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/widget/HeaderFloatBehavior.java
class HeaderFloatBehavior (line 18) | public class HeaderFloatBehavior extends CoordinatorLayout.Behavior<View> {
method HeaderFloatBehavior (line 23) | public HeaderFloatBehavior(Context context, AttributeSet attrs) {
method layoutDependsOn (line 29) | @Override
method onDependentViewChanged (line 38) | @Override
method getDependentView (line 67) | private View getDependentView() {
FILE: app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/widget/HeaderScrollingBehavior.java
class HeaderScrollingBehavior (line 19) | public class HeaderScrollingBehavior extends CoordinatorLayout.Behavior<...
method HeaderScrollingBehavior (line 28) | public HeaderScrollingBehavior(Context context, AttributeSet attrs) {
method isExpanded (line 34) | public boolean isExpanded() {
method layoutDependsOn (line 38) | @Override
method onLayoutChild (line 47) | @Override
method onDependentViewChanged (line 57) | @Override
method onStartNestedScroll (line 74) | @Override
method onNestedScrollAccepted (line 79) | @Override
method onNestedPreScroll (line 87) | @Override
method onNestedScroll (line 103) | @Override
method onNestedPreFling (line 118) | @Override
method onStopNestedScroll (line 123) | @Override
method onUserStopDragging (line 130) | private boolean onUserStopDragging(float velocity) {
method getDependentViewCollapsedHeight (line 163) | private float getDependentViewCollapsedHeight() {
method getDependentView (line 167) | private View getDependentView() {
method run (line 172) | @Override
FILE: refresh-java/src/main/java/gorden/refresh/JRefreshHeader.java
type JRefreshHeader (line 4) | public interface JRefreshHeader {
method succeedRetention (line 8) | long succeedRetention();
method failingRetention (line 12) | long failingRetention();
method refreshHeight (line 16) | int refreshHeight();
method maxOffsetHeight (line 20) | int maxOffsetHeight();
method onReset (line 25) | void onReset(JRefreshLayout refreshLayout);
method onPrepare (line 29) | void onPrepare(JRefreshLayout refreshLayout);
method onRefresh (line 33) | void onRefresh(JRefreshLayout refreshLayout);
method onComplete (line 38) | void onComplete(JRefreshLayout refreshLayout,boolean isSuccess);
method onScroll (line 45) | void onScroll(JRefreshLayout refreshLayout,int distance,float percent,...
FILE: refresh-java/src/main/java/gorden/refresh/JRefreshLayout.java
class JRefreshLayout (line 27) | @SuppressWarnings({"unused", "FieldCanBeLocal"})
method JRefreshLayout (line 68) | public JRefreshLayout(Context context) {
method JRefreshLayout (line 72) | public JRefreshLayout(Context context, AttributeSet attrs) {
method JRefreshLayout (line 76) | public JRefreshLayout(Context context, AttributeSet attrs, int defStyl...
method onFinishInflate (line 93) | @Override
method generateDefaultLayoutParams (line 113) | @Override
method generateLayoutParams (line 118) | @Override
method generateLayoutParams (line 123) | @Override
class LayoutParams (line 128) | @SuppressWarnings("WeakerAccess")
method LayoutParams (line 131) | public LayoutParams(Context c, AttributeSet attrs) {
method LayoutParams (line 135) | public LayoutParams(int width, int height) {
method LayoutParams (line 139) | public LayoutParams(MarginLayoutParams source) {
method LayoutParams (line 143) | public LayoutParams(ViewGroup.LayoutParams source) {
method onLayout (line 148) | @Override
method onMeasure (line 169) | @Override
method dispatchTouchEvent (line 180) | @Override
method onInterceptTouchEvent (line 199) | @Override
method requestDisallowInterceptTouchEvent (line 233) | @SuppressWarnings("StatementWithEmptyBody")
method onTouchEvent (line 244) | @Override
class RefreshGestureListener (line 258) | private class RefreshGestureListener extends GestureDetector.SimpleOnG...
method onScroll (line 259) | @Override
method onFling (line 276) | @Override
method canChildScrollUp (line 292) | private boolean canChildScrollUp() {
method onStartNestedScroll (line 296) | @Override
method onNestedScrollAccepted (line 302) | @Override
method onNestedPreScroll (line 308) | @Override
method onNestedScroll (line 318) | @Override
method onNestedPreFling (line 330) | @Override
method onNestedFling (line 349) | @Override
method onStopNestedScroll (line 360) | @Override
method computeScroll (line 369) | @Override
method calculateOffset (line 407) | private int calculateOffset(int offset) {
method moveView (line 425) | private void moveView(int offset) {
method cancelAnimator (line 454) | private void cancelAnimator() {
method onAnimationUpdate (line 464) | @Override
method finishSpinner (line 474) | private void finishSpinner() {
method animTo (line 499) | private void animTo(int target) {
type JRefreshListener (line 519) | @SuppressWarnings("WeakerAccess")
method onRefresh (line 521) | void onRefresh(JRefreshLayout refreshLayout);
type JScrollListener (line 524) | @SuppressWarnings("WeakerAccess")
method onScroll (line 532) | void onScroll(int offset, int distance, float percent, boolean refre...
method setJRefreshListener (line 538) | public void setJRefreshListener(JRefreshListener refreshListener) {
method setJScrollListener (line 542) | public void setJScrollListener(JScrollListener scrollListener) {
method setPinContent (line 546) | public void setPinContent(boolean pinContent) {
method setKeepHeaderWhenRefresh (line 550) | public void setKeepHeaderWhenRefresh(boolean keep) {
method setRefreshEnable (line 554) | public void setRefreshEnable(boolean enable) {
method setDurationOffset (line 558) | public void setDurationOffset(long duration) {
method setHeaderView (line 562) | public void setHeaderView(JRefreshHeader headerView) {
method setHeaderView (line 566) | public void setHeaderView(JRefreshHeader headerView, int width, int he...
method setHeaderView (line 573) | public void setHeaderView(JRefreshHeader headerView, LayoutParams para...
method getHeader (line 581) | public JRefreshHeader getHeader() {
method removeHeader (line 585) | public void removeHeader() {
method setTouchSlop (line 591) | public void setTouchSlop(int mTouchSlop) {
method setFlingSlop (line 595) | public void setFlingSlop(int mFlingSlop) {
method setHeaderOffset (line 599) | public void setHeaderOffset(int mHeaderOffset) {
method setDefaultRefreshHeight (line 603) | public void setDefaultRefreshHeight(int defaultRefreshHeight) {
method setDefaultMaxOffset (line 607) | public void setDefaultMaxOffset(int defaultMaxOffset) {
method startRefresh (line 614) | public void startRefresh() {
method refreshComplete (line 633) | public void refreshComplete(boolean isSuccess) {
Condensed preview — 103 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (361K chars).
[
{
"path": ".gitattributes",
"chars": 31,
"preview": "*.java linguist-language=kotlin"
},
{
"path": ".gitignore",
"chars": 846,
"preview": "# 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 file"
},
{
"path": "LICENSE",
"chars": 11357,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "LoadMore.md",
"chars": 1308,
"preview": "#### 为什么不将LoadMore功能集成进RefreshLayout\n* 实现效果不友好,loadMoreView加载完成后,会有个回弹效果(个人不喜欢)\n* 加载更多的触发时机不好控制(比如滚动到内容倒数几条的时候自动加载)\n---\n"
},
{
"path": "README.md",
"chars": 2954,
"preview": "# KRefreshLayout (JRefreshLayout)\nkotlin和java两个版本的下拉刷新框架,支持任意View、支持定制任意header\n## Download[ 2014 The Android Open Source Project\n *\n * Licensed under the Apache License, Version 2.0 (the \"Lice"
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/rentals/RentalsSunDrawable.java",
"chars": 10763,
"preview": "package gorden.krefreshlayout.demo.header.rentals;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimpo"
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/rentals/RentalsSunHeaderView.java",
"chars": 3522,
"preview": "package gorden.krefreshlayout.demo.header.rentals;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimpo"
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/storehouse/StoreHouseBarItem.java",
"chars": 2118,
"preview": "package gorden.krefreshlayout.demo.header.storehouse;\n\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nim"
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/storehouse/StoreHouseHeader.java",
"chars": 10769,
"preview": "package gorden.krefreshlayout.demo.header.storehouse;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\ni"
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/header/storehouse/StoreHousePath.java",
"chars": 10637,
"preview": "package gorden.krefreshlayout.demo.header.storehouse;\n\nimport android.util.SparseArray;\n\nimport java.util.ArrayList;\n\n/*"
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/MainActivity.kt",
"chars": 1637,
"preview": "package gorden.krefreshlayout.demo.ui\n\nimport android.content.Intent\nimport android.os.Bundle\nimport android.support.v7."
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/SampleActivity.kt",
"chars": 2709,
"preview": "package gorden.krefreshlayout.demo.ui\n\nimport android.app.Activity\nimport android.content.Intent\nimport android.support."
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/SettingActivity.kt",
"chars": 2476,
"preview": "package gorden.krefreshlayout.demo.ui\n\nimport android.app.Activity\nimport android.content.Intent\nimport android.os.Bundl"
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/ISampleFragment.kt",
"chars": 2442,
"preview": "package gorden.krefreshlayout.demo.ui.fragment\n\nimport android.support.v4.app.Fragment\nimport android.view.ViewGroup\nimp"
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleAFragment.kt",
"chars": 1974,
"preview": "package gorden.krefreshlayout.demo.ui.fragment\n\nimport android.os.Bundle\nimport android.support.v7.widget.DividerItemDec"
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleBFragment.kt",
"chars": 1101,
"preview": "package gorden.krefreshlayout.demo.ui.fragment\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport andro"
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleCFragment.kt",
"chars": 1112,
"preview": "package gorden.krefreshlayout.demo.ui.fragment\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport andro"
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleDFragment.kt",
"chars": 1237,
"preview": "package gorden.krefreshlayout.demo.ui.fragment\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport andro"
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleEFragment.kt",
"chars": 1225,
"preview": "package gorden.krefreshlayout.demo.ui.fragment\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport andro"
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleFFragment.kt",
"chars": 1472,
"preview": "package gorden.krefreshlayout.demo.ui.fragment\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport andro"
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleGFragment.kt",
"chars": 2094,
"preview": "package gorden.krefreshlayout.demo.ui.fragment\n\nimport android.os.Bundle\nimport android.support.v4.app.Fragment\nimport a"
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleHFragment.kt",
"chars": 2042,
"preview": "package gorden.krefreshlayout.demo.ui.fragment\n\nimport android.os.Bundle\nimport android.support.v7.widget.DividerItemDec"
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleIFragment.kt",
"chars": 1606,
"preview": "package gorden.krefreshlayout.demo.ui.fragment\n\nimport android.os.Bundle\nimport android.view.LayoutInflater\nimport andro"
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/ui/fragment/SampleJFragment.kt",
"chars": 2562,
"preview": "package gorden.krefreshlayout.demo.ui.fragment\n\nimport android.os.Bundle\nimport android.support.v7.widget.DividerItemDec"
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/util/CrashHandler.java",
"chars": 4806,
"preview": "package gorden.krefreshlayout.demo.util;\n\nimport android.content.Context;\nimport android.content.pm.PackageInfo;\nimport "
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/util/DensityUtil.java",
"chars": 634,
"preview": "package gorden.krefreshlayout.demo.util;\n\nimport android.content.res.Resources;\n\n/**\n * document\n * Created by Gordn on "
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/util/XLog.java",
"chars": 6955,
"preview": "package gorden.krefreshlayout.demo.util;\n\nimport android.text.TextUtils;\nimport android.util.Log;\n\nimport java.io.PrintW"
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/widget/AdViewPager.java",
"chars": 13512,
"preview": "package gorden.krefreshlayout.demo.widget;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimpor"
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/widget/HeaderFloatBehavior.java",
"chars": 2569,
"preview": "package gorden.krefreshlayout.demo.widget;\n\nimport android.animation.ArgbEvaluator;\nimport android.content.Context;\nimpo"
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/widget/HeaderScrollingBehavior.java",
"chars": 6482,
"preview": "package gorden.krefreshlayout.demo.widget;\n\nimport android.content.Context;\nimport android.content.res.Resources;\nimport"
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/widget/recyclerview/KLoadMoreView.kt",
"chars": 541,
"preview": "package gorden.krefreshlayout.demo.widget.recyclerview\n\ninterface KLoadMoreView {\n /**\n * 自定义适当的加载时机\n * @retu"
},
{
"path": "app_kotlin/src/main/kotlin/gorden/krefreshlayout/demo/widget/recyclerview/KRecyclerView.kt",
"chars": 8575,
"preview": "package gorden.krefreshlayout.demo.widget.recyclerview\n\nimport android.content.Context\nimport android.support.v4.util.Sp"
},
{
"path": "app_kotlin/src/main/res/drawable/bg_main.xml",
"chars": 268,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <gradient "
},
{
"path": "app_kotlin/src/main/res/drawable/selector_adpager_point.xml",
"chars": 529,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n <item a"
},
{
"path": "app_kotlin/src/main/res/layout/activity_header_list.xml",
"chars": 2268,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xm"
},
{
"path": "app_kotlin/src/main/res/layout/activity_main.xml",
"chars": 938,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xm"
},
{
"path": "app_kotlin/src/main/res/layout/activity_sample.xml",
"chars": 1911,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n an"
},
{
"path": "app_kotlin/src/main/res/layout/activity_setting.xml",
"chars": 5790,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n andr"
},
{
"path": "app_kotlin/src/main/res/layout/item_main.xml",
"chars": 519,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n andr"
},
{
"path": "app_kotlin/src/main/res/layout/item_sample.xml",
"chars": 1404,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n an"
},
{
"path": "app_kotlin/src/main/res/layout/layout_coordinatorlayout.xml",
"chars": 1866,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n xm"
},
{
"path": "app_kotlin/src/main/res/layout/layout_krecyclerview.xml",
"chars": 623,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n an"
},
{
"path": "app_kotlin/src/main/res/layout/layout_nestedscrollview.xml",
"chars": 2592,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n andro"
},
{
"path": "app_kotlin/src/main/res/layout/layout_recyclerview.xml",
"chars": 601,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n an"
},
{
"path": "app_kotlin/src/main/res/layout/layout_scrollview.xml",
"chars": 2528,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n andro"
},
{
"path": "app_kotlin/src/main/res/layout/layout_viewpager.xml",
"chars": 570,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n andr"
},
{
"path": "app_kotlin/src/main/res/layout/layout_vp_nestedscrollview.xml",
"chars": 2933,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n an"
},
{
"path": "app_kotlin/src/main/res/layout/layout_vp_scrollview.xml",
"chars": 2869,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n an"
},
{
"path": "app_kotlin/src/main/res/layout/layout_webview.xml",
"chars": 596,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n andr"
},
{
"path": "app_kotlin/src/main/res/values/attrs.xml",
"chars": 471,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <declare-styleable name=\"AdViewPager\">\n <attr name=\"ad_poi"
},
{
"path": "app_kotlin/src/main/res/values/colors.xml",
"chars": 497,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <color name=\"colorPrimary\">#3F51B5</color>\n <color name=\"color"
},
{
"path": "app_kotlin/src/main/res/values/dimens.xml",
"chars": 573,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n <dimen "
},
{
"path": "app_kotlin/src/main/res/values/strings.xml",
"chars": 609,
"preview": "<resources>\n <string name=\"app_name\">KRefreshLayout</string>\n\n <string name=\"header_scrolling_behavior\">gorden.kre"
},
{
"path": "app_kotlin/src/main/res/values/styles.xml",
"chars": 1043,
"preview": "<resources>\n\n <!-- Base application theme. -->\n <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.NoActionBar\">"
},
{
"path": "bintrayUpload.gradle",
"chars": 3963,
"preview": "apply plugin: 'com.jfrog.bintray'\napply plugin: 'com.github.dcendents.android-maven'\napply plugin: 'org.jetbrains.dokka-"
},
{
"path": "build.gradle",
"chars": 907,
"preview": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\n\nbuildscript {\n e"
},
{
"path": "refresh-java/.gitignore",
"chars": 7,
"preview": "/build\n"
},
{
"path": "refresh-java/build.gradle",
"chars": 728,
"preview": "apply plugin: 'com.android.library'\n\nandroid {\n compileSdkVersion 27\n buildToolsVersion \"27.0.1\"\n defaultConfig"
},
{
"path": "refresh-java/proguard-rules.pro",
"chars": 916,
"preview": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in D:"
},
{
"path": "refresh-java/project.properties",
"chars": 282,
"preview": "#project\nproject.name=JRefreshLayout\nproject.groupId=gorden.refresh\nproject.artifactId=refresh-java\nproject.packaging=aa"
},
{
"path": "refresh-java/src/main/AndroidManifest.xml",
"chars": 37,
"preview": "<manifest package=\"gorden.refresh\"/>\n"
},
{
"path": "refresh-java/src/main/java/gorden/refresh/JRefreshHeader.java",
"chars": 921,
"preview": "package gorden.refresh;\n\n\npublic interface JRefreshHeader {\n /**\n * 刷新成功停滞时间\n */\n long succeedRetention();"
},
{
"path": "refresh-java/src/main/java/gorden/refresh/JRefreshLayout.java",
"chars": 23610,
"preview": "package gorden.refresh;\n\nimport android.animation.ValueAnimator;\nimport android.content.Context;\nimport android.content."
},
{
"path": "refresh-java/src/main/res/values/jattr.xml",
"chars": 552,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <declare-styleable name=\"JRefreshLayout\">\n <attr name=\"j_p"
},
{
"path": "refresh-kotlin/.gitignore",
"chars": 7,
"preview": "/build\n"
},
{
"path": "refresh-kotlin/build.gradle",
"chars": 757,
"preview": "apply plugin: 'com.android.library'\napply plugin: 'kotlin-android'\napply plugin: 'kotlin-android-extensions'\n\nandroid {\n"
},
{
"path": "refresh-kotlin/proguard-rules.pro",
"chars": 916,
"preview": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in D:"
},
{
"path": "refresh-kotlin/project.properties",
"chars": 286,
"preview": "#project\nproject.name=KRefreshLayout\nproject.groupId=gorden.refresh\nproject.artifactId=refresh-kotlin\nproject.packaging="
},
{
"path": "refresh-kotlin/src/main/AndroidManifest.xml",
"chars": 37,
"preview": "<manifest package=\"gorden.refresh\"/>\n"
},
{
"path": "refresh-kotlin/src/main/kotlin/gorden/refresh/KRefreshHeader.kt",
"chars": 948,
"preview": "package gorden.refresh\n\ninterface KRefreshHeader {\n /**\n * 刷新成功停滞时间\n */\n fun succeedRetention(): Long\n "
},
{
"path": "refresh-kotlin/src/main/kotlin/gorden/refresh/KRefreshLayout.kt",
"chars": 20582,
"preview": "package gorden.refresh\n\nimport android.animation.ValueAnimator\nimport android.annotation.SuppressLint\nimport android.con"
},
{
"path": "refresh-kotlin/src/main/res/values/kattr.xml",
"chars": 555,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n <declare-styleable name=\"KRefreshLayout\">\n <attr name=\"k_p"
},
{
"path": "settings.gradle",
"chars": 71,
"preview": "include ':app_kotlin', ':refresh-kotlin', ':refresh-java', ':app_java'\n"
}
]
About this extraction
This page contains the full source code of the XiaoQiWen/KRefreshLayout GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 103 files (326.7 KB), approximately 79.9k tokens, and a symbol index with 532 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.