Commit bc25d7a6 by chengchong

Initial commit

parent 103093f3
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
<option value="$PROJECT_DIR$" /> <option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/FastBleLib" /> <option value="$PROJECT_DIR$/FastBleLib" />
<option value="$PROJECT_DIR$/app" /> <option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/library" />
</set> </set>
</option> </option>
<option name="resolveModulePerSourceSet" value="false" /> <option name="resolveModulePerSourceSet" value="false" />
......
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
\ No newline at end of file
apply plugin: 'com.android.library' apply plugin: 'com.android.library'
android { android {
compileSdkVersion 26 compileSdkVersion 30
buildToolsVersion '26.0.2' buildToolsVersion "30.0.2"
defaultConfig { defaultConfig {
minSdkVersion 14 minSdkVersion 14
......
-keep class java.util.function.ToDoubleFunction {
double applyAsDouble(java.lang.Object);
}
-keep class j$.util.Map { *; }
-keep class java.util.function.Function { *; }
-keep class j$.util.function.ToLongFunction { *; }
-keep class j$.util.function.BiConsumer { *; }
-keep class java.util.function.ToLongFunction {
long applyAsLong(java.lang.Object);
}
-keep class j$.util.function.Function { *; }
-keep class java.util.function.ToIntFunction {
int applyAsInt(java.lang.Object);
}
-keep class j$.util.function.ToDoubleFunction { *; }
-keep class j$.util.function.ToIntFunction { *; }
-keep class j$.util.Map$-CC {
boolean $default$replace(java.util.Map, java.lang.Object, java.lang.Object, java.lang.Object);
void $default$forEach(java.util.Map, j$.util.function.BiConsumer);
java.lang.Object $default$computeIfAbsent(java.util.Map, java.lang.Object, j$.util.function.Function);
java.lang.Object $default$putIfAbsent(java.util.Map, java.lang.Object, java.lang.Object);
java.lang.Object $default$getOrDefault(java.util.Map, java.lang.Object, java.lang.Object);
java.lang.Object $default$replace(java.util.Map, java.lang.Object, java.lang.Object);
java.lang.Object $default$computeIfPresent(java.util.Map, java.lang.Object, j$.util.function.BiFunction);
java.lang.Object $default$compute(java.util.Map, java.lang.Object, j$.util.function.BiFunction);
boolean $default$remove(java.util.Map, java.lang.Object, java.lang.Object);
java.lang.Object $default$merge(java.util.Map, java.lang.Object, java.lang.Object, j$.util.function.BiFunction);
void $default$replaceAll(java.util.Map, j$.util.function.BiFunction);
}
-keep class j$.util.function.BiFunction { *; }
-keep class j$.util.Comparator { *; }
-keep class java.util.function.BiConsumer { *; }
-keep class j$.util.Comparator$-CC {
java.util.Comparator $default$thenComparingLong(java.util.Comparator, j$.util.function.ToLongFunction);
java.util.Comparator $default$thenComparingDouble(java.util.Comparator, j$.util.function.ToDoubleFunction);
java.util.Comparator $default$reversed(java.util.Comparator);
java.util.Comparator $default$thenComparing(java.util.Comparator, j$.util.function.Function, java.util.Comparator);
java.util.Comparator $default$thenComparing(java.util.Comparator, j$.util.function.Function);
java.util.Comparator $default$thenComparingInt(java.util.Comparator, j$.util.function.ToIntFunction);
java.util.Comparator $default$thenComparing(java.util.Comparator, java.util.Comparator);
}
-keep class java.util.function.BiFunction {
java.util.function.BiFunction andThen(java.util.function.Function);
java.lang.Object apply(java.lang.Object, java.lang.Object);
}
-keep class java.util.function.ToDoubleFunction {
double applyAsDouble(java.lang.Object);
}
-keep class j$.util.Map { *; }
-keep class java.util.function.Function { *; }
-keep class j$.util.function.ToLongFunction { *; }
-keep class j$.util.function.BiConsumer { *; }
-keep class java.util.function.ToLongFunction {
long applyAsLong(java.lang.Object);
}
-keep class j$.util.function.Function { *; }
-keep class java.util.function.ToIntFunction {
int applyAsInt(java.lang.Object);
}
-keep class j$.util.function.ToDoubleFunction { *; }
-keep class j$.util.function.ToIntFunction { *; }
-keep class j$.util.Map$-CC {
boolean $default$replace(java.util.Map, java.lang.Object, java.lang.Object, java.lang.Object);
void $default$forEach(java.util.Map, j$.util.function.BiConsumer);
java.lang.Object $default$computeIfAbsent(java.util.Map, java.lang.Object, j$.util.function.Function);
java.lang.Object $default$putIfAbsent(java.util.Map, java.lang.Object, java.lang.Object);
java.lang.Object $default$getOrDefault(java.util.Map, java.lang.Object, java.lang.Object);
java.lang.Object $default$replace(java.util.Map, java.lang.Object, java.lang.Object);
java.lang.Object $default$computeIfPresent(java.util.Map, java.lang.Object, j$.util.function.BiFunction);
java.lang.Object $default$compute(java.util.Map, java.lang.Object, j$.util.function.BiFunction);
boolean $default$remove(java.util.Map, java.lang.Object, java.lang.Object);
java.lang.Object $default$merge(java.util.Map, java.lang.Object, java.lang.Object, j$.util.function.BiFunction);
void $default$replaceAll(java.util.Map, j$.util.function.BiFunction);
}
-keep class j$.util.function.BiFunction { *; }
-keep class j$.util.Comparator { *; }
-keep class java.util.function.BiConsumer { *; }
-keep class j$.util.Comparator$-CC {
java.util.Comparator $default$thenComparingLong(java.util.Comparator, j$.util.function.ToLongFunction);
java.util.Comparator $default$thenComparingDouble(java.util.Comparator, j$.util.function.ToDoubleFunction);
java.util.Comparator $default$reversed(java.util.Comparator);
java.util.Comparator $default$thenComparing(java.util.Comparator, j$.util.function.Function, java.util.Comparator);
java.util.Comparator $default$thenComparing(java.util.Comparator, j$.util.function.Function);
java.util.Comparator $default$thenComparingInt(java.util.Comparator, j$.util.function.ToIntFunction);
java.util.Comparator $default$thenComparing(java.util.Comparator, java.util.Comparator);
}
-keep class java.util.function.BiFunction {
java.util.function.BiFunction andThen(java.util.function.Function);
java.lang.Object apply(java.lang.Object, java.lang.Object);
}
...@@ -6,13 +6,7 @@ package com.clj.fastble; ...@@ -6,13 +6,7 @@ package com.clj.fastble;
public final class BuildConfig { public final class BuildConfig {
public static final boolean DEBUG = false; public static final boolean DEBUG = false;
public static final String LIBRARY_PACKAGE_NAME = "com.clj.fastble"; public static final String LIBRARY_PACKAGE_NAME = "com.clj.fastble";
/**
* @deprecated APPLICATION_ID is misleading in libraries. For the library package name use LIBRARY_PACKAGE_NAME
*/
@Deprecated
public static final String APPLICATION_ID = "com.clj.fastble";
public static final String BUILD_TYPE = "release"; public static final String BUILD_TYPE = "release";
public static final String FLAVOR = "";
public static final int VERSION_CODE = 232; public static final int VERSION_CODE = 232;
public static final String VERSION_NAME = "2.3.2"; public static final String VERSION_NAME = "2.3.2";
} }
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<uses-sdk <uses-sdk
android:minSdkVersion="14" android:minSdkVersion="14"
android:targetSdkVersion="22" /> android:targetSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
......
[{"outputType":{"type":"AAPT_FRIENDLY_MERGED_MANIFESTS"},"apkData":{"type":"MAIN","splits":[],"versionCode":232,"versionName":"2.3.2","enabled":true,"outputFile":"FastBleLib-release.aar","fullName":"release","baseName":"release","dirName":""},"path":"AndroidManifest.xml","properties":{"packageId":"com.clj.fastble","split":""}}] {
\ No newline at end of file "version": 1,
"applicationId": "com.clj.fastble",
"variantType": "LIBRARY",
"elements": [
{
"outputType": {
"type": "AAPT_FRIENDLY_MERGED_MANIFESTS"
},
"apkData": {
"type": "MAIN",
"splits": [],
"versionCode": 232,
"versionName": "2.3.2",
"outputFile": "FastBleLib-release.aar",
"fullName": "release",
"baseName": "release",
"dirName": ""
},
"path": "AndroidManifest.xml",
"properties": {
"packageId": "com.clj.fastble",
"split": ""
}
}
]
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<merger version="3"><dataSet config="main" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/jniLibs"/></dataSet><dataSet config="release" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/release/jniLibs"/></dataSet></merger> <merger version="3"><dataSet config="main" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="D:\androidProject\BluToysApplication\FastBleLib\src\main\jniLibs"/></dataSet><dataSet config="release" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="D:\androidProject\BluToysApplication\FastBleLib\src\release\jniLibs"/></dataSet></merger>
\ No newline at end of file \ No newline at end of file
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<merger version="3"><dataSet config="main" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/shaders"/></dataSet><dataSet config="release" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/release/shaders"/></dataSet></merger> <merger version="3"><dataSet config="main" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="D:\androidProject\BluToysApplication\FastBleLib\src\main\shaders"/></dataSet><dataSet config="release" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="D:\androidProject\BluToysApplication\FastBleLib\src\release\shaders"/></dataSet></merger>
\ No newline at end of file \ No newline at end of file
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<merger version="3"><dataSet config="main" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/assets"/><source path="/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/build/intermediates/shader_assets/release/out"/></dataSet><dataSet config="release" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/release/assets"/></dataSet></merger> <merger version="3"><dataSet config="main" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="D:\androidProject\BluToysApplication\FastBleLib\src\main\assets"/><source path="D:\androidProject\BluToysApplication\FastBleLib\build\intermediates\shader_assets\release\out"/></dataSet><dataSet config="release" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="D:\androidProject\BluToysApplication\FastBleLib\src\release\assets"/></dataSet></merger>
\ No newline at end of file \ No newline at end of file
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<merger version="3"><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="main$Generated" generated="true" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/res"/><source path="/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/build/generated/res/rs/release"/><source path="/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/build/generated/res/resValues/release"/></dataSet><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="main" generated-set="main$Generated" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/res"/><source path="/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/build/generated/res/rs/release"/><source path="/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/build/generated/res/resValues/release"/></dataSet><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="release$Generated" generated="true" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/release/res"/></dataSet><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="release" generated-set="release$Generated" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/release/res"/></dataSet><mergedItems/></merger> <merger version="3"><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="main$Generated" generated="true" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="D:\androidProject\BluToysApplication\FastBleLib\src\main\res"/><source path="D:\androidProject\BluToysApplication\FastBleLib\build\generated\res\rs\release"/><source path="D:\androidProject\BluToysApplication\FastBleLib\build\generated\res\resValues\release"/></dataSet><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="main" generated-set="main$Generated" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="D:\androidProject\BluToysApplication\FastBleLib\src\main\res"/><source path="D:\androidProject\BluToysApplication\FastBleLib\build\generated\res\rs\release"/><source path="D:\androidProject\BluToysApplication\FastBleLib\build\generated\res\resValues\release"/></dataSet><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="release$Generated" generated="true" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="D:\androidProject\BluToysApplication\FastBleLib\src\release\res"/></dataSet><dataSet aapt-namespace="http://schemas.android.com/apk/res-auto" config="release" generated-set="release$Generated" ignore_pattern="!.svn:!.git:!.ds_store:!*.scc:.*:&lt;dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~"><source path="D:\androidProject\BluToysApplication\FastBleLib\src\release\res"/></dataSet><mergedItems/></merger>
\ No newline at end of file \ No newline at end of file
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
<uses-sdk <uses-sdk
android:minSdkVersion="14" android:minSdkVersion="14"
android:targetSdkVersion="22" /> android:targetSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
......
...@@ -6,21 +6,21 @@ ...@@ -6,21 +6,21 @@
6 6
7 <uses-sdk 7 <uses-sdk
8 android:minSdkVersion="14" 8 android:minSdkVersion="14"
8-->/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml 8-->D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml
9 android:targetSdkVersion="22" /> 9 android:targetSdkVersion="30" />
9-->/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml 9-->D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml
10 10
11 <uses-permission android:name="android.permission.BLUETOOTH" /> 11 <uses-permission android:name="android.permission.BLUETOOTH" />
11-->/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:4:5-68 11-->D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:4:5-68
11-->/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:4:22-65 11-->D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:4:22-65
12 <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> 12 <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
12-->/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:5:5-74 12-->D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:5:5-74
12-->/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:5:22-71 12-->D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:5:22-71
13 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> 13 <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
13-->/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:6:5-81 13-->D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:6:5-81
13-->/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:6:22-78 13-->D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:6:22-78
14 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> 14 <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
14-->/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:7:5-79 14-->D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:7:5-79
14-->/Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:7:22-76 14-->D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:7:22-76
15 15
16</manifest> 16</manifest>
[{"outputType":{"type":"MERGED_MANIFESTS"},"apkData":{"type":"MAIN","splits":[],"versionCode":232,"versionName":"2.3.2","enabled":true,"outputFile":"FastBleLib-release.aar","fullName":"release","baseName":"release","dirName":""},"path":"../../library_manifest/release/AndroidManifest.xml","properties":{"packageId":"com.clj.fastble","split":""}}] {
\ No newline at end of file "version": 1,
"applicationId": "com.clj.fastble",
"variantType": "LIBRARY",
"elements": [
{
"outputType": {
"type": "MERGED_MANIFESTS"
},
"apkData": {
"type": "MAIN",
"splits": [],
"versionCode": 232,
"versionName": "2.3.2",
"outputFile": "FastBleLib-release.aar",
"fullName": "release",
"baseName": "release",
"dirName": ""
},
"path": "../../library_manifest/release/AndroidManifest.xml",
"properties": {
"packageId": "com.clj.fastble",
"split": ""
}
}
]
}
\ No newline at end of file
-- Merging decision tree log --- -- Merging decision tree log ---
manifest manifest
ADDED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:1:1-9:12 ADDED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:1:1-9:12
INJECTED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:1:1-9:12 INJECTED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:1:1-9:12
INJECTED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:1:1-9:12 INJECTED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:1:1-9:12
INJECTED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:1:1-9:12 INJECTED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:1:1-9:12
INJECTED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:1:1-9:12 INJECTED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:1:1-9:12
INJECTED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:1:1-9:12 INJECTED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:1:1-9:12
INJECTED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:1:1-9:12 INJECTED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:1:1-9:12
package package
ADDED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:2:5-30 ADDED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:2:5-30
INJECTED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml INJECTED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml
INJECTED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml INJECTED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml
android:versionName android:versionName
INJECTED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml INJECTED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml
ADDED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:1:1-9:12 ADDED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:1:1-9:12
INJECTED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml INJECTED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml
android:versionCode android:versionCode
INJECTED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml INJECTED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml
ADDED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:1:1-9:12 ADDED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:1:1-9:12
INJECTED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml INJECTED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml
xmlns:android xmlns:android
ADDED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:1:11-69 ADDED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:1:11-69
uses-permission#android.permission.BLUETOOTH uses-permission#android.permission.BLUETOOTH
ADDED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:4:5-68 ADDED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:4:5-68
android:name android:name
ADDED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:4:22-65 ADDED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:4:22-65
uses-permission#android.permission.BLUETOOTH_ADMIN uses-permission#android.permission.BLUETOOTH_ADMIN
ADDED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:5:5-74 ADDED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:5:5-74
android:name android:name
ADDED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:5:22-71 ADDED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:5:22-71
uses-permission#android.permission.ACCESS_COARSE_LOCATION uses-permission#android.permission.ACCESS_COARSE_LOCATION
ADDED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:6:5-81 ADDED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:6:5-81
android:name android:name
ADDED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:6:22-78 ADDED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:6:22-78
uses-permission#android.permission.ACCESS_FINE_LOCATION uses-permission#android.permission.ACCESS_FINE_LOCATION
ADDED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:7:5-79 ADDED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:7:5-79
android:name android:name
ADDED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml:7:22-76 ADDED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml:7:22-76
uses-sdk uses-sdk
INJECTED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml reason: use-sdk injection requested INJECTED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml reason: use-sdk injection requested
INJECTED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml INJECTED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml
INJECTED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml INJECTED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml
INJECTED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml INJECTED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml
INJECTED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml INJECTED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml
android:targetSdkVersion android:targetSdkVersion
INJECTED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml INJECTED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml
ADDED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml ADDED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml
INJECTED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml INJECTED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml
android:minSdkVersion android:minSdkVersion
INJECTED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml INJECTED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml
ADDED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml ADDED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml
INJECTED from /Users/liuxiaojie/Documents/work/android/bluetooth-voice/FastBleLib/src/main/AndroidManifest.xml INJECTED from D:\androidProject\BluToysApplication\FastBleLib\src\main\AndroidManifest.xml
...@@ -50,7 +50,7 @@ public class BleManager { ...@@ -50,7 +50,7 @@ public class BleManager {
public static final int DEFAULT_SCAN_TIME = 10000; public static final int DEFAULT_SCAN_TIME = 10000;
private static final int DEFAULT_MAX_MULTIPLE_DEVICE = 7; private static final int DEFAULT_MAX_MULTIPLE_DEVICE = 7;
private static final int DEFAULT_OPERATE_TIME = 5000; private static final int DEFAULT_OPERATE_TIME = 3000;
private static final int DEFAULT_CONNECT_RETRY_COUNT = 0; private static final int DEFAULT_CONNECT_RETRY_COUNT = 0;
private static final int DEFAULT_CONNECT_RETRY_INTERVAL = 5000; private static final int DEFAULT_CONNECT_RETRY_INTERVAL = 5000;
private static final int DEFAULT_MTU = 23; private static final int DEFAULT_MTU = 23;
......
...@@ -532,7 +532,7 @@ public class BleConnector { ...@@ -532,7 +532,7 @@ public class BleConnector {
bleWriteCallback.setHandler(mHandler); bleWriteCallback.setHandler(mHandler);
mBleBluetooth.addWriteCallback(uuid_write, bleWriteCallback); mBleBluetooth.addWriteCallback(uuid_write, bleWriteCallback);
mHandler.sendMessageDelayed( mHandler.sendMessageDelayed(
mHandler.obtainMessage(BleMsg.MSG_CHA_WRITE_START, bleWriteCallback), mHandler.obtainMessage(BleMsg.MSG_CHA_WRITE_RESULT, bleWriteCallback),
BleManager.getInstance().getOperateTimeout()); BleManager.getInstance().getOperateTimeout());
} }
} }
......
...@@ -62,6 +62,7 @@ dependencies { ...@@ -62,6 +62,7 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4' implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation project(path: ':FastBleLib') implementation project(path: ':FastBleLib')
implementation project(path: ':library')
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
...@@ -80,8 +81,8 @@ dependencies { ...@@ -80,8 +81,8 @@ dependencies {
implementation 'com.hjq:xxpermissions:8.6' implementation 'com.hjq:xxpermissions:8.6'
implementation "androidx.multidex:multidex:2.0.0" implementation "androidx.multidex:multidex:2.0.0"
implementation 'androidx.recyclerview:recyclerview:1.1.0'
/// implementation 'com.github.tbruyelle:rxpermissions:0.12'
...@@ -115,14 +116,13 @@ dependencies { ...@@ -115,14 +116,13 @@ dependencies {
implementation 'com.contrarywind:Android-PickerView:4.1.9' implementation 'com.contrarywind:Android-PickerView:4.1.9'
// implementation 'com.wx.wheelview:wheelview:1.3.3'
//工具类 //工具类
implementation 'com.blankj:utilcodex:1.28.0' implementation 'com.blankj:utilcodex:1.28.0'
implementation group: 'com.alibaba', name: 'fastjson', version: '1.2.73' implementation 'com.alibaba:fastjson:1.2.73'
implementation 'com.android.support:multidex:1.0.3' implementation 'androidx.multidex:multidex:2.0.0'
implementation 'com.orhanobut:logger:1.15' implementation 'com.orhanobut:logger:1.15'
implementation 'top.zibin:Luban:1.1.8' implementation 'top.zibin:Luban:1.1.8'
//implementation 'com.vise.xiaoyaoyou:baseble:2.0.5'
} }
\ No newline at end of file
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
android:name="android.permission.BLUETOOTH_PRIVILEGED" android:name="android.permission.BLUETOOTH_PRIVILEGED"
tools:ignore="ProtectedPermissions" /> tools:ignore="ProtectedPermissions" />
<uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" /> <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
<uses-permission android:name="android.permission.VIBRATE"/> <uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.FLASHLIGHT" /> <uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-feature android:name="android.hardware.camera" /> <uses-feature android:name="android.hardware.camera" />
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-feature android:name="android.hardware.location.gps" /> <uses-feature android:name="android.hardware.location.gps" />
<uses-feature <uses-feature
android:name="android.hardware.bluetooth_le" android:name="android.hardware.bluetooth_le"
...@@ -39,15 +38,17 @@ ...@@ -39,15 +38,17 @@
<application <application
android:name=".app.App" android:name=".app.App"
android:allowBackup="true" android:allowBackup="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/timerlogo"
android:label="@string/app_name" android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config" android:networkSecurityConfig="@xml/network_security_config"
android:requestLegacyExternalStorage="true" android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher" android:roundIcon="@mipmap/timerlogo"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme" android:theme="@style/AppTheme"
tools:targetApi="n"> tools:targetApi="n">
<activity android:name=".activity.SelectTimerActivity"></activity> <activity android:name=".activity.SettingMusicActivity"></activity>
<activity android:name=".activity.MusicActivity" />
<activity android:name=".activity.SelectTimerActivity" />
<activity android:name=".activity.PlayActivity" /> <activity android:name=".activity.PlayActivity" />
<activity android:name=".activity.SetTimeActivity" /> <activity android:name=".activity.SetTimeActivity" />
<activity android:name=".activity.SelectDeviceActivity" /> <activity android:name=".activity.SelectDeviceActivity" />
...@@ -61,13 +62,11 @@ ...@@ -61,13 +62,11 @@
</intent-filter> </intent-filter>
</activity> </activity>
<receiver android:name=".ble.receiver.BluetoothOpenAndClose"> <receiver android:name=".ble.receiver.BluetoothOpenAndClose">
<intent-filter> <intent-filter>
<action android:name="android.bluetooth.adapter.action.STATE_CHANGED" /> <action android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
</intent-filter> </intent-filter>
</receiver> </receiver>
</application> </application>
</manifest> </manifest>
\ No newline at end of file
package com.example.blu.toys; package com.example.blu.toys;
import android.Manifest;
import android.os.Bundle; import android.os.Bundle;
import android.widget.LinearLayout; import android.os.Handler;
import com.example.blu.toys.activity.AddDeviceActivity; import com.example.blu.toys.activity.AddDeviceActivity;
import com.example.blu.toys.activity.BaseActivity; import com.example.blu.toys.activity.BaseActivity;
import com.hjq.permissions.OnPermission;
import com.hjq.permissions.Permission;
import com.hjq.permissions.XXPermissions;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.OnClick;
public class MainActivity extends BaseActivity { public class MainActivity extends BaseActivity {
@BindView(R.id.stoplight_but)
LinearLayout stoplightBut;
String[] permissions = new String[]{
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_PHONE_STATE
};
// 声明一个集合,在后面的代码中用来存储用户拒绝授权的权
List<String> mPermissionList = new ArrayList<>();
private static final int MY_PERMISSIONS_REQUEST_CALL_PHONE = 1;
private static final int MY_PERMISSIONS_REQUEST_CALL_CAMERA = 2;
private BluetoothHelper bluetoothHelper;
@Override @Override
public int getLayout() { public int getLayout() {
...@@ -42,139 +16,15 @@ public class MainActivity extends BaseActivity { ...@@ -42,139 +16,15 @@ public class MainActivity extends BaseActivity {
@Override @Override
public void init(Bundle savedInstanceState) { public void init(Bundle savedInstanceState) {
new Handler().postDelayed(() -> {
// for (int i = 0; i < permissions.length; i++) { goActivity(AddDeviceActivity.class);
// if (ContextCompat.checkSelfPermission(MainActivity.this, permissions[i]) != PackageManager.PERMISSION_GRANTED) { finish();
// mPermissionList.add(permissions[i]); }, 1000); //延时1s执行
// }
// }
// if (mPermissionList.isEmpty()) {//未授予的权限为空,表示都授予了
// Toast.makeText(MainActivity.this, "已经授权", Toast.LENGTH_LONG).show();
// } else {//请求权限方法
// String[] permissions = mPermissionList.toArray(new String[mPermissionList.size()]);//将List转为数组
// ActivityCompat.requestPermissions(MainActivity.this, permissions, MY_PERMISSIONS_REQUEST_CALL_CAMERA);
// }
}
private void checkPermission() {
XXPermissions.with(this) // 申请安装包权限
.permission(Permission.CAMERA, Permission.ACCESS_FINE_LOCATION, Permission.ACCESS_FINE_LOCATION) // 申请多个权限
.request(new OnPermission() {
@Override
public void hasPermission(List<String> granted, boolean all) {
if (!all) {
checkPermission();
}
}
@Override
public void noPermission(List<String> denied, boolean never) {
if (never) {
XXPermissions.startPermissionActivity(MainActivity.this, denied);
} else {
checkPermission();
}
}
}
);
} }
@Override @Override
public void initData() { public void initData() {
checkPermission();
}
@OnClick(R.id.stoplight_but)
public void onViewClicked() {
goActivity(AddDeviceActivity.class);
} }
// @Override
// public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
// if (requestCode == MY_PERMISSIONS_REQUEST_CALL_PHONE) {
// if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// showToast("权限已申请");
// } else {
// showToast("权限已拒绝");
// }
// } else if (requestCode == MY_PERMISSIONS_REQUEST_CALL_CAMERA) {
// for (int i = 0; i < grantResults.length; i++) {
// if (grantResults[i] != PackageManager.PERMISSION_GRANTED) {
// //判断是否勾选禁止后不再询问
// boolean showRequestPermission = ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this, permissions[i]);
// if (showRequestPermission) {
// showToast("权限未申请");
// }
// }
// }
// }
// super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// }
//
// private void showToast(String string) {
// Toast.makeText(MainActivity.this, string, Toast.LENGTH_LONG).show();
// }
// private void checkBluetoothPermission() {
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// //校验是否已具有模糊定位权限
// if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// PermissionManager.instance().with(this).request(new OnPermissionCallback() {
// @Override
// public void onRequestAllow(String permissionName) {
// enableBluetooth();
// }
//
// @Override
// public void onRequestRefuse(String permissionName) {
// finish();
// }
//
// @Override
// public void onRequestNoAsk(String permissionName) {
// finish();
// }
// }, Manifest.permission.ACCESS_COARSE_LOCATION);
// } else {
// enableBluetooth();
// }
// } else {
// enableBluetooth();
// }
// }
//
// private void enableBluetooth() {
// if (!BleUtil.isBleEnable(this)) {
// BleUtil.enableBluetooth(this, 1);
// } else {
// boolean isSupport = BleUtil.isSupportBle(this);
// boolean isOpenBle = BleUtil.isBleEnable(this);
// if (isSupport) {
// supportTv.setText(getString(R.string.supported));
// } else {
// supportTv.setText(getString(R.string.not_supported));
// }
// if (isOpenBle) {
// statusTv.setText(getString(R.string.on));
// } else {
// statusTv.setText(getString(R.string.off));
// }
// invalidateOptionsMenu();
// updateConnectedDevice();
// }
// }
} }
\ No newline at end of file
...@@ -19,9 +19,15 @@ import android.view.WindowManager; ...@@ -19,9 +19,15 @@ import android.view.WindowManager;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.example.blu.toys.MainActivity;
import com.example.blu.toys.app.AppManager; import com.example.blu.toys.app.AppManager;
import com.example.blu.toys.utils.Utils; import com.example.blu.toys.utils.Utils;
import com.example.blu.toys.view.WrapContentGridLayoutManager;
import com.hjq.permissions.OnPermission;
import com.hjq.permissions.Permission;
import com.hjq.permissions.XXPermissions;
import java.util.ArrayList; import java.util.ArrayList;
...@@ -32,7 +38,6 @@ import butterknife.ButterKnife; ...@@ -32,7 +38,6 @@ import butterknife.ButterKnife;
import butterknife.Unbinder; import butterknife.Unbinder;
public abstract class BaseActivity extends AppCompatActivity { public abstract class BaseActivity extends AppCompatActivity {
private Unbinder mBinder; private Unbinder mBinder;
...@@ -51,13 +56,44 @@ public abstract class BaseActivity extends AppCompatActivity { ...@@ -51,13 +56,44 @@ public abstract class BaseActivity extends AppCompatActivity {
setContentView(getLayout()); setContentView(getLayout());
// getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); // getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
AppManager.getInstance().addActivity(this); AppManager.getInstance().addActivity(this);
checkPermission();
mBinder = ButterKnife.bind(this); mBinder = ButterKnife.bind(this);
init(savedInstanceState); init(savedInstanceState);
initData(); initData();
}
private void checkPermission() {
XXPermissions.with(this) // 申请安装包权限
.permission(Permission.CAMERA, Permission.ACCESS_FINE_LOCATION, Permission.ACCESS_FINE_LOCATION) // 申请多个权限
.request(new OnPermission() {
@Override
public void hasPermission(List<String> granted, boolean all) {
if (!all) {
checkPermission();
}
}
@Override
public void noPermission(List<String> denied, boolean never) {
if (never) {
XXPermissions.startPermissionActivity(BaseActivity.this, denied);
} else {
checkPermission();
}
}
}
);
} }
protected LinearLayoutManager getLinearLayout() {
LinearLayoutManager layoutManager = new WrapContentGridLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
return layoutManager;
}
public abstract int getLayout(); public abstract int getLayout();
public abstract void init(Bundle savedInstanceState); public abstract void init(Bundle savedInstanceState);
...@@ -73,7 +109,6 @@ public abstract class BaseActivity extends AppCompatActivity { ...@@ -73,7 +109,6 @@ public abstract class BaseActivity extends AppCompatActivity {
} }
@Override @Override
protected void onDestroy() { protected void onDestroy() {
super.onDestroy(); super.onDestroy();
......
package com.example.blu.toys.activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import com.example.blu.toys.R;
import com.example.blu.toys.view.TypefaceTextView;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class MusicActivity extends BaseActivity {
@BindView(R.id.open_music)
TypefaceTextView openMusic;
@BindView(R.id.close_music)
TypefaceTextView closeMusic;
@Override
public int getLayout() {
return R.layout.activity_music;
}
@Override
public void init(Bundle savedInstanceState) {
}
@Override
public void initData() {
}
@OnClick({R.id.open_music, R.id.close_music})
public void onViewClicked(View view) {
Intent intent = new Intent(MusicActivity.this, SettingMusicActivity.class);
switch (view.getId()) {
case R.id.open_music:
intent.putExtra("musicType", "open");
break;
case R.id.close_music:
intent.putExtra("musicType", "close");
break;
}
startActivity(intent);
}
}
\ No newline at end of file
package com.example.blu.toys.activity; package com.example.blu.toys.activity;
import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View; import android.view.View;
import com.clj.fastble.callback.BleWriteCallback;
import com.clj.fastble.exception.BleException;
import com.example.blu.toys.R; import com.example.blu.toys.R;
import com.example.blu.toys.ble.BlePlay;
import com.example.blu.toys.ble.agreement.TrafficLightBean;
import com.example.blu.toys.utils.SpUtils;
import com.example.blu.toys.view.TypefaceTextView;
import com.example.blu.toys.view.WheelView;
import com.hjq.toast.ToastUtils;
import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import butterknife.OnClick; import butterknife.OnClick;
public class PlayActivity extends BaseActivity { public class PlayActivity extends BaseActivity {
@BindView(R.id.task_time)
TypefaceTextView typefaceTextView;//倒计时
private int mDay = 0;
private int mHour = 0;
private int mMin = 0;
private int mSecond = 00;// 天 ,小时,分钟,秒
private boolean isRun = true;
private Handler timeHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 1) {
computeTime();
typefaceTextView.setText(mHour + ":" + mHour + ":" + mSecond);
}
}
};
/**
* 开启倒计时
*/
private void startRun() {
new Thread(() -> {
while (isRun) {
try {
Thread.sleep(1000); // sleep 1000ms
Message message = Message.obtain();
message.what = 1;
timeHandler.sendMessage(message);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
/**
* 倒计时计算
*/
private void computeTime() {
mSecond--;
if (mSecond < 0) {
mMin--;
mSecond = 59;
if (mMin < 0) {
mMin = 59;
mHour--;
if (mHour < 0) {
// 倒计时结束
mHour = 23;
mDay--;
}
}
}
}
@Override @Override
public int getLayout() { public int getLayout() {
return R.layout.activity_play; return R.layout.activity_play;
...@@ -17,7 +92,11 @@ public class PlayActivity extends BaseActivity { ...@@ -17,7 +92,11 @@ public class PlayActivity extends BaseActivity {
@Override @Override
public void init(Bundle savedInstanceState) { public void init(Bundle savedInstanceState) {
Intent intent = getIntent();
mHour = intent.getIntExtra("hour", 0);
mMin = intent.getIntExtra("min", 0);
mSecond = intent.getIntExtra("second", 0);
startRun();
} }
@Override @Override
...@@ -28,11 +107,73 @@ public class PlayActivity extends BaseActivity { ...@@ -28,11 +107,73 @@ public class PlayActivity extends BaseActivity {
@OnClick({R.id.cancel_but, R.id.pause_but, R.id.resume_but}) @OnClick({R.id.cancel_but, R.id.pause_but, R.id.resume_but})
public void onViewClicked(View view) { public void onViewClicked(View view) {
SpUtils spUtils = SpUtils.getSpUtils(PlayActivity.this);
int close = spUtils.getSPValue("close", 1);
int open = spUtils.getSPValue("open", 10);
int alarm = spUtils.getSPValue("alarm", 1);
int green = spUtils.getSPValue("green", 1);
int brightness = spUtils.getSPValue("brightness", 50);
switch (view.getId()) { switch (view.getId()) {
case R.id.cancel_but: case R.id.cancel_but://取消 关机
case R.id.pause_but:
case R.id.resume_but:
goActivity(SelectTimerActivity.class);
TrafficLightBean trafficLightBean = new TrafficLightBean(
1, 0,
0, 0, 0, 0, 0, 0);
byte[] bytes = trafficLightBean.toByte();
BlePlay.getInstance().sendStard(bytes, new BleWriteCallback() {
@Override
public void onWriteSuccess(int current, int total, byte[] justWrite) {
ToastUtils.show("关机-发送成功");
timeHandler.removeMessages(1);
}
@Override
public void onWriteFailure(BleException exception) {
}
});
case R.id.pause_but://暂停
int time = mHour * 360 + mMin * 60 + mSecond;
TrafficLightBean ttt = new TrafficLightBean(2, 0,
time, brightness, open, close, green, alarm);
byte[] bytes12 = ttt.toByte();
BlePlay.getInstance().sendPause(bytes12, new BleWriteCallback() {
@Override
public void onWriteSuccess(int current, int total, byte[] justWrite) {
ToastUtils.show("暂停-发送成功");
timeHandler.removeMessages(1);
}
@Override
public void onWriteFailure(BleException exception) {
}
});
case R.id.resume_but://开始
int hh = mHour * 360 + mMin * 60 + mSecond;
TrafficLightBean tt = new TrafficLightBean(2, 1,
hh, brightness, open, close, green, alarm);
byte[] byte11 = tt.toByte();
BlePlay.getInstance().sendStard(byte11, new BleWriteCallback() {
@Override
public void onWriteSuccess(int current, int total, byte[] justWrite) {
startRun();
ToastUtils.show("开始-发送成功");
}
@Override
public void onWriteFailure(BleException exception) {
}
});
break; break;
} }
} }
......
package com.example.blu.toys.activity; package com.example.blu.toys.activity;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log;
import androidx.annotation.RequiresApi;
import com.clj.fastble.data.BleDevice;
import com.example.blu.toys.R; import com.example.blu.toys.R;
import com.example.blu.toys.app.AppManager; import com.example.blu.toys.ble.BlePlay;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe; import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode; import org.greenrobot.eventbus.ThreadMode;
import java.util.List;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import butterknife.OnClick; import butterknife.OnClick;
public class SearchingActivity extends BaseActivity { public class SearchingActivity extends BaseActivity {
@Override @Override
public int getLayout() { public int getLayout() {
return R.layout.activity_searching; return R.layout.activity_searching;
...@@ -27,22 +33,18 @@ public class SearchingActivity extends BaseActivity { ...@@ -27,22 +33,18 @@ public class SearchingActivity extends BaseActivity {
@Override @Override
public void initData() { public void initData() {
BlePlay.getInstance().scanBle();
} }
@OnClick(R.id.select_dev) @RequiresApi(api = Build.VERSION_CODES.N)
public void onViewClicked() { @Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void GoDeviceListPage(List<BleDevice> bleDevices) {
goActivity(SelectDeviceActivity.class); goActivity(SelectDeviceActivity.class);
} }
@OnClick(R.id.back_but)
public void onViewClicked() {
@Subscribe(threadMode = ThreadMode.MAIN) finish();
public void GoDeviceListPage(String login) {
goActivity(SelectDeviceActivity.class);
} }
} }
\ No newline at end of file
package com.example.blu.toys.activity; package com.example.blu.toys.activity;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils;
import androidx.recyclerview.widget.RecyclerView;
import com.blankj.utilcode.util.CollectionUtils;
import com.blankj.utilcode.util.LogUtils;
import com.clj.fastble.data.BleDevice;
import com.example.blu.toys.R; import com.example.blu.toys.R;
import com.example.blu.toys.adapter.BleDeviceAdapter;
import com.example.blu.toys.ble.BlePlay;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import butterknife.ButterKnife; import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.OnClick; import butterknife.OnClick;
public class SelectDeviceActivity extends BaseActivity { public class SelectDeviceActivity extends BaseActivity {
@BindView(R.id.recyclerView)
RecyclerView mRecyclerView;
BleDeviceAdapter bleDeviceAdapter;
private List<BleDevice> bleDevices;
@Override @Override
public int getLayout() { public int getLayout() {
return R.layout.activity_seleclt_device; return R.layout.activity_seleclt_device;
...@@ -16,17 +37,58 @@ public class SelectDeviceActivity extends BaseActivity { ...@@ -16,17 +37,58 @@ public class SelectDeviceActivity extends BaseActivity {
@Override @Override
public void init(Bundle savedInstanceState) { public void init(Bundle savedInstanceState) {
EventBus.getDefault().register(this);
} }
@Override @Override
public void initData() { public void initData() {
if (bleDevices == null) {
bleDevices = new ArrayList<>();
}
mRecyclerView.setLayoutManager(getLinearLayout());
bleDeviceAdapter = new BleDeviceAdapter(R.layout.ble_devices_item, bleDevices);
mRecyclerView.setAdapter(bleDeviceAdapter);
bleDeviceAdapter.setOnItemClickListener((adapter, view, position) -> {
BleDevice bleDevice = (BleDevice) adapter.getItem(position);
BlePlay.getInstance().connectedBleDevice(bleDevice);
});
}
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
public void showBleDevices(List<BleDevice> bles) {
if (CollectionUtils.isEmpty(bles)) {
return;
}
if (bleDevices == null) {
bleDevices = new ArrayList<>();
}
bleDevices.clear();
for (int i = 0; i < bles.size(); i++) {
BleDevice bleDevice = bles.get(i);
String deviceName = bleDevice.getName();
if (!TextUtils.isEmpty(deviceName) && deviceName.contains("Traffic")) {
bleDevices.add(bleDevice);
}
}
if (bleDeviceAdapter != null) {
bleDeviceAdapter.notifyDataSetChanged();
}
} }
@OnClick(R.id.go_start) @Subscribe(threadMode = ThreadMode.MAIN)
public void onViewClicked() { public void connDevices(BleDevice ble) {
LogUtils.e("连接 成功");
goActivity(SetTimeActivity.class); goActivity(SetTimeActivity.class);
} }
@OnClick(R.id.back_but)
public void onViewClicked() {
finish();
}
} }
\ No newline at end of file
package com.example.blu.toys.activity; package com.example.blu.toys.activity;
import androidx.appcompat.app.AppCompatActivity; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.widget.CompoundButton;
import android.widget.SeekBar;
import android.widget.Switch;
import com.example.blu.toys.R; import com.example.blu.toys.R;
import com.example.blu.toys.utils.SpUtils;
import com.example.blu.toys.view.TypefaceTextView;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
//设置
public class SelectTimerActivity extends BaseActivity { public class SelectTimerActivity extends BaseActivity {
@BindView(R.id.back_but)
TypefaceTextView backBut;
@BindView(R.id.will)
TypefaceTextView will;
@BindView(R.id.alarm_switch)
Switch alarmSwitch;
@BindView(R.id.music_switch)
Switch musicSwitch;
@BindView(R.id.green_switch)
Switch greenSwitch;
@BindView(R.id.brightness_bar)
SeekBar brightnessBar;
@Override @Override
public int getLayout() { public int getLayout() {
return R.layout.activity_select_timer; return R.layout.activity_select_timer;
...@@ -17,10 +39,59 @@ public class SelectTimerActivity extends BaseActivity { ...@@ -17,10 +39,59 @@ public class SelectTimerActivity extends BaseActivity {
@Override @Override
public void init(Bundle savedInstanceState) { public void init(Bundle savedInstanceState) {
SpUtils spUtils = SpUtils.getSpUtils(this);
// spUtils.putSPValue("close", 1);
// spUtils.putSPValue("open", 10);
spUtils.putSPValue("brightness", 50);
alarmSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (isChecked) {
spUtils.putSPValue("alarm", 1);
} else {
spUtils.putSPValue("alarm", 0);
}
});
musicSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
startActivity(new Intent(SelectTimerActivity.this, MusicActivity.class));
});
greenSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (isChecked) {
spUtils.putSPValue("green", 1);
} else {
spUtils.putSPValue("green", 0);
}
});
brightnessBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
spUtils.putSPValue("brightness", progress);
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
} }
@Override @Override
public void initData() { public void initData() {
} }
@OnClick(R.id.back_but)
public void onViewClicked() {
finish();
}
} }
\ No newline at end of file
package com.example.blu.toys.activity; package com.example.blu.toys.activity;
import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import com.blankj.utilcode.util.LogUtils;
import com.blankj.utilcode.util.StringUtils;
import com.clj.fastble.callback.BleWriteCallback;
import com.clj.fastble.data.BleDevice;
import com.clj.fastble.exception.BleException;
import com.example.blu.toys.R; import com.example.blu.toys.R;
import com.example.blu.toys.ble.BlePlay;
import com.example.blu.toys.ble.agreement.TrafficLightBean;
import com.example.blu.toys.utils.LocalDateUtils;
import com.example.blu.toys.utils.SpUtils;
import com.example.blu.toys.view.TypefaceTextView;
import com.example.blu.toys.view.WheelView;
import com.hjq.toast.ToastUtils;
import butterknife.ButterKnife; import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import butterknife.BindView;
import butterknife.OnClick; import butterknife.OnClick;
public class SetTimeActivity extends BaseActivity { public class SetTimeActivity extends BaseActivity {
@BindView(R.id.wheel_hour)
WheelView wheelHour;
@BindView(R.id.wheel_minute)
WheelView wheelMinute;
@BindView(R.id.wheel_second)
WheelView wheelSecond;
@BindView(R.id.wheel_am_pm)
WheelView wheelAmPm;
@BindView(R.id.wheel_hour_dw)
WheelView wheelHour_dw;
@BindView(R.id.wheel_minute_dw)
WheelView wheelMinute_dw;
@BindView(R.id.wheel_second_dw)
WheelView wheelSecond_dw;
@BindView(R.id.back_but)
TypefaceTextView backBut;
@BindView(R.id.center)
LinearLayout center;
@BindView(R.id.start_but)
RelativeLayout startBut;
@BindView(R.id.will)
TypefaceTextView will;
private ArrayList<String> hourList = new ArrayList<>();
private ArrayList<String> minuteList = new ArrayList<>();
private ArrayList<String> secondList = new ArrayList<>();
private ArrayList<String> amPmList = new ArrayList<>();
private int amOrPm = 0;
String selectHour;
String selectMin;
String selectSec;
String selectHour_dw;
String selectMin_dw;
String selectSec_dw;
int hour = 0;
int min = 0;
int second = 0;
@Override @Override
public int getLayout() { public int getLayout() {
return R.layout.activity_set_time; return R.layout.activity_set_time;
...@@ -17,16 +87,397 @@ public class SetTimeActivity extends BaseActivity { ...@@ -17,16 +87,397 @@ public class SetTimeActivity extends BaseActivity {
@Override @Override
public void init(Bundle savedInstanceState) { public void init(Bundle savedInstanceState) {
wheelHour.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
@Override
public void onSelected(int selectedIndex, String item) {
if (StringUtils.isEmpty(item)) {
//不能动
int indexHour = hourList.indexOf(selectHour);
wheelHour.setSeletion(indexHour);
return;
}
Date time = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(time);
int nowHour = calendar.get(Calendar.HOUR);//时(12小时制)
if (item.startsWith("0")) {
item = item.substring(1);
}
//获取选择的时间
Integer selectHourTime = Integer.valueOf(item);
if (selectHourTime < nowHour) {
int indexHour = hourList.indexOf(selectHour);
wheelHour.setSeletion(indexHour);
ToastUtils.show("选择的时间不能小于当前时间");
return;
}
// selectHour = item;
// //下面的小时 显示
// int dowHour = selectHourTime - nowHour;
// if (dowHour < 10) {
// selectHour_dw = "0" + dowHour;
// } else {
// selectHour_dw = String.valueOf(dowHour);
// }
// wheelHour_dw.setSeletion(hourList.indexOf(selectHour_dw));
}
});
wheelMinute.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
@Override
public void onSelected(int selectedIndex, String item) {
if (StringUtils.isEmpty(item)) {
int indexMinute = minuteList.indexOf(selectMin);
wheelMinute.setSeletion(indexMinute);
return;
}
Calendar calendar = Calendar.getInstance();
int nowHour = calendar.get(Calendar.HOUR);//时(12小时制)
int nowMin = calendar.get(Calendar.MINUTE);
String currentSelectHour;
if (selectHour.startsWith("0")) {
currentSelectHour = item.substring(1);
} else {
currentSelectHour = selectHour;
}
Integer selectHourTime = Integer.valueOf(currentSelectHour);
if (selectHourTime < nowHour) {
ToastUtils.show("选择的时间不能小于当前时间");
return;
}
if (selectHourTime > nowHour) {
selectMin = item;
}
if (selectHourTime == nowHour) {
if (item.startsWith("0")) {
item = item.substring(1);
}
Integer selectMinTime = Integer.valueOf(item);
if (selectMinTime < nowMin) {
int indexMinute = minuteList.indexOf(selectMin);
wheelMinute.setSeletion(indexMinute);
ToastUtils.show("选择的时间不能小于当前时间");
} else {
selectMin = item;
}
}
if (selectMin.startsWith("0")) {
item = item.substring(1);
}
Integer selectMinTime = Integer.valueOf(item);
//设置下面的时间
// int dowMin = selectMinTime - nowMin;
// if (dowMin < 10) {
// selectMin_dw = "0" + dowMin;
// } else {
// selectMin_dw = String.valueOf(dowMin);
// }
//
// wheelMinute_dw.setSeletion(minuteList.indexOf(selectMin_dw));
}
});
//秒的选择
wheelSecond.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
@Override
public void onSelected(int selectedIndex, String item) {
if (StringUtils.isEmpty(item)) {
int indexSecond = secondList.indexOf(selectSec);
wheelSecond.setSeletion(indexSecond);
return;
}
Date time = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(time);
int nowHour = calendar.get(Calendar.HOUR);//时(12小时制)
int nowMinute = calendar.get(Calendar.MINUTE);//分
int nowSecond = calendar.get(Calendar.SECOND);
String currentHour;
if (selectHour.startsWith("0")) {
currentHour = item.substring(1);
} else {
currentHour = selectHour;
}
Integer currentSelectHour = Integer.valueOf(currentHour);
String currentMin;
if (selectMin.startsWith("0")) {
currentMin = item.substring(1);
} else {
currentMin = selectMin;
}
Integer currentSelectMin = Integer.valueOf(currentMin);
//当小时大于当前的时间
if (currentSelectHour >= nowHour) {
if (currentSelectMin > nowMinute) {
selectSec = item;
}
if (currentSelectMin == nowMinute) {
String sec;
if (item.startsWith("0")) {
sec = item.substring(1);
} else {
sec = item;
}
Integer selectSecTime = Integer.valueOf(sec);
//计算秒
if (selectSecTime < nowSecond) {
int indexSec = secondList.indexOf(selectMin);
wheelSecond.setSeletion(indexSec);
ToastUtils.show("选择的时间不能小于当前时间");
} else {
selectMin = item;
}
//
// int dowSec = selectSecTime - nowSecond;
// if (dowSec < 10) {
// selectSec_dw = "0" + dowSec;
// } else {
// selectSec_dw = String.valueOf(dowSec);
// }
//
// wheelSecond_dw.setSeletion(secondList.indexOf(selectSec_dw));
}
} else {
ToastUtils.show("选择的时间不能小于当前时间");
}
}
});
wheelHour_dw.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
@Override
public void onSelected(int selectedIndex, String item) {
selectHour_dw = hourList.get(selectedIndex);
}
});
wheelMinute_dw.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
@Override
public void onSelected(int selectedIndex, String item) {
selectMin_dw = minuteList.get(selectedIndex);
}
});
wheelSecond_dw.setOnWheelViewListener(new WheelView.OnWheelViewListener() {
@Override
public void onSelected(int selectedIndex, String item) {
selectSec_dw = secondList.get(selectedIndex);
}
});
} }
@Override @Override
public void initData() { public void initData() {
Date time = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(time);
int hour = calendar.get(Calendar.HOUR);//时(12小时制)
int minute = calendar.get(Calendar.MINUTE);//分
int second = calendar.get(Calendar.SECOND);
int currTime = LocalDateUtils.getHour(time);
if (currTime > 12) {
amOrPm = 1;
} else {
amOrPm = 0;
}
hourList.clear();
minuteList.clear();
secondList.clear();
amPmList.add("AM");
amPmList.add("PM");
hourList.add("00");
for (int i = 1; i <= 12; i++) {
if (i < 10) {
hourList.add("0" + i);
} else {
hourList.add(String.valueOf(i));
}
}
for (int i = 0; i <= 59; i++) {
if (i < 10) {
minuteList.add("0" + i);
secondList.add("0" + i);
} else {
minuteList.add(String.valueOf(i));
secondList.add(String.valueOf(i));
}
}
///时////
wheelHour.setOffset(3);
wheelHour.setItems(hourList);
if (hour < 10) {
selectHour = "0" + hour;
} else {
selectHour = String.valueOf(hour);
}
int indexHour = hourList.indexOf(selectHour);
wheelHour.setSeletion(indexHour);
///分////
wheelMinute.setOffset(3);// 对话框中当前项上面和下面的项数
wheelMinute.setItems(minuteList);// 设置数据源
if (minute < 10) {
selectMin = "0" + minute;
} else {
selectMin = String.valueOf(minute);
}
int indexMinute = minuteList.indexOf(selectMin);
wheelMinute.setSeletion(indexMinute);// 默认选中第三项
///秒////
wheelSecond.setOffset(3);
wheelSecond.setItems(secondList);// 设置数据源
if (second < 10) {
selectSec = "0" + second;
} else {
selectSec = String.valueOf(second);
}
int indexSecond = secondList.indexOf(selectSec);
wheelSecond.setSeletion(indexSecond);
wheelAmPm.setOffset(2);// 对话框中当前项上面和下面的项数
wheelAmPm.setItems(amPmList);// 设置数据源
wheelAmPm.setSeletion(amOrPm);// 默认选中第三项
/////////下////////
///时////
wheelHour_dw.setOffset(3);
wheelHour_dw.setItems(hourList);
wheelHour_dw.setSeletion(0);
///分////
wheelMinute_dw.setOffset(3);// 对话框中当前项上面和下面的项数
wheelMinute_dw.setItems(minuteList);// 设置数据源
wheelMinute_dw.setSeletion(0);// 默认选中第三项
///秒////
wheelSecond_dw.setOffset(3);
wheelSecond_dw.setItems(secondList);
wheelSecond_dw.setSeletion(0);
} }
@OnClick(R.id.start_but) @Subscribe(threadMode = ThreadMode.MAIN)
public void onViewClicked() { public void setBleDevice(BleDevice ble) {
goActivity(PlayActivity.class); LogUtils.e("连接 成功-----开机");
}
@OnClick({R.id.back_but, R.id.start_but})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.back_but:
BlePlay.getInstance().closeBle();
finish();
break;
case R.id.start_but:
boolean bleOpen = BlePlay.getInstance().isBleOpen();
if (!bleOpen) {
ToastUtils.show("请打开蓝牙");
return;
}
if (TextUtils.isEmpty(selectHour_dw)) {
hour = 0;
} else if (selectHour_dw.startsWith("0")) {
selectHour_dw = selectHour_dw.substring(1);
hour = Integer.valueOf(selectHour_dw);
}
if (TextUtils.isEmpty(selectMin_dw)) {
min = 0;
} else if (selectMin_dw.startsWith("0")) {
selectMin_dw = selectMin_dw.substring(1);
min = Integer.valueOf(selectMin_dw);
}
if (TextUtils.isEmpty(selectSec_dw)) {
second = 0;
} else if (selectSec_dw.startsWith("0")) {
selectSec_dw = selectSec_dw.substring(1);
second = Integer.valueOf(selectSec_dw);
}
//转换成秒 0000000000000000
int time = hour * 360 + min * 60 + second;
SpUtils spUtils = SpUtils.getSpUtils(SetTimeActivity.this);
int close = spUtils.getSPValue("close", 1);
int open = spUtils.getSPValue("open", 10);
int alarm = spUtils.getSPValue("alarm", 1);
int green = spUtils.getSPValue("green", 1);
int brightness = spUtils.getSPValue("brightness", 50);
TrafficLightBean trafficLightBean = new TrafficLightBean(
2, 1,
time, brightness, open, close, green, alarm);
byte[] bytes = trafficLightBean.toByte();
BlePlay.getInstance().sendStard(bytes, new BleWriteCallback() {
@Override
public void onWriteSuccess(int current, int total, byte[] justWrite) {
Intent intent = new Intent(SetTimeActivity.this, PlayActivity.class);
intent.putExtra("hour", hour);
intent.putExtra("min", min);
intent.putExtra("second", second);
startActivity(intent);
}
@Override
public void onWriteFailure(BleException exception) {
}
});
break;
}
} }
} }
\ No newline at end of file
package com.example.blu.toys.activity;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.RecyclerView;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.clj.fastble.data.BleDevice;
import com.example.blu.toys.R;
import com.example.blu.toys.adapter.BleDeviceAdapter;
import com.example.blu.toys.adapter.MusicAdapter;
import com.example.blu.toys.utils.SpUtils;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
public class SettingMusicActivity extends BaseActivity {
@BindView(R.id.recyclerView)
RecyclerView mRecyclerView;
MusicAdapter musicAdapter;
private List<Integer> integerList;
private SpUtils spUtils;
@Override
public int getLayout() {
return R.layout.activity_setting_music;
}
@Override
public void init(Bundle savedInstanceState) {
spUtils = SpUtils.getSpUtils(SettingMusicActivity.this);
Intent intent = getIntent();
String musicType = intent.getStringExtra("musicType");
integerList = new ArrayList<>();
for (int i = 0; i < 20; i++) {
integerList.add(i);
}
mRecyclerView.setLayoutManager(getLinearLayout());
musicAdapter = new MusicAdapter(R.layout.ble_devices_item, integerList, musicType);
mRecyclerView.setAdapter(musicAdapter);
musicAdapter.setOnItemClickListener((adapter, view, position) -> {
Integer integer = integerList.get(position);
if (musicType.equals("close")) {
spUtils.putSPValue("close", integer);
} else {
spUtils.putSPValue("open", integer);
}
});
}
@Override
public void initData() {
}
}
\ No newline at end of file
package com.example.blu.toys.adapter;
import android.text.TextUtils;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.clj.fastble.data.BleDevice;
import com.example.blu.toys.R;
import java.util.List;
public class BleDeviceAdapter extends BaseQuickAdapter<BleDevice, BaseViewHolder> {
public BleDeviceAdapter(int layoutResId, List<BleDevice> data) {
super(layoutResId, data);
}
@Override
protected void convert(BaseViewHolder helper, BleDevice item) {
String deviceName = item.getName();
if (!TextUtils.isEmpty(deviceName) && deviceName.contains("Traffic")) {
helper.setText(R.id.dv_name, item.getName() + "");
}
}
}
\ No newline at end of file
package com.example.blu.toys.adapter;
import android.text.TextUtils;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.clj.fastble.data.BleDevice;
import com.example.blu.toys.R;
import com.example.blu.toys.utils.SpUtils;
import java.util.List;
public class MusicAdapter extends BaseQuickAdapter<Integer, BaseViewHolder> {
private String musicType;
public MusicAdapter(int layoutResId, List<Integer> data, String musicType) {
super(layoutResId, data);
this.musicType = musicType;
}
@Override
protected void convert(BaseViewHolder helper, Integer item) {
SpUtils spUtils = SpUtils.getSpUtils(mContext);
int spValue = spUtils.getSPValue(musicType, -1);
if (spValue == item) {
helper.setTextColor(R.id.dv_name, mContext.getResources().getColor(R.color.backer_back));
}
helper.setText(R.id.dv_name, item + "");
}
}
\ No newline at end of file
...@@ -5,6 +5,7 @@ import android.app.Application; ...@@ -5,6 +5,7 @@ import android.app.Application;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import com.clj.fastble.BleManager; import com.clj.fastble.BleManager;
import com.example.blu.toys.utils.SpUtils;
import com.hjq.toast.ToastUtils; import com.hjq.toast.ToastUtils;
public class App extends Application { public class App extends Application {
...@@ -39,39 +40,15 @@ public class App extends Application { ...@@ -39,39 +40,15 @@ public class App extends Application {
.enableLog(true) .enableLog(true)
.setReConnectCount(3, 5000) .setReConnectCount(3, 5000)
.setMaxConnectCount(7) .setMaxConnectCount(7)
.setConnectOverTime(50000) .setSplitWriteNum(50000)
.setOperateTimeout(50000); .setConnectOverTime(50000);
SpUtils spUtils = SpUtils.getSpUtils(this);
// DoohanBle.getInstance().init(this); spUtils.putSPValue("close",1);
// DoohanBle.config().setScanTimeout(5000)//扫描超时时间,这里设置为永久扫描 spUtils.putSPValue("open",10);
// .setConnectTimeout(10 * 1000)//连接超时时间 spUtils.putSPValue("alarm",1);
// .setOperateTimeout(5 * 1000)//设置数据操作超时时间 spUtils.putSPValue("green",1);
// .setConnectRetryCount(5)//设置连接失败重试次数 spUtils.putSPValue("brightness",50);
// .setConnectRetryInterval(1000)//设置连接失败重试间隔时间
// .setOperateRetryCount(3)//设置数据操作失败重试次数
// .setOperateRetryInterval(1000)//设置数据操作失败重试间隔时间
// .setServiceUUID("0000fff0-0000-1000-8000-00805f9b34fb")
// .setNotifyUUID("0000fff4-0000-1000-8000-00805f9b34fb")
// .setWriteUUID("0000fff3-0000-1000-8000-00805f9b34fb");
// //蓝牙相关配置修改
// ViseBle.config()
// .setScanTimeout(-1)//扫描超时时间,这里设置为永久扫描
// .setConnectTimeout(10 * 1000)//连接超时时间
// .setOperateTimeout(5 * 1000)//设置数据操作超时时间
// .setConnectRetryCount(3)//设置连接失败重试次数
// .setConnectRetryInterval(1000)//设置连接失败重试间隔时间
// .setOperateRetryCount(3)//设置数据操作失败重试次数
// .setOperateRetryInterval(1000)//设置数据操作失败重试间隔时间
// .setMaxConnectCount(3);//设置最大连接设备数量
////蓝牙信息初始化,全局唯一,必须在应用初始化时调用
// ViseBle.getInstance().init(this);
} }
public static App getInstance() { public static App getInstance() {
......
package com.example.blu.toys.ble.receiver; package com.example.blu.toys.ble;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import com.blankj.utilcode.util.LogUtils; import com.blankj.utilcode.util.LogUtils;
import com.clj.fastble.BleManager; import com.clj.fastble.BleManager;
...@@ -12,68 +14,92 @@ import com.clj.fastble.data.BleDevice; ...@@ -12,68 +14,92 @@ import com.clj.fastble.data.BleDevice;
import com.clj.fastble.exception.BleException; import com.clj.fastble.exception.BleException;
import com.clj.fastble.scan.BleScanRuleConfig; import com.clj.fastble.scan.BleScanRuleConfig;
import com.example.blu.toys.app.App; import com.example.blu.toys.app.App;
import com.example.blu.toys.ble.Notify; import com.example.blu.toys.ble.agreement.HexStringUtils;
import com.example.blu.toys.utils.SpUtils; import com.example.blu.toys.utils.SpUtils;
import org.greenrobot.eventbus.EventBus; import org.greenrobot.eventbus.EventBus;
import java.util.List; import java.util.List;
import java.util.UUID;
@SuppressWarnings("all") @SuppressWarnings("all")
public class VehiclePlay { public class BlePlay {
String UUID_SERVICE = "00001812-0000-1000-8000-00805f9b34fb"; // String UUID_SERVICE = "00001812-0000-1000-8000-00805f9b34fb";
String UUID_WRITE = "0000180f-0000-1000-8000-00805f9b34fb"; // String UUID_WRITE = "0000180f-0000-1000-8000-00805f9b34fb";
//
// String UUID_READ = "0000ae02-0000-1000-8000-00805f9b34fb";
//
//
// UUID[] serviceIds = {UUID.fromString("49535343-fe7d-4ae5-8fa9-9fafd205e455"),
// UUID.fromString("0000ffe0-0000-1000-8000-00805f9b34fb"),
// UUID.fromString("00001812-0000-1000-8000-00805f9b34fb")};
String UUID_NOTIFY = "0000ae02-0000-1000-8000-00805f9b34fb";
String UUID_SERVICE = "0000ffe0-0000-1000-8000-00805f9b34fb";
String UUID_WRITE = "0000ff4-0000-1000-8000-00805f9b34fb";
String UUID_READ = "0000ffe5-0000-1000-8000-00805f9b34fb";
private static VehiclePlay instance;
private static BlePlay instance;
private SpUtils mSpUtils; private SpUtils mSpUtils;
public static VehiclePlay getInstance() { public static BlePlay getInstance() {
if (instance == null) { if (instance == null) {
synchronized (VehiclePlay.class) { synchronized (BlePlay.class) {
if (instance == null) { if (instance == null) {
instance = new VehiclePlay(); instance = new BlePlay();
} }
} }
} }
return instance; return instance;
} }
private BleDevice bleDevice;
private VehiclePlay() { private BlePlay() {
mSpUtils = SpUtils.getSpUtils(App.getInstance()); mSpUtils = SpUtils.getSpUtils(App.getInstance());
} }
public void scanBle() { public BleDevice getBleDevice() {
return bleDevice;
}
public void setBleDevice(BleDevice bleDevice) {
this.bleDevice = bleDevice;
}
BleScanRuleConfig scanRuleConfig = new BleScanRuleConfig.Builder()
.setAutoConnect(false)
.setScanTimeOut(30000)
.build();
BleManager.getInstance().initScanRule(scanRuleConfig);
/**
* 扫描设备 30000
*/
public void scanBle() {
BleScanRuleConfig scanRuleConfig = new BleScanRuleConfig.Builder().setAutoConnect(false)
//.setServiceUuids(serviceIds)
.setScanTimeOut(1000).build();
BleManager.getInstance().initScanRule(scanRuleConfig);
BleManager.getInstance().scan(new BleScanCallback() { BleManager.getInstance().scan(new BleScanCallback() {
@Override @Override
public void onScanStarted(boolean success) { public void onScanStarted(boolean success) {
LogUtils.e("===========0000"); LogUtils.e("开始扫描");
} }
@Override @Override
public void onScanning(BleDevice bleDevice) { public void onScanning(BleDevice bleDevice) {
LogUtils.e("获取设备");
} }
@Override @Override
public void onScanFinished(List<BleDevice> scanResultList) { public void onScanFinished(List<BleDevice> scanResultList) {
EventBus.getDefault().post(scanResultList); LogUtils.e("扫描介素获取设备列表");
EventBus.getDefault().postSticky(scanResultList);
} }
}); });
} }
...@@ -98,7 +124,6 @@ public class VehiclePlay { ...@@ -98,7 +124,6 @@ public class VehiclePlay {
* @param bleDevice 设备 * @param bleDevice 设备
*/ */
public void connectedBleDevice(BleDevice bleDevice) { public void connectedBleDevice(BleDevice bleDevice) {
BleManager.getInstance().connect(bleDevice, new BleGattCallback() { BleManager.getInstance().connect(bleDevice, new BleGattCallback() {
//开始链接 //开始链接
...@@ -116,7 +141,32 @@ public class VehiclePlay { ...@@ -116,7 +141,32 @@ public class VehiclePlay {
//链接成功 //链接成功
@Override @Override
public void onConnectSuccess(BleDevice bleDevice, BluetoothGatt gatt, int status) { public void onConnectSuccess(BleDevice bleDevice, BluetoothGatt gatt, int status) {
setBleDevice(bleDevice);
List<BluetoothGattService> serviceList = gatt.getServices();
for (BluetoothGattService service : serviceList) {
UUID uuid_service = service.getUuid();
if (UUID_SERVICE.equals(uuid_service)){}
LogUtils.e("uuid_service----" + uuid_service);
List<BluetoothGattCharacteristic> characteristicList = service.getCharacteristics();
for (BluetoothGattCharacteristic characteristic : characteristicList) {
UUID uuid_chara = characteristic.getUuid();
int properties = characteristic.getProperties();
LogUtils.e("uuid_chara----" + uuid_service);
}
}
EventBus.getDefault().post(bleDevice);
} }
//关闭链接 //关闭链接
...@@ -132,7 +182,7 @@ public class VehiclePlay { ...@@ -132,7 +182,7 @@ public class VehiclePlay {
/** /**
* 暂停 * 暂停
*/ */
public void sendCance(BleDevice bleDevice, byte[] data) { public void sendCance(byte[] data,BleWriteCallback callback) {
BleManager.getInstance().write( BleManager.getInstance().write(
bleDevice, bleDevice,
UUID_SERVICE, UUID_SERVICE,
...@@ -141,12 +191,12 @@ public class VehiclePlay { ...@@ -141,12 +191,12 @@ public class VehiclePlay {
new BleWriteCallback() { new BleWriteCallback() {
@Override @Override
public void onWriteSuccess(int current, int total, byte[] justWrite) { public void onWriteSuccess(int current, int total, byte[] justWrite) {
callback.onWriteSuccess(current,total,justWrite);
} }
@Override @Override
public void onWriteFailure(BleException exception) { public void onWriteFailure(BleException exception) {
callback.onWriteFailure(exception);
} }
}); });
...@@ -156,24 +206,19 @@ public class VehiclePlay { ...@@ -156,24 +206,19 @@ public class VehiclePlay {
/** /**
* 开始/继续 * 开始/继续
*/ */
public void sendStard(BleDevice bleDevice, byte[] data) { public void sendStard(byte[] data,BleWriteCallback callback) {
BleManager.getInstance().write( BleManager.getInstance().write(bleDevice, UUID_SERVICE, UUID_WRITE, data, new BleWriteCallback() {
bleDevice, @Override
UUID_SERVICE, public void onWriteSuccess(int current, int total, byte[] justWrite) {
UUID_WRITE, callback.onWriteSuccess(current,total,justWrite);
data,
new BleWriteCallback() {
@Override
public void onWriteSuccess(int current, int total, byte[] justWrite) {
}
@Override
public void onWriteFailure(BleException exception) {
} }
});
@Override
public void onWriteFailure(BleException exception) {
callback.onWriteFailure(exception);
}
});
} }
...@@ -181,7 +226,7 @@ public class VehiclePlay { ...@@ -181,7 +226,7 @@ public class VehiclePlay {
/** /**
* 暂停 * 暂停
*/ */
public void sendPause(BleDevice bleDevice, byte[] data) { public void sendPause(byte[] data,BleWriteCallback callback) {
BleManager.getInstance().write( BleManager.getInstance().write(
bleDevice, bleDevice,
UUID_SERVICE, UUID_SERVICE,
...@@ -190,12 +235,12 @@ public class VehiclePlay { ...@@ -190,12 +235,12 @@ public class VehiclePlay {
new BleWriteCallback() { new BleWriteCallback() {
@Override @Override
public void onWriteSuccess(int current, int total, byte[] justWrite) { public void onWriteSuccess(int current, int total, byte[] justWrite) {
callback.onWriteSuccess(current,total,justWrite);
} }
@Override @Override
public void onWriteFailure(BleException exception) { public void onWriteFailure(BleException exception) {
callback.onWriteFailure(exception);
} }
}); });
...@@ -216,14 +261,14 @@ public class VehiclePlay { ...@@ -216,14 +261,14 @@ public class VehiclePlay {
* *
* @rturn * @rturn
*/ */
public boolean isConnected(BleDevice bleDevice) { public boolean isConnected() {
return BleManager.getInstance().isConnected(bleDevice); return BleManager.getInstance().isConnected(bleDevice);
} }
/** /**
* 断开蓝牙链接 * 断开蓝牙链接
*/ */
public void closeBle(BleDevice bleDevice) { public void closeBle() {
BleManager.getInstance().disconnect(bleDevice); BleManager.getInstance().disconnect(bleDevice);
} }
......
...@@ -67,11 +67,11 @@ public class TrafficLightBean { ...@@ -67,11 +67,11 @@ public class TrafficLightBean {
* @param protocolNo 协议编号 * @param protocolNo 协议编号
* @param suspendAndContinue 暂停或者继续 * @param suspendAndContinue 暂停或者继续
* @param timeRemaining 剩余时间 毫秒 * @param timeRemaining 剩余时间 毫秒
* @param brightness 亮度值 0-100 * @param brightness 亮度值 0-100 默认 50
* @param openSoundNo 开机声音编号 * @param openSoundNo 开机声音编号 默认 1
* @param closeSoundNo 关机声音编号 * @param closeSoundNo 关机声音编号 默认 10
* @param trafficLightUpdateSet 红绿灯变更方式 * @param trafficLightUpdateSet 红绿灯变更方式 默认 1
* @param alarm 报警状态 * @param alarm 报警状态 默认 0
*/ */
public TrafficLightBean(Integer protocolNo,Integer suspendAndContinue,Integer timeRemaining,Integer brightness,Integer openSoundNo,Integer closeSoundNo,Integer trafficLightUpdateSet,Integer alarm){ public TrafficLightBean(Integer protocolNo,Integer suspendAndContinue,Integer timeRemaining,Integer brightness,Integer openSoundNo,Integer closeSoundNo,Integer trafficLightUpdateSet,Integer alarm){
...@@ -107,7 +107,6 @@ public class TrafficLightBean { ...@@ -107,7 +107,6 @@ public class TrafficLightBean {
} }
public byte[] toByte(){ public byte[] toByte(){
//数据要加密的 //数据要加密的
byte[] resData=new byte[17]; byte[] resData=new byte[17];
......
package com.example.blu.toys.utils;
import java.text.DateFormat;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
public class LocalDateUtils {
/**
* 显示年月日时分秒,例如 2015-08-11 09:51:53.
*/
public static final String DATETIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
/**
* 仅显示年月日,例如 2015-08-11.
*/
public static final String DATE_PATTERN = "yyyy-MM-dd";
/**
* 仅显示时分秒,例如 09:51:53.
*/
public static final String TIME_PATTERN = "HH:mm:ss";
/**
* 显示年月日时分秒(无符号),例如 20150811095153.
*/
public static final String UNSIGNED_DATETIME_PATTERN = "yyyyMMddHHmmss";
/**
* 仅显示年月日(无符号),例如 20150811.
*/
public static final String UNSIGNED_DATE_PATTERN = "yyyyMMdd";
/**
* 春天;
*/
public static final Integer SPRING = 1;
/**
* 夏天;
*/
public static final Integer SUMMER = 2;
/**
* 秋天;
*/
public static final Integer AUTUMN = 3;
/**
* 冬天;
*/
public static final Integer WINTER = 4;
/**
* 星期日;
*/
public static final String SUNDAY = "星期日";
/**
* 星期一;
*/
public static final String MONDAY = "星期一";
/**
* 星期二;
*/
public static final String TUESDAY = "星期二";
/**
* 星期三;
*/
public static final String WEDNESDAY = "星期三";
/**
* 星期四;
*/
public static final String THURSDAY = "星期四";
/**
* 星期五;
*/
public static final String FRIDAY = "星期五";
/**
* 星期六;
*/
public static final String SATURDAY = "星期六";
/**
* 年
*/
private static final String YEAR = "year";
/**
* 月
*/
private static final String MONTH = "month";
/**
* 周
*/
private static final String WEEK = "week";
/**
* 日
*/
private static final String DAY = "day";
/**
* 时
*/
private static final String HOUR = "hour";
/**
* 分
*/
private static final String MINUTE = "minute";
/**
* 秒
*/
private static final String SECOND = "second";
/**
* 获取当前日期和时间字符串.
*
* @return String 日期时间字符串,例如 2015-08-11 09:51:53
*/
public static String getLocalDateTimeStr() {
return format(LocalDateTime.now(), DATETIME_PATTERN);
}
/**
* 获取当前日期字符串.
*
* @return String 日期字符串,例如2015-08-11
*/
public static String getLocalDateStr() {
return format(LocalDate.now(), DATE_PATTERN);
}
/**
* 获取当前时间字符串.
*
* @return String 时间字符串,例如 09:51:53
*/
public static String getLocalTimeStr() {
return format(LocalTime.now(), TIME_PATTERN);
}
/**
* 获取当前星期字符串.
*
* @return String 当前星期字符串,例如 星期二
*/
public static String getDayOfWeekStr() {
return format(LocalDate.now(), "E");
}
/**
* 获取指定日期是星期几
*
* @param localDate 日期
* @return String 星期几
*/
public static String getDayOfWeekStr(LocalDate localDate) {
String[] weekOfDays = {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY};
int dayOfWeek = localDate.getDayOfWeek().getValue() - 1;
return weekOfDays[dayOfWeek];
}
/**
* 获取日期时间字符串
*
* @param temporal 需要转化的日期时间
* @param pattern 时间格式
* @return String 日期时间字符串,例如 2015-08-11 09:51:53
*/
public static String format(TemporalAccessor temporal, String pattern) {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
return dateTimeFormatter.format(temporal);
}
/**
* 日期时间字符串转换为日期时间(java.time.LocalDateTime)
*
* @param localDateTimeStr 日期时间字符串
* @param pattern 日期时间格式 例如DATETIME_PATTERN
* @return LocalDateTime 日期时间
*/
public static LocalDateTime parseLocalDateTime(String localDateTimeStr, String pattern) {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
return LocalDateTime.parse(localDateTimeStr, dateTimeFormatter);
}
/**
* 日期字符串转换为日期(java.time.LocalDate)
*
* @param localDateStr 日期字符串
* @param pattern 日期格式 例如DATE_PATTERN
* @return LocalDate 日期
*/
public static LocalDate parseLocalDate(String localDateStr, String pattern) {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
return LocalDate.parse(localDateStr, dateTimeFormatter);
}
/**
* 获取指定日期时间加上指定数量日期时间单位之后的日期时间.
*
* @param localDateTime 日期时间
* @param num 数量
* @param chronoUnit 日期时间单位
* @return LocalDateTime 新的日期时间
*/
public static LocalDateTime plus(LocalDateTime localDateTime, int num, ChronoUnit chronoUnit) {
return localDateTime.plus(num, chronoUnit);
}
/**
* 获取指定日期时间减去指定数量日期时间单位之后的日期时间.
*
* @param localDateTime 日期时间
* @param num 数量
* @param chronoUnit 日期时间单位
* @return LocalDateTime 新的日期时间
*/
public static LocalDateTime minus(LocalDateTime localDateTime, int num, ChronoUnit chronoUnit) {
return localDateTime.minus(num, chronoUnit);
}
/**
* 根据ChronoUnit计算两个日期时间之间相隔日期时间
*
* @param start 开始日期时间
* @param end 结束日期时间
* @param chronoUnit 日期时间单位
* @return long 相隔日期时间
*/
public static long getChronoUnitBetween(LocalDateTime start, LocalDateTime end, ChronoUnit chronoUnit) {
return Math.abs(start.until(end, chronoUnit));
}
/**
* 根据ChronoUnit计算两个日期之间相隔年数或月数或天数
*
* @param start 开始日期
* @param end 结束日期
* @param chronoUnit 日期时间单位,(ChronoUnit.YEARS,ChronoUnit.MONTHS,ChronoUnit.WEEKS,ChronoUnit.DAYS)
* @return long 相隔年数或月数或天数
*/
public static long getChronoUnitBetween(LocalDate start, LocalDate end, ChronoUnit chronoUnit) {
return Math.abs(start.until(end, chronoUnit));
}
/**
* 获取本年第一天的日期字符串
*
* @return String 格式:yyyy-MM-dd 00:00:00
*/
public static String getFirstDayOfYearStr() {
return getFirstDayOfYearStr(LocalDateTime.now());
}
/**
* 获取本年最后一天的日期字符串
*
* @return String 格式:yyyy-MM-dd 23:59:59
*/
public static String getLastDayOfYearStr() {
return getLastDayOfYearStr(LocalDateTime.now());
}
/**
* 获取指定日期当年第一天的日期字符串
*
* @param localDateTime 指定日期时间
* @return String 格式:yyyy-MM-dd 00:00:00
*/
public static String getFirstDayOfYearStr(LocalDateTime localDateTime) {
return getFirstDayOfYearStr(localDateTime, DATETIME_PATTERN);
}
/**
* 获取指定日期当年最后一天的日期字符串
*
* @param localDateTime 指定日期时间
* @return String 格式:yyyy-MM-dd 23:59:59
*/
public static String getLastDayOfYearStr(LocalDateTime localDateTime) {
return getLastDayOfYearStr(localDateTime, DATETIME_PATTERN);
}
/**
* 获取指定日期当年第一天的日期字符串,带日期格式化参数
*
* @param localDateTime 指定日期时间
* @param pattern 日期时间格式
* @return String 格式:yyyy-MM-dd 00:00:00
*/
public static String getFirstDayOfYearStr(LocalDateTime localDateTime, String pattern) {
return format(localDateTime.withDayOfYear(1).withHour(0).withMinute(0).withSecond(0), pattern);
}
/**
* 获取指定日期当年最后一天的日期字符串,带日期格式化参数
*
* @param localDateTime 指定日期时间
* @param pattern 日期时间格式
* @return String 格式:yyyy-MM-dd 23:59:59
*/
public static String getLastDayOfYearStr(LocalDateTime localDateTime, String pattern) {
return format(localDateTime.with(TemporalAdjusters.lastDayOfYear()).withHour(23).withMinute(59).withSecond(59), pattern);
}
/**
* 获取本月第一天的日期字符串
*
* @return String 格式:yyyy-MM-dd 00:00:00
*/
public static String getFirstDayOfMonthStr() {
return getFirstDayOfMonthStr(LocalDateTime.now());
}
/**
* 获取本月最后一天的日期字符串
*
* @return String 格式:yyyy-MM-dd 23:59:59
*/
public static String getLastDayOfMonthStr() {
return getLastDayOfMonthStr(LocalDateTime.now());
}
/**
* 获取指定日期当月第一天的日期字符串
*
* @param localDateTime 指定日期时间
* @return String 格式:yyyy-MM-dd 23:59:59
*/
public static String getFirstDayOfMonthStr(LocalDateTime localDateTime) {
return getFirstDayOfMonthStr(localDateTime, DATETIME_PATTERN);
}
/**
* 获取指定日期当月最后一天的日期字符串
*
* @param localDateTime 指定日期时间
* @return String 格式:yyyy-MM-dd 23:59:59
*/
public static String getLastDayOfMonthStr(LocalDateTime localDateTime) {
return getLastDayOfMonthStr(localDateTime, DATETIME_PATTERN);
}
/**
* 获取指定日期当月第一天的日期字符串,带日期格式化参数
*
* @param localDateTime 指定日期时间
* @return String 格式:yyyy-MM-dd 00:00:00
*/
public static String getFirstDayOfMonthStr(LocalDateTime localDateTime, String pattern) {
return format(localDateTime.withDayOfMonth(1).withHour(0).withMinute(0).withSecond(0), pattern);
}
/**
* 获取指定日期当月最后一天的日期字符串,带日期格式化参数
*
* @param localDateTime 指定日期时间
* @param pattern 日期时间格式
* @return String 格式:yyyy-MM-dd 23:59:59
*/
public static String getLastDayOfMonthStr(LocalDateTime localDateTime, String pattern) {
return format(localDateTime.with(TemporalAdjusters.lastDayOfMonth()).withHour(23).withMinute(59).withSecond(59), pattern);
}
/**
* 获取本周第一天的日期字符串
*
* @return String 格式:yyyy-MM-dd 00:00:00
*/
public static String getFirstDayOfWeekStr() {
return getFirstDayOfWeekStr(LocalDateTime.now());
}
/**
* 获取本周最后一天的日期字符串
*
* @return String 格式:yyyy-MM-dd 23:59:59
*/
public static String getLastDayOfWeekStr() {
return getLastDayOfWeekStr(LocalDateTime.now());
}
/**
* 获取指定日期当周第一天的日期字符串,这里第一天为周一
*
* @param localDateTime 指定日期时间
* @return String 格式:yyyy-MM-dd 00:00:00
*/
public static String getFirstDayOfWeekStr(LocalDateTime localDateTime) {
return getFirstDayOfWeekStr(localDateTime, DATETIME_PATTERN);
}
/**
* 获取指定日期当周最后一天的日期字符串,这里最后一天为周日
*
* @param localDateTime 指定日期时间
* @return String 格式:yyyy-MM-dd 23:59:59
*/
public static String getLastDayOfWeekStr(LocalDateTime localDateTime) {
return getLastDayOfWeekStr(localDateTime, DATETIME_PATTERN);
}
/**
* 获取指定日期当周第一天的日期字符串,这里第一天为周一,带日期格式化参数
*
* @param localDateTime 指定日期时间
* @param pattern 日期时间格式
* @return String 格式:yyyy-MM-dd 00:00:00
*/
public static String getFirstDayOfWeekStr(LocalDateTime localDateTime, String pattern) {
return format(localDateTime.with(DayOfWeek.MONDAY).withHour(0).withMinute(0).withSecond(0), pattern);
}
/**
* 获取指定日期当周最后一天的日期字符串,这里最后一天为周日,带日期格式化参数
*
* @param localDateTime 指定日期时间
* @param pattern 日期时间格式
* @return String 格式:yyyy-MM-dd 23:59:59
*/
public static String getLastDayOfWeekStr(LocalDateTime localDateTime, String pattern) {
return format(localDateTime.with(DayOfWeek.SUNDAY).withHour(23).withMinute(59).withSecond(59), pattern);
}
/**
* 获取今天开始时间的日期字符串
*
* @return String 格式:yyyy-MM-dd 00:00:00
*/
public static String getStartTimeOfDayStr() {
return getStartTimeOfDayStr(LocalDateTime.now());
}
/**
* 获取今天结束时间的日期字符串
*
* @return String 格式:yyyy-MM-dd 23:59:59
*/
public static String getEndTimeOfDayStr() {
return getEndTimeOfDayStr(LocalDateTime.now());
}
/**
* 获取指定日期开始时间的日期字符串
*
* @param localDateTime 指定日期时间
* @return String 格式:yyyy-MM-dd 00:00:00
*/
public static String getStartTimeOfDayStr(LocalDateTime localDateTime) {
return getStartTimeOfDayStr(localDateTime, DATETIME_PATTERN);
}
/**
* 获取指定日期结束时间的日期字符串
*
* @param localDateTime 指定日期时间
* @return String 格式:yyyy-MM-dd 23:59:59
*/
public static String getEndTimeOfDayStr(LocalDateTime localDateTime) {
return getEndTimeOfDayStr(localDateTime, DATETIME_PATTERN);
}
/**
* 获取指定日期开始时间的日期字符串,带日期格式化参数
*
* @param localDateTime 指定日期时间
* @param pattern 日期时间格式
* @return String 格式:yyyy-MM-dd HH:mm:ss
*/
public static String getStartTimeOfDayStr(LocalDateTime localDateTime, String pattern) {
return format(localDateTime.withHour(0).withMinute(0).withSecond(0), pattern);
}
/**
* 获取指定日期结束时间的日期字符串,带日期格式化参数
*
* @param localDateTime 指定日期时间
* @param pattern 日期时间格式
* @return String 格式:yyyy-MM-dd 23:59:59
*/
public static String getEndTimeOfDayStr(LocalDateTime localDateTime, String pattern) {
return format(localDateTime.withHour(23).withMinute(59).withSecond(59), pattern);
}
/**
* 切割日期。按照周期切割成小段日期段。例如: <br>
*
* @param startDate 开始日期(yyyy-MM-dd)
* @param endDate 结束日期(yyyy-MM-dd)
* @param period 周期(天,周,月,年)
* @return 切割之后的日期集合
* <li>startDate="2019-02-28",endDate="2019-03-05",period="day"</li>
* <li>结果为:[2019-02-28, 2019-03-01, 2019-03-02, 2019-03-03, 2019-03-04, 2019-03-05]</li><br>
* <li>startDate="2019-02-28",endDate="2019-03-25",period="week"</li>
* <li>结果为:[2019-02-28,2019-03-06, 2019-03-07,2019-03-13, 2019-03-14,2019-03-20,
* 2019-03-21,2019-03-25]</li><br>
* <li>startDate="2019-02-28",endDate="2019-05-25",period="month"</li>
* <li>结果为:[2019-02-28,2019-02-28, 2019-03-01,2019-03-31, 2019-04-01,2019-04-30,
* 2019-05-01,2019-05-25]</li><br>
* <li>startDate="2019-02-28",endDate="2020-05-25",period="year"</li>
* <li>结果为:[2019-02-28,2019-12-31, 2020-01-01,2020-05-25]</li><br>
*/
public static List<String> listDateStrs(String startDate, String endDate, String period) {
List<String> result = new ArrayList<>();
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATE_PATTERN);
LocalDate end = LocalDate.parse(endDate, dateTimeFormatter);
LocalDate start = LocalDate.parse(startDate, dateTimeFormatter);
LocalDate tmp = start;
switch (period) {
case DAY:
while (start.isBefore(end) || start.isEqual(end)) {
result.add(start.toString());
start = start.plusDays(1);
}
break;
case WEEK:
while (tmp.isBefore(end) || tmp.isEqual(end)) {
if (tmp.plusDays(6).isAfter(end)) {
result.add(tmp.toString() + "," + end);
} else {
result.add(tmp.toString() + "," + tmp.plusDays(6));
}
tmp = tmp.plusDays(7);
}
break;
case MONTH:
while (tmp.isBefore(end) || tmp.isEqual(end)) {
LocalDate lastDayOfMonth = tmp.with(TemporalAdjusters.lastDayOfMonth());
if (lastDayOfMonth.isAfter(end)) {
result.add(tmp.toString() + "," + end);
} else {
result.add(tmp.toString() + "," + lastDayOfMonth);
}
tmp = lastDayOfMonth.plusDays(1);
}
break;
case YEAR:
while (tmp.isBefore(end) || tmp.isEqual(end)) {
LocalDate lastDayOfYear = tmp.with(TemporalAdjusters.lastDayOfYear());
if (lastDayOfYear.isAfter(end)) {
result.add(tmp.toString() + "," + end);
} else {
result.add(tmp.toString() + "," + lastDayOfYear);
}
tmp = lastDayOfYear.plusDays(1);
}
break;
default:
break;
}
return result;
}
/**
* 获取时间的小时
*
* @param date
* @return
*/
public static Integer getHour(Date date) {
if (date == null) {
return null;
}
return getCalendar(date).get(Calendar.HOUR_OF_DAY);
}
/**
* 获取时间的分钟
*
* @param date
* @return
*/
public static Integer getMinute(Date date) {
if (date == null) {
return null;
}
return getCalendar(date).get(Calendar.MINUTE);
}
/**
* 获取时间的秒
*
* @param date
* @return
*/
public static Integer getSecond(Date date) {
if (date == null) {
return null;
}
return getCalendar(date).get(Calendar.SECOND);
}
public static Calendar getCalendar(Date date) {
if (date == null) {
return null;
}
DateFormat df = DateFormat.getDateInstance();
df.format(date);
return df.getCalendar();
}
public static void main(String[] args) {
System.out.println(getLocalDateTimeStr());
System.out.println(getLocalDateStr());
System.out.println(getLocalTimeStr());
System.out.println(getDayOfWeekStr());
System.out.println(getDayOfWeekStr(LocalDate.now()));
System.out.println("========");
System.out.println(format(LocalDate.now(), UNSIGNED_DATE_PATTERN));
System.out.println("========");
System.out.println(parseLocalDateTime("2020-12-13 11:14:12", DATETIME_PATTERN));
System.out.println(parseLocalDate("2020-12-13", DATE_PATTERN));
System.out.println("========");
System.out.println(plus(LocalDateTime.now(), 3, ChronoUnit.HOURS));
System.out.println(minus(LocalDateTime.now(), 4, ChronoUnit.DAYS));
System.out.println("========");
System.out.println(getChronoUnitBetween(LocalDateTime.now(), parseLocalDateTime("2020-12-12 12:03:12", DATETIME_PATTERN), ChronoUnit.MINUTES));
System.out.println(getChronoUnitBetween(LocalDate.now(), parseLocalDate("2021-12-12", DATE_PATTERN), ChronoUnit.WEEKS));
System.out.println("========");
System.out.println(getFirstDayOfYearStr());
System.out.println(getFirstDayOfYearStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN)));
System.out.println(getFirstDayOfYearStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN), UNSIGNED_DATETIME_PATTERN));
System.out.println(getLastDayOfYearStr());
System.out.println(getLastDayOfYearStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN)));
System.out.println(getLastDayOfYearStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN), UNSIGNED_DATETIME_PATTERN));
System.out.println("========");
System.out.println(getFirstDayOfMonthStr());
System.out.println(getFirstDayOfMonthStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN)));
System.out.println(getFirstDayOfMonthStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN), UNSIGNED_DATETIME_PATTERN));
System.out.println(getLastDayOfMonthStr());
System.out.println(getLastDayOfMonthStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN)));
System.out.println(getLastDayOfMonthStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN), UNSIGNED_DATETIME_PATTERN));
System.out.println("========");
System.out.println(getFirstDayOfWeekStr());
System.out.println(getFirstDayOfWeekStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN)));
System.out.println(getFirstDayOfWeekStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN), UNSIGNED_DATETIME_PATTERN));
System.out.println(getLastDayOfWeekStr());
System.out.println(getLastDayOfWeekStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN)));
System.out.println(getLastDayOfWeekStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN), UNSIGNED_DATETIME_PATTERN));
System.out.println("========");
System.out.println(getStartTimeOfDayStr());
System.out.println(getStartTimeOfDayStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN)));
System.out.println(getStartTimeOfDayStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN), UNSIGNED_DATETIME_PATTERN));
System.out.println(getEndTimeOfDayStr());
System.out.println(getEndTimeOfDayStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN)));
System.out.println(getEndTimeOfDayStr(parseLocalDateTime("2021-12-12 12:03:12", DATETIME_PATTERN), UNSIGNED_DATETIME_PATTERN));
System.out.println("========");
List<String> dateStrs = listDateStrs("2019-01-30", "2020-12-13", YEAR);
for (String dateStr : dateStrs) {
System.out.println(dateStr);
}
System.out.println("========");
List<String> dateStrs1 = listDateStrs("2019-01-30", "2020-12-13", MONTH);
for (String dateStr : dateStrs1) {
System.out.println(dateStr);
}
System.out.println("========");
List<String> dateStrs2 = listDateStrs("2020-12-01", "2020-12-13", DAY);
for (String dateStr : dateStrs2) {
System.out.println(dateStr);
}
Date date = new Date();
System.out.println(getHour(date) + "h" + getMinute(date) + "m" + getSecond(date) + "s");
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date()); //放入Date类型数据
calendar.get(Calendar.HOUR); //时(12小时制)
calendar.get(Calendar.MINUTE); //分
calendar.get(Calendar.SECOND);
System.out.println(calendar.get(Calendar.HOUR) + "h" + calendar.get(Calendar.MINUTE) + "m" + calendar.get(Calendar.SECOND) + "s");
}
}
\ No newline at end of file
package com.example.blu.toys.view;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.Gravity;
import android.widget.ImageView;
import android.widget.LinearLayout;
import com.example.blu.toys.R;
import java.lang.ref.WeakReference;
public class PointWaitBar extends LinearLayout {
private static final int NUM = 3;
private Context context;
private String TAG = "PointWaitBar";
private ImageView mOldIM;
private UpdateHandler handler;
public PointWaitBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
init();
}
public PointWaitBar(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
init();
}
public PointWaitBar(Context context) {
super(context);
this.context = context;
init();
}
private void init() {
//初始化数据
this.setOrientation(LinearLayout.HORIZONTAL);
this.setGravity(Gravity.CENTER);
handler = new UpdateHandler(context);
Bitmap bitmap = null;
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
Drawable vectorDrawable = context.getDrawable(R.drawable.point_waitingbar_black);
bitmap = Bitmap.createBitmap(vectorDrawable.getIntrinsicWidth(),
vectorDrawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
vectorDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
vectorDrawable.draw(canvas);
} else {
bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.point_waitingbar_black);
}
LinearLayout.LayoutParams tLayoutParams = new LinearLayout.LayoutParams(bitmap.getWidth(), bitmap.getHeight());
tLayoutParams.leftMargin = 10;
tLayoutParams.rightMargin = 10;
//添加5个小点省略号
for (int i = 0; i < NUM; i++) {
ImageView vDot = new ImageView(context);
vDot.setLayoutParams(tLayoutParams);
if (i == 0) {
vDot.setBackgroundResource(R.drawable.point_waitingbar_white);
} else {
vDot.setBackgroundResource(R.drawable.point_waitingbar_black);
}
this.addView(vDot);
}
mOldIM = (ImageView) this.getChildAt(0);
handler.sendEmptyMessage(0);
}
//提供给外部消除message
public void setDestroyCallBack() {
if (handler != null) {
handler.removeCallbacksAndMessages(null);
// LogUtil.i(TAG, "已经清除消息");
}
}
class UpdateHandler extends Handler {
WeakReference<Context> reference;
public UpdateHandler(Context context) {
reference = new WeakReference<Context>(context);
}
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
int cPosition = msg.what;
if (mOldIM != null)
mOldIM.setBackgroundResource(R.drawable.point_waitingbar_black);
ImageView currentIM = (ImageView) PointWaitBar.this.getChildAt(cPosition);
currentIM.setBackgroundResource(R.drawable.point_waitingbar_white);
mOldIM = currentIM;
if (++cPosition == NUM)
cPosition = 0;
this.sendEmptyMessageDelayed(cPosition, 200);
}
}
}
\ No newline at end of file
package com.example.blu.toys.view;
import android.app.Activity;
import android.content.Context;
import android.content.res.AssetManager;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class WheelView extends ScrollView {
public static final String TAG = WheelView.class.getSimpleName();
public static class OnWheelViewListener {
public void onSelected(int selectedIndex, String item) {
}
}
private Context context;
private LinearLayout views;
public WheelView(Context context) {
super(context);
init(context);
}
public WheelView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public WheelView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
List<String> items;
private List<String> getItems() {
return items;
}
public void setItems(List<String> list) {
if (null == items) {
items = new ArrayList<String>();
}
items.clear();
items.addAll(list);
// 前面和后面补全
for (int i = 0; i < offset; i++) {
items.add(0, "");
items.add("");
}
initData();
}
public static final int OFF_SET_DEFAULT = 1;
int offset = OFF_SET_DEFAULT; // 偏移量(需要在最前面和最后面补全)
public int getOffset() {
return offset;
}
public void setOffset(int offset) {
this.offset = offset;
}
int displayItemCount; // 每页显示的数量
int selectedIndex = 1;
private void init(Context context) {
this.context = context;
this.setVerticalScrollBarEnabled(false);
views = new LinearLayout(context);
views.setOrientation(LinearLayout.VERTICAL);
this.addView(views);
scrollerTask = () -> {
int newY = getScrollY();
if (initialY - newY == 0) {
// stopped
final int remainder = initialY % itemHeight;
final int divided = initialY / itemHeight;
if (remainder == 0) {
selectedIndex = divided + offset;
onSeletedCallBack();
} else {
if (remainder > itemHeight / 2) {
WheelView.this.post(() -> {
WheelView.this.smoothScrollTo(0, initialY - remainder + itemHeight);
selectedIndex = divided + offset + 1;
onSeletedCallBack();
});
} else {
WheelView.this.post(() -> {
WheelView.this.smoothScrollTo(0, initialY - remainder);
selectedIndex = divided + offset;
onSeletedCallBack();
});
}
}
} else {
initialY = getScrollY();
WheelView.this.postDelayed(scrollerTask, newCheck);
}
};
}
int initialY;
Runnable scrollerTask;
int newCheck = 50;
public void startScrollerTask() {
initialY = getScrollY();
this.postDelayed(scrollerTask, newCheck);
}
private void initData() {
displayItemCount = offset * 2 + 1;
for (String item : items) {
views.addView(createView(item));
}
refreshItemView(0);
}
int itemHeight = 0;
private TextView createView(String item) {
TextView tv = new TextView(context);
tv.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
tv.setSingleLine(true);
tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 24);
tv.setText(item);
tv.setGravity(Gravity.CENTER);
AssetManager mgr = this.getContext().getAssets();
//根据路径得到Typeface
Typeface tf = Typeface.createFromAsset(mgr, "fonts/LittleOrion.otf");
tv.setTypeface(tf);
int padding = dip2px(15);
tv.setPadding(padding, 0, padding, 0);
if (0 == itemHeight) {
itemHeight = getViewMeasuredHeight(tv);
Log.d(TAG, "itemHeight: " + itemHeight);
views.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, itemHeight * displayItemCount));
LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) this.getLayoutParams();
this.setLayoutParams(new LinearLayout.LayoutParams(lp.width, itemHeight * displayItemCount));
}
return tv;
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
refreshItemView(t);
if (t > oldt) {
// Log.d(TAG, "向下滚动");
scrollDirection = SCROLL_DIRECTION_DOWN;
} else {
// Log.d(TAG, "向上滚动");
scrollDirection = SCROLL_DIRECTION_UP;
}
}
private void refreshItemView(int y) {
int position = y / itemHeight + offset;
int remainder = y % itemHeight;
int divided = y / itemHeight;
if (remainder == 0) {
position = divided + offset;
} else {
if (remainder > itemHeight / 2) {
position = divided + offset + 1;
}
}
int childSize = views.getChildCount();
for (int i = 0; i < childSize; i++) {
TextView itemView = (TextView) views.getChildAt(i);
if (null == itemView) {
return;
}
if (position == i) {
itemView.setTextColor(Color.parseColor("#eeeeee"));
} else {
itemView.setTextColor(Color.parseColor("#bbbbbb"));
}
}
}
/**
* 获取选中区域的边界
*/
int[] selectedAreaBorder;
private int[] obtainSelectedAreaBorder() {
if (null == selectedAreaBorder) {
selectedAreaBorder = new int[2];
selectedAreaBorder[0] = itemHeight * offset;
selectedAreaBorder[1] = itemHeight * (offset + 1);
}
return selectedAreaBorder;
}
private int scrollDirection = -1;
private static final int SCROLL_DIRECTION_UP = 0;
private static final int SCROLL_DIRECTION_DOWN = 1;
Paint paint;
int viewWidth;
@Override
public void setBackgroundDrawable(Drawable background) {
if (viewWidth == 0) {
viewWidth = ((Activity) context).getWindowManager().getDefaultDisplay().getWidth();
Log.d(TAG, "viewWidth: " + viewWidth);
}
if (null == paint) {
paint = new Paint();
paint.setColor(Color.parseColor("#ff000000"));
paint.setStrokeWidth(dip2px(1f));
}
background = new Drawable() {
@Override
public void draw(Canvas canvas) {
canvas.drawLine(viewWidth * 1 / 6, obtainSelectedAreaBorder()[0], viewWidth * 5 / 6, obtainSelectedAreaBorder()[0], paint);
canvas.drawLine(viewWidth * 1 / 6, obtainSelectedAreaBorder()[1], viewWidth * 5 / 6, obtainSelectedAreaBorder()[1], paint);
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(ColorFilter cf) {
}
@Override
public int getOpacity() {
return 0;
}
};
super.setBackgroundDrawable(background);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
Log.d(TAG, "w: " + w + ", h: " + h + ", oldw: " + oldw + ", oldh: " + oldh);
viewWidth = w;
setBackgroundDrawable(null);
}
/**
* 选中回调
*/
private void onSeletedCallBack() {
if (null != onWheelViewListener) {
onWheelViewListener.onSelected(selectedIndex, items.get(selectedIndex));
}
}
public void setSeletion(int position) {
final int p = position;
selectedIndex = p + offset;
this.post(new Runnable() {
@Override
public void run() {
WheelView.this.smoothScrollTo(0, p * itemHeight);
}
});
}
public String getSeletedItem() {
return items.get(selectedIndex);
}
public int getSeletedIndex() {
return selectedIndex - offset;
}
@Override
public void fling(int velocityY) {
super.fling(velocityY / 3);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_UP) {
startScrollerTask();
}
return super.onTouchEvent(ev);
}
private OnWheelViewListener onWheelViewListener;
public OnWheelViewListener getOnWheelViewListener() {
return onWheelViewListener;
}
public void setOnWheelViewListener(OnWheelViewListener onWheelViewListener) {
this.onWheelViewListener = onWheelViewListener;
}
private int dip2px(float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
private int getViewMeasuredHeight(View view) {
int width = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
int expandSpec = View.MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, View.MeasureSpec.AT_MOST);
view.measure(width, expandSpec);
return view.getMeasuredHeight();
}
}
\ No newline at end of file
package com.example.blu.toys.view;
import android.content.Context;
import android.util.AttributeSet;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class WrapContentGridLayoutManager extends LinearLayoutManager {
public WrapContentGridLayoutManager(Context context) {
super(context);
}
public WrapContentGridLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
public WrapContentGridLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
try {
super.onLayoutChildren(recycler, state);
} catch (IndexOutOfBoundsException e) {
//手动catch住
e.printStackTrace();
}
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/black" />
<corners android:radius="150dp" />
<size
android:width="@dimen/dp_5"
android:height="@dimen/dp_5" />
</shape>
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/white" />
<corners android:radius="150dp" />
<size
android:width="@dimen/dp_5"
android:height="@dimen/dp_5" />
</shape>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFCA05"
android:orientation="vertical"
tools:context=".activity.MusicActivity">
<com.example.blu.toys.view.TypefaceTextView
android:id="@+id/open_music"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/back_but"
android:layout_centerHorizontal="true"
android:layout_gravity="center_horizontal"
android:layout_marginTop="@dimen/dp_14"
android:gravity="center"
android:text="开机音乐"
android:textColor="@color/backer_back"
android:textSize="@dimen/sp_24"
android:textStyle="bold"
app:typeface="@string/LittleOrion" />
<com.example.blu.toys.view.TypefaceTextView
android:id="@+id/close_music"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/back_but"
android:layout_centerHorizontal="true"
android:layout_gravity="center_horizontal"
android:layout_marginTop="@dimen/dp_14"
android:gravity="center"
android:text="关机音乐"
android:textColor="@color/backer_back"
android:textSize="@dimen/sp_24"
android:textStyle="bold"
app:typeface="@string/LittleOrion" />
</LinearLayout>
\ No newline at end of file
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
android:gravity="center" android:gravity="center"
android:padding="@dimen/dp_5" android:padding="@dimen/dp_5"
android:text="Back" android:text="Back"
app:typeface="@string/LittleOrion"
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="@dimen/sp_28" android:textSize="@dimen/sp_28"
android:textStyle="bold" /> android:textStyle="bold" />
...@@ -37,6 +38,7 @@ ...@@ -37,6 +38,7 @@
android:gravity="center" android:gravity="center"
android:padding="@dimen/dp_10" android:padding="@dimen/dp_10"
android:text="00:14:99" android:text="00:14:99"
app:typeface="@string/LittleOrion"
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="@dimen/sp_30" android:textSize="@dimen/sp_30"
android:textStyle="bold" /> android:textStyle="bold" />
...@@ -67,6 +69,7 @@ ...@@ -67,6 +69,7 @@
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:gravity="center" android:gravity="center"
android:text="Cancel" android:text="Cancel"
app:typeface="@string/LittleOrion"
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="@dimen/sp_30" android:textSize="@dimen/sp_30"
android:textStyle="bold" /> android:textStyle="bold" />
...@@ -89,6 +92,7 @@ ...@@ -89,6 +92,7 @@
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:gravity="center" android:gravity="center"
android:text="Pause" android:text="Pause"
app:typeface="@string/LittleOrion"
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="@dimen/sp_30" android:textSize="@dimen/sp_30"
android:textStyle="bold" /> android:textStyle="bold" />
...@@ -111,6 +115,7 @@ ...@@ -111,6 +115,7 @@
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:gravity="center" android:gravity="center"
android:text="Resume" android:text="Resume"
app:typeface="@string/LittleOrion"
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="@dimen/sp_30" android:textSize="@dimen/sp_30"
android:textStyle="bold" /> android:textStyle="bold" />
......
...@@ -8,19 +8,26 @@ ...@@ -8,19 +8,26 @@
tools:context=".activity.SearchingActivity"> tools:context=".activity.SearchingActivity">
<com.example.blu.toys.view.TypefaceTextView <LinearLayout
android:id="@+id/back_but" android:id="@+id/back_but"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_20" android:layout_marginLeft="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_20" android:layout_marginTop="@dimen/dp_20"
android:background="@drawable/black_thumb" android:background="@drawable/black_thumb"
android:gravity="center" android:gravity="center">
android:padding="@dimen/dp_5"
android:text="Back" <com.example.blu.toys.view.TypefaceTextView
android:textColor="@color/white" android:layout_width="wrap_content"
android:textSize="@dimen/sp_28" android:layout_height="wrap_content"
android:textStyle="bold" /> android:padding="@dimen/dp_5"
android:text="Back"
android:textColor="@color/white"
android:textSize="@dimen/sp_28"
android:textStyle="bold"
app:typeface="@string/LittleOrion" />
</LinearLayout>
<com.example.blu.toys.view.TypefaceTextView <com.example.blu.toys.view.TypefaceTextView
...@@ -57,15 +64,29 @@ ...@@ -57,15 +64,29 @@
android:orientation="vertical"> android:orientation="vertical">
<com.example.blu.toys.view.TypefaceTextView <LinearLayout
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerHorizontal="true" android:layout_centerHorizontal="true"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:text="Srearching..." android:orientation="horizontal">
android:textColor="@color/black"
android:textSize="@dimen/sp_22"
android:textStyle="bold" /> <com.example.blu.toys.view.TypefaceTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Srearching"
android:textColor="@color/black"
android:textSize="@dimen/sp_22"
android:textStyle="bold" />
<com.example.blu.toys.view.PointWaitBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginBottom="@dimen/dp_3" />
</LinearLayout>
<androidx.appcompat.widget.AppCompatImageView <androidx.appcompat.widget.AppCompatImageView
......
...@@ -47,34 +47,15 @@ ...@@ -47,34 +47,15 @@
android:textStyle="bold" /> android:textStyle="bold" />
<com.example.blu.toys.view.TypefaceTextView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_20" android:layout_marginLeft="@dimen/dp_10"
android:layout_marginTop="@dimen/dp_20" android:layout_marginTop="@dimen/dp_20"
android:layout_marginRight="@dimen/dp_20" android:layout_marginRight="@dimen/dp_20"
android:background="@drawable/black_thumb"
android:gravity="center"
android:padding="@dimen/dp_10" android:padding="@dimen/dp_10"
android:text="Stoplight Golight Time 1" app:layout_constraintTop_toBottomOf="@+id/include" />
android:textColor="@color/white"
android:textSize="@dimen/sp_22"
android:textStyle="bold" />
<com.example.blu.toys.view.TypefaceTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_20"
android:layout_marginRight="@dimen/dp_20"
android:background="@drawable/black_thumb"
android:gravity="center"
android:padding="@dimen/dp_10"
android:text="Stoplight Golight Time 1"
android:textColor="@color/white"
android:textSize="@dimen/sp_22"
android:textStyle="bold" />
<com.example.blu.toys.view.TypefaceTextView <com.example.blu.toys.view.TypefaceTextView
......
...@@ -20,7 +20,8 @@ ...@@ -20,7 +20,8 @@
android:text="Back" android:text="Back"
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="@dimen/sp_28" android:textSize="@dimen/sp_28"
android:textStyle="bold" /> android:textStyle="bold"
app:typeface="@string/LittleOrion" />
<LinearLayout <LinearLayout
...@@ -47,7 +48,8 @@ ...@@ -47,7 +48,8 @@
android:text="Select Timer Type" android:text="Select Timer Type"
android:textColor="@color/backer_back" android:textColor="@color/backer_back"
android:textSize="@dimen/sp_24" android:textSize="@dimen/sp_24"
android:textStyle="bold" /> android:textStyle="bold"
app:typeface="@string/LittleOrion" />
<RelativeLayout <RelativeLayout
...@@ -71,6 +73,7 @@ ...@@ -71,6 +73,7 @@
<Switch <Switch
android:id="@+id/alarm_switch"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerVertical="true" android:layout_centerVertical="true"
...@@ -109,6 +112,7 @@ ...@@ -109,6 +112,7 @@
<Switch <Switch
android:id="@+id/music_switch"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerVertical="true" android:layout_centerVertical="true"
...@@ -147,6 +151,7 @@ ...@@ -147,6 +151,7 @@
<Switch <Switch
android:id="@+id/green_switch"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerVertical="true" android:layout_centerVertical="true"
...@@ -196,6 +201,7 @@ ...@@ -196,6 +201,7 @@
<SeekBar <SeekBar
android:id="@+id/brightness_bar"
style="?android:attr/progressBarStyleHorizontal" style="?android:attr/progressBarStyleHorizontal"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
......
...@@ -20,7 +20,8 @@ ...@@ -20,7 +20,8 @@
android:text="Back" android:text="Back"
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="@dimen/sp_28" android:textSize="@dimen/sp_28"
android:textStyle="bold" /> android:textStyle="bold"
app:typeface="@string/LittleOrion" />
<ImageView <ImageView
...@@ -44,7 +45,8 @@ ...@@ -44,7 +45,8 @@
android:text="Set Your Timer!" android:text="Set Your Timer!"
android:textColor="@color/backer_back" android:textColor="@color/backer_back"
android:textSize="@dimen/sp_34" android:textSize="@dimen/sp_34"
android:textStyle="bold" /> android:textStyle="bold"
app:typeface="@string/LittleOrion" />
<LinearLayout <LinearLayout
...@@ -71,26 +73,74 @@ ...@@ -71,26 +73,74 @@
android:text="Select End Timer" android:text="Select End Timer"
android:textColor="@color/backer_back" android:textColor="@color/backer_back"
android:textSize="@dimen/sp_24" android:textSize="@dimen/sp_24"
android:textStyle="bold" /> android:textStyle="bold"
app:typeface="@string/LittleOrion" />
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="@dimen/dp_75"
android:background="@drawable/black_thumb" android:background="@drawable/black_thumb"
android:padding="@dimen/dp_5"> >
<com.example.blu.toys.view.TypefaceTextView <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:gravity="center_horizontal" android:gravity="center">
android:padding="@dimen/dp_10"
android:text="08:00:00" <com.example.blu.toys.view.WheelView
android:textColor="@color/white" android:id="@+id/wheel_hour"
android:textSize="@dimen/sp_28" android:layout_width="wrap_content"
android:textStyle="bold" android:layout_height="wrap_content"
app:typeface="@string/LittleOrion" /> android:layout_gravity="center_vertical" />
<com.example.blu.toys.view.TypefaceTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/back_but"
android:layout_centerHorizontal="true"
android:layout_gravity="center_vertical"
android:text=":"
android:textColor="@color/white"
android:textSize="@dimen/sp_24"
app:typeface="@string/LittleOrion" />
<com.example.blu.toys.view.WheelView
android:id="@+id/wheel_minute"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical" />
<com.example.blu.toys.view.TypefaceTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/back_but"
android:layout_centerHorizontal="true"
android:layout_gravity="center_vertical"
android:text=":"
android:textColor="@color/white"
android:textSize="@dimen/sp_24"
app:typeface="@string/LittleOrion" />
<com.example.blu.toys.view.WheelView
android:id="@+id/wheel_second"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical" />
<com.example.blu.toys.view.WheelView
android:id="@+id/wheel_am_pm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="20dp" />
</LinearLayout>
</RelativeLayout> </RelativeLayout>
...@@ -107,25 +157,64 @@ ...@@ -107,25 +157,64 @@
android:text="Select Time Interval" android:text="Select Time Interval"
android:textColor="@color/backer_back" android:textColor="@color/backer_back"
android:textSize="@dimen/sp_24" android:textSize="@dimen/sp_24"
android:textStyle="bold" /> android:textStyle="bold"
app:typeface="@string/LittleOrion" />
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="@dimen/dp_50"
android:background="@drawable/black_thumb" android:background="@drawable/black_thumb"
android:padding="@dimen/dp_5"> android:padding="@dimen/dp_5">
<com.example.blu.toys.view.TypefaceTextView <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true" android:layout_centerVertical="true"
android:gravity="center" android:gravity="center">
android:padding="@dimen/dp_10"
android:text="00:15:00" <com.example.blu.toys.view.WheelView
android:textColor="@color/white" android:id="@+id/wheel_hour_dw"
android:textSize="@dimen/sp_28" android:layout_width="wrap_content"
android:textStyle="bold" android:layout_height="wrap_content"
app:typeface="@string/LittleOrion" /> android:layout_gravity="center_vertical" />
<com.example.blu.toys.view.TypefaceTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/back_but"
android:layout_centerHorizontal="true"
android:layout_gravity="center_vertical"
android:text=":"
android:textColor="@color/white"
android:textSize="@dimen/sp_24"
app:typeface="@string/LittleOrion" />
<com.example.blu.toys.view.WheelView
android:id="@+id/wheel_minute_dw"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical" />
<com.example.blu.toys.view.TypefaceTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/back_but"
android:layout_centerHorizontal="true"
android:layout_gravity="center_vertical"
android:text=":"
android:textColor="@color/white"
android:textSize="@dimen/sp_24"
app:typeface="@string/LittleOrion" />
<com.example.blu.toys.view.WheelView
android:id="@+id/wheel_second_dw"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical" />
</LinearLayout>
</RelativeLayout> </RelativeLayout>
......
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFCA05"
tools:context=".activity.SettingMusicActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_10"
android:layout_marginTop="@dimen/dp_20"
android:layout_marginRight="@dimen/dp_20"
android:padding="@dimen/dp_10"
app:layout_constraintTop_toBottomOf="@+id/include" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<com.example.blu.toys.view.TypefaceTextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/dv_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_10"
android:layout_marginRight="@dimen/dp_20"
android:background="@drawable/black_thumb"
android:gravity="center"
android:padding="@dimen/dp_10"
android:text="Stoplight Golight Time 1"
android:textColor="@color/white"
android:textSize="@dimen/sp_22"
android:textStyle="bold">
</com.example.blu.toys.view.TypefaceTextView>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#FFCA05"
android:gravity="center"
android:padding="@dimen/dp_10">
<com.example.blu.toys.view.TypefaceTextView
android:id="@+id/dv_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_20"
android:layout_marginTop="@dimen/dp_10"
android:layout_marginRight="@dimen/dp_20"
android:gravity="center"
android:padding="@dimen/dp_10"
android:text="Stoplight Golight Time 1"
android:textColor="@color/white"
android:textSize="@dimen/sp_22"
android:textStyle="bold" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
\ No newline at end of file
...@@ -3,8 +3,8 @@ buildscript { ...@@ -3,8 +3,8 @@ buildscript {
repositories { repositories {
google() google()
jcenter() jcenter()
// maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' } maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
// maven { url 'https://jitpack.io' } maven { url 'https://jitpack.io' }
} }
dependencies { dependencies {
...@@ -16,9 +16,9 @@ buildscript { ...@@ -16,9 +16,9 @@ buildscript {
allprojects { allprojects {
repositories { repositories {
google() google()
mavenCentral()
maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' } maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
maven { url "https://jitpack.io" }
// maven { url 'https://www.jitpack.io' }
jcenter() jcenter()
} }
} }
......
.gradle/
.DS_Store
local.properties
# build files
build/
bin/
gen/
output/
# android studio
*.iml
.idea
apply plugin: 'com.android.library'
android {
compileSdkVersion 28
defaultConfig {
minSdkVersion 14
targetSdkVersion 28
versionCode 1
versionName "1.0"
}
buildTypes {
release {
consumerProguardFiles 'proguard-rules.pro'
}
}
lintOptions {
abortOnError false
}
}
// 打包源码jar
task sourcesJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
classifier = 'sources'
}
task javadoc(type: Javadoc) {
failOnError false
source = android.sourceSets.main.java.sourceFiles
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
classpath += configurations.compile
}
// 打包文档jar
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
artifacts {
archives sourcesJar
archives javadocJar
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
compileOnly 'androidx.recyclerview:recyclerview:1.0.0'
}
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /Users/huasheng/Desktop/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 *;
#}
-keep class com.chad.library.adapter.** {
*;
}
-keep public class * extends com.chad.library.adapter.base.BaseQuickAdapter
-keep public class * extends com.chad.library.adapter.base.BaseViewHolder
-keepclassmembers class **$** extends com.chad.library.adapter.base.BaseViewHolder {
<init>(...);
}
-keepattributes InnerClasses
\ No newline at end of file
<manifest package="com.chad.library"
xmlns:android="http://schemas.android.com/apk/res/android">
</manifest>
package com.chad.library.adapter.base;
import android.graphics.Canvas;
import androidx.annotation.NonNull;
import androidx.core.view.MotionEventCompat;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
import android.view.MotionEvent;
import android.view.View;
import com.chad.library.R;
import com.chad.library.adapter.base.callback.ItemDragAndSwipeCallback;
import com.chad.library.adapter.base.listener.OnItemDragListener;
import com.chad.library.adapter.base.listener.OnItemSwipeListener;
import java.util.Collections;
import java.util.List;
/**
* Created by luoxw on 2016/7/13.
*/
public abstract class BaseItemDraggableAdapter<T, K extends BaseViewHolder> extends BaseQuickAdapter<T, K> {
private static final int NO_TOGGLE_VIEW = 0;
protected int mToggleViewId = NO_TOGGLE_VIEW;
protected ItemTouchHelper mItemTouchHelper;
protected boolean itemDragEnabled = false;
protected boolean itemSwipeEnabled = false;
protected OnItemDragListener mOnItemDragListener;
protected OnItemSwipeListener mOnItemSwipeListener;
protected boolean mDragOnLongPress = true;
protected View.OnTouchListener mOnToggleViewTouchListener;
protected View.OnLongClickListener mOnToggleViewLongClickListener;
private static final String ERROR_NOT_SAME_ITEMTOUCHHELPER = "Item drag and item swipe should pass the same ItemTouchHelper";
public BaseItemDraggableAdapter(List<T> data) {
super(data);
}
public BaseItemDraggableAdapter(int layoutResId, List<T> data) {
super(layoutResId, data);
}
/**
* To bind different types of holder and solve different the bind events
*
* @param holder
* @param position
* @see #getDefItemViewType(int)
*/
@Override
public void onBindViewHolder(@NonNull K holder, int position) {
super.onBindViewHolder(holder, position);
int viewType = holder.getItemViewType();
if (mItemTouchHelper != null && itemDragEnabled && viewType != LOADING_VIEW && viewType != HEADER_VIEW
&& viewType != EMPTY_VIEW && viewType != FOOTER_VIEW) {
if (mToggleViewId != NO_TOGGLE_VIEW) {
View toggleView = holder.getView(mToggleViewId);
if (toggleView != null) {
toggleView.setTag(R.id.BaseQuickAdapter_viewholder_support, holder);
if (mDragOnLongPress) {
toggleView.setOnLongClickListener(mOnToggleViewLongClickListener);
} else {
toggleView.setOnTouchListener(mOnToggleViewTouchListener);
}
}
} else {
holder.itemView.setTag(R.id.BaseQuickAdapter_viewholder_support, holder);
holder.itemView.setOnLongClickListener(mOnToggleViewLongClickListener);
}
}
}
/**
* Set the toggle view's id which will trigger drag event.
* If the toggle view id is not set, drag event will be triggered when the item is long pressed.
*
* @param toggleViewId the toggle view's id
*/
public void setToggleViewId(int toggleViewId) {
mToggleViewId = toggleViewId;
}
/**
* Set the drag event should be trigger on long press.
* Work when the toggleViewId has been set.
*
* @param longPress by default is true.
*/
public void setToggleDragOnLongPress(boolean longPress) {
mDragOnLongPress = longPress;
if (mDragOnLongPress) {
mOnToggleViewTouchListener = null;
mOnToggleViewLongClickListener = new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (mItemTouchHelper != null && itemDragEnabled) {
mItemTouchHelper.startDrag((RecyclerView.ViewHolder) v.getTag(R.id.BaseQuickAdapter_viewholder_support));
}
return true;
}
};
} else {
mOnToggleViewTouchListener = new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (MotionEventCompat.getActionMasked(event) == MotionEvent.ACTION_DOWN
&& !mDragOnLongPress) {
if (mItemTouchHelper != null && itemDragEnabled) {
mItemTouchHelper.startDrag((RecyclerView.ViewHolder) v.getTag(R.id.BaseQuickAdapter_viewholder_support));
}
return true;
} else {
return false;
}
}
};
mOnToggleViewLongClickListener = null;
}
}
/**
* Enable drag items.
* Use itemView as the toggleView when long pressed.
*
* @param itemTouchHelper {@link ItemTouchHelper}
*/
public void enableDragItem(@NonNull ItemTouchHelper itemTouchHelper) {
enableDragItem(itemTouchHelper, NO_TOGGLE_VIEW, true);
}
/**
* Enable drag items. Use the specified view as toggle.
*
* @param itemTouchHelper {@link ItemTouchHelper}
* @param toggleViewId The toggle view's id.
* @param dragOnLongPress If true the drag event will be trigger on long press, otherwise on touch down.
*/
public void enableDragItem(@NonNull ItemTouchHelper itemTouchHelper, int toggleViewId, boolean dragOnLongPress) {
itemDragEnabled = true;
mItemTouchHelper = itemTouchHelper;
setToggleViewId(toggleViewId);
setToggleDragOnLongPress(dragOnLongPress);
}
/**
* Disable drag items.
*/
public void disableDragItem() {
itemDragEnabled = false;
mItemTouchHelper = null;
}
public boolean isItemDraggable() {
return itemDragEnabled;
}
/**
* <p>Enable swipe items.</p>
* You should attach {@link ItemTouchHelper} which construct with {@link ItemDragAndSwipeCallback} to the Recycler when you enable this.
*/
public void enableSwipeItem() {
itemSwipeEnabled = true;
}
public void disableSwipeItem() {
itemSwipeEnabled = false;
}
public boolean isItemSwipeEnable() {
return itemSwipeEnabled;
}
/**
* @param onItemDragListener Register a callback to be invoked when drag event happen.
*/
public void setOnItemDragListener(OnItemDragListener onItemDragListener) {
mOnItemDragListener = onItemDragListener;
}
public int getViewHolderPosition(RecyclerView.ViewHolder viewHolder) {
return viewHolder.getAdapterPosition() - getHeaderLayoutCount();
}
public void onItemDragStart(RecyclerView.ViewHolder viewHolder) {
if (mOnItemDragListener != null && itemDragEnabled) {
mOnItemDragListener.onItemDragStart(viewHolder, getViewHolderPosition(viewHolder));
}
}
public void onItemDragMoving(RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
int from = getViewHolderPosition(source);
int to = getViewHolderPosition(target);
if (inRange(from) && inRange(to)) {
if (from < to) {
for (int i = from; i < to; i++) {
Collections.swap(mData, i, i + 1);
}
} else {
for (int i = from; i > to; i--) {
Collections.swap(mData, i, i - 1);
}
}
notifyItemMoved(source.getAdapterPosition(), target.getAdapterPosition());
}
if (mOnItemDragListener != null && itemDragEnabled) {
mOnItemDragListener.onItemDragMoving(source, from, target, to);
}
}
public void onItemDragEnd(RecyclerView.ViewHolder viewHolder) {
if (mOnItemDragListener != null && itemDragEnabled) {
mOnItemDragListener.onItemDragEnd(viewHolder, getViewHolderPosition(viewHolder));
}
}
public void setOnItemSwipeListener(OnItemSwipeListener listener) {
mOnItemSwipeListener = listener;
}
public void onItemSwipeStart(RecyclerView.ViewHolder viewHolder) {
if (mOnItemSwipeListener != null && itemSwipeEnabled) {
mOnItemSwipeListener.onItemSwipeStart(viewHolder, getViewHolderPosition(viewHolder));
}
}
public void onItemSwipeClear(RecyclerView.ViewHolder viewHolder) {
if (mOnItemSwipeListener != null && itemSwipeEnabled) {
mOnItemSwipeListener.clearView(viewHolder, getViewHolderPosition(viewHolder));
}
}
public void onItemSwiped(RecyclerView.ViewHolder viewHolder) {
final int pos = getViewHolderPosition(viewHolder);
if (inRange(pos)) {
mData.remove(pos);
notifyItemRemoved(viewHolder.getAdapterPosition());
if (mOnItemSwipeListener != null && itemSwipeEnabled) {
mOnItemSwipeListener.onItemSwiped(viewHolder, pos);
}
}
}
public void onItemSwiping(Canvas canvas, RecyclerView.ViewHolder viewHolder, float dX, float dY, boolean isCurrentlyActive) {
if (mOnItemSwipeListener != null && itemSwipeEnabled) {
mOnItemSwipeListener.onItemSwipeMoving(canvas, viewHolder, dX, dY, isCurrentlyActive);
}
}
private boolean inRange(int position) {
return position >= 0 && position < mData.size();
}
}
package com.chad.library.adapter.base;
import android.util.SparseIntArray;
import android.view.ViewGroup;
import androidx.annotation.IntRange;
import androidx.annotation.LayoutRes;
import com.chad.library.adapter.base.entity.IExpandable;
import com.chad.library.adapter.base.entity.MultiItemEntity;
import java.util.List;
/**
* https://github.com/CymChad/BaseRecyclerViewAdapterHelper
*/
public abstract class BaseMultiItemQuickAdapter<T extends MultiItemEntity, K extends BaseViewHolder> extends BaseQuickAdapter<T, K> {
/**
* layouts indexed with their types
*/
private SparseIntArray layouts;
private static final int DEFAULT_VIEW_TYPE = -0xff;
public static final int TYPE_NOT_FOUND = -404;
/**
* Same as QuickAdapter#QuickAdapter(Context,int) but with
* some initialization data.
*
* @param data A new list is created out of this one to avoid mutable list
*/
public BaseMultiItemQuickAdapter(List<T> data) {
super(data);
}
@Override
protected int getDefItemViewType(int position) {
T item = mData.get(position);
if (item != null) {
return item.getItemType();
}
return DEFAULT_VIEW_TYPE;
}
protected void setDefaultViewTypeLayout(@LayoutRes int layoutResId) {
addItemType(DEFAULT_VIEW_TYPE, layoutResId);
}
@Override
protected K onCreateDefViewHolder(ViewGroup parent, int viewType) {
return createBaseViewHolder(parent, getLayoutId(viewType));
}
private int getLayoutId(int viewType) {
return layouts.get(viewType, TYPE_NOT_FOUND);
}
protected void addItemType(int type, @LayoutRes int layoutResId) {
if (layouts == null) {
layouts = new SparseIntArray();
}
layouts.put(type, layoutResId);
}
@Override
public void remove(@IntRange(from = 0L) int position) {
if (mData == null
|| position < 0
|| position >= mData.size()) return;
T entity = mData.get(position);
if (entity instanceof IExpandable) {
removeAllChild((IExpandable) entity, position);
}
removeDataFromParent(entity);
super.remove(position);
}
/**
* 移除父控件时,若父控件处于展开状态,则先移除其所有的子控件
*
* @param parent 父控件实体
* @param parentPosition 父控件位置
*/
protected void removeAllChild(IExpandable parent, int parentPosition) {
if (parent.isExpanded()) {
List<MultiItemEntity> chidChilds = parent.getSubItems();
if (chidChilds == null || chidChilds.size() == 0) return;
int childSize = chidChilds.size();
for (int i = 0; i < childSize; i++) {
remove(parentPosition + 1);
}
}
}
/**
* 移除子控件时,移除父控件实体类中相关子控件数据,避免关闭后再次展开数据重现
*
* @param child 子控件实体
*/
protected void removeDataFromParent(T child) {
int position = getParentPosition(child);
if (position >= 0) {
IExpandable parent = (IExpandable) mData.get(position);
if (parent != child) {
parent.getSubItems().remove(child);
}
}
}
/**
* 该方法用于 IExpandable 树形列表。
* 如果不存在 Parent,则 return -1。
*
* @param position 所处列表的位置
* @return 父 position 在数据列表中的位置
*/
public int getParentPositionInAll(int position) {
List<T> data = getData();
MultiItemEntity multiItemEntity = getItem(position);
if (isExpandable(multiItemEntity)) {
IExpandable IExpandable = (IExpandable) multiItemEntity;
for (int i = position - 1; i >= 0; i--) {
MultiItemEntity entity = data.get(i);
if (isExpandable(entity) && IExpandable.getLevel() > ((IExpandable) entity).getLevel()) {
return i;
}
}
} else {
for (int i = position - 1; i >= 0; i--) {
MultiItemEntity entity = data.get(i);
if (isExpandable(entity)) {
return i;
}
}
}
return -1;
}
public boolean isExpandable(MultiItemEntity item) {
return item != null && item instanceof IExpandable;
}
}
/*
* Copyright 2013 Joan Zapata
* <p/>
* 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
* <p/>
* http://www.apache.org/licenses/LICENSE-2.0
* <p/>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chad.library.adapter.base;
import android.animation.Animator;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import androidx.annotation.IdRes;
import androidx.annotation.IntDef;
import androidx.annotation.IntRange;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import com.chad.library.adapter.base.animation.AlphaInAnimation;
import com.chad.library.adapter.base.animation.BaseAnimation;
import com.chad.library.adapter.base.animation.ScaleInAnimation;
import com.chad.library.adapter.base.animation.SlideInBottomAnimation;
import com.chad.library.adapter.base.animation.SlideInLeftAnimation;
import com.chad.library.adapter.base.animation.SlideInRightAnimation;
import com.chad.library.adapter.base.diff.BaseQuickAdapterListUpdateCallback;
import com.chad.library.adapter.base.diff.BaseQuickDiffCallback;
import com.chad.library.adapter.base.entity.IExpandable;
import com.chad.library.adapter.base.loadmore.LoadMoreView;
import com.chad.library.adapter.base.loadmore.SimpleLoadMoreView;
import com.chad.library.adapter.base.util.MultiTypeDelegate;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
/**
* https://github.com/CymChad/BaseRecyclerViewAdapterHelper
*/
public abstract class BaseQuickAdapter<T, K extends BaseViewHolder> extends RecyclerView.Adapter<K> {
//load more
private boolean mNextLoadEnable = false;
private boolean mLoadMoreEnable = false;
private boolean mLoading = false;
private LoadMoreView mLoadMoreView = new SimpleLoadMoreView();
private RequestLoadMoreListener mRequestLoadMoreListener;
private boolean mEnableLoadMoreEndClick = false;
//Animation
/**
* Use with {@link #openLoadAnimation}
*/
public static final int ALPHAIN = 0x00000001;
/**
* Use with {@link #openLoadAnimation}
*/
public static final int SCALEIN = 0x00000002;
/**
* Use with {@link #openLoadAnimation}
*/
public static final int SLIDEIN_BOTTOM = 0x00000003;
/**
* Use with {@link #openLoadAnimation}
*/
public static final int SLIDEIN_LEFT = 0x00000004;
/**
* Use with {@link #openLoadAnimation}
*/
public static final int SLIDEIN_RIGHT = 0x00000005;
private OnItemClickListener mOnItemClickListener;
private OnItemLongClickListener mOnItemLongClickListener;
private OnItemChildClickListener mOnItemChildClickListener;
private OnItemChildLongClickListener mOnItemChildLongClickListener;
private boolean mFirstOnlyEnable = true;
private boolean mOpenAnimationEnable = false;
private Interpolator mInterpolator = new LinearInterpolator();
private int mDuration = 300;
private int mLastPosition = -1;
private BaseAnimation mCustomAnimation;
private BaseAnimation mSelectAnimation = new AlphaInAnimation();
//header footer
private LinearLayout mHeaderLayout;
private LinearLayout mFooterLayout;
//empty
private FrameLayout mEmptyLayout;
private boolean mIsUseEmpty = true;
private boolean mHeadAndEmptyEnable;
private boolean mFootAndEmptyEnable;
protected static final String TAG = BaseQuickAdapter.class.getSimpleName();
protected Context mContext;
protected int mLayoutResId;
protected LayoutInflater mLayoutInflater;
protected List<T> mData;
public static final int HEADER_VIEW = 0x00000111;
public static final int LOADING_VIEW = 0x00000222;
public static final int FOOTER_VIEW = 0x00000333;
public static final int EMPTY_VIEW = 0x00000555;
/**
* up fetch start
*/
private boolean mUpFetchEnable;
private boolean mUpFetching;
private UpFetchListener mUpFetchListener;
private RecyclerView mRecyclerView;
private int mPreLoadNumber = 1;
/**
* start up fetch position, default is 1.
*/
private int mStartUpFetchPosition = 1;
/**
* if asFlow is true, footer/header will arrange like normal item view.
* only works when use {@link GridLayoutManager},and it will ignore span size.
*/
private boolean headerViewAsFlow, footerViewAsFlow;
@IntDef({ALPHAIN, SCALEIN, SLIDEIN_BOTTOM, SLIDEIN_LEFT, SLIDEIN_RIGHT})
@Retention(RetentionPolicy.SOURCE)
public @interface AnimationType {
}
protected RecyclerView getRecyclerView() {
return mRecyclerView;
}
private void setRecyclerView(RecyclerView recyclerView) {
mRecyclerView = recyclerView;
}
private void checkNotNull() {
if (getRecyclerView() == null) {
throw new IllegalStateException("please bind recyclerView first!");
}
}
/**
* same as recyclerView.setAdapter(), and save the instance of recyclerView
*/
public void bindToRecyclerView(RecyclerView recyclerView) {
if (getRecyclerView() != null) {
throw new IllegalStateException("Don't bind twice");
}
setRecyclerView(recyclerView);
getRecyclerView().setAdapter(this);
}
/**
* @see #setOnLoadMoreListener(RequestLoadMoreListener, RecyclerView)
* @deprecated This method is because it can lead to crash: always call this method while RecyclerView is computing a layout or scrolling.
* Please use {@link #setOnLoadMoreListener(RequestLoadMoreListener, RecyclerView)}
*/
@Deprecated
public void setOnLoadMoreListener(RequestLoadMoreListener requestLoadMoreListener) {
openLoadMore(requestLoadMoreListener);
}
private void openLoadMore(RequestLoadMoreListener requestLoadMoreListener) {
this.mRequestLoadMoreListener = requestLoadMoreListener;
mNextLoadEnable = true;
mLoadMoreEnable = true;
mLoading = false;
}
public void setOnLoadMoreListener(RequestLoadMoreListener requestLoadMoreListener, RecyclerView recyclerView) {
openLoadMore(requestLoadMoreListener);
if (getRecyclerView() == null) {
setRecyclerView(recyclerView);
}
}
/**
* bind recyclerView {@link #bindToRecyclerView(RecyclerView)} before use!
*
* @see #disableLoadMoreIfNotFullPage(RecyclerView)
*/
public void disableLoadMoreIfNotFullPage() {
checkNotNull();
disableLoadMoreIfNotFullPage(getRecyclerView());
}
/**
* check if full page after {@link #setNewData(List)}, if full, it will enable load more again.
* <p>
* 不是配置项!!
* <p>
* 这个方法是用来检查是否满一屏的,所以只推荐在 {@link #setNewData(List)} 之后使用
* 原理很简单,先关闭 load more,检查完了再决定是否开启
* <p>
* 不是配置项!!
*
* @param recyclerView your recyclerView
* @see #setNewData(List)
*/
public void disableLoadMoreIfNotFullPage(RecyclerView recyclerView) {
setEnableLoadMore(false);
if (recyclerView == null) return;
RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
if (manager == null) return;
if (manager instanceof LinearLayoutManager) {
final LinearLayoutManager linearLayoutManager = (LinearLayoutManager) manager;
recyclerView.postDelayed(new Runnable() {
@Override
public void run() {
if (isFullScreen(linearLayoutManager)) {
setEnableLoadMore(true);
}
}
}, 50);
} else if (manager instanceof StaggeredGridLayoutManager) {
final StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) manager;
recyclerView.postDelayed(new Runnable() {
@Override
public void run() {
final int[] positions = new int[staggeredGridLayoutManager.getSpanCount()];
staggeredGridLayoutManager.findLastCompletelyVisibleItemPositions(positions);
int pos = getTheBiggestNumber(positions) + 1;
if (pos != getItemCount()) {
setEnableLoadMore(true);
}
}
}, 50);
}
}
private boolean isFullScreen(LinearLayoutManager llm) {
return (llm.findLastCompletelyVisibleItemPosition() + 1) != getItemCount() ||
llm.findFirstCompletelyVisibleItemPosition() != 0;
}
private int getTheBiggestNumber(int[] numbers) {
int tmp = -1;
if (numbers == null || numbers.length == 0) {
return tmp;
}
for (int num : numbers) {
if (num > tmp) {
tmp = num;
}
}
return tmp;
}
public void setUpFetchEnable(boolean upFetch) {
this.mUpFetchEnable = upFetch;
}
public boolean isUpFetchEnable() {
return mUpFetchEnable;
}
public void setStartUpFetchPosition(int startUpFetchPosition) {
mStartUpFetchPosition = startUpFetchPosition;
}
private void autoUpFetch(int positions) {
if (!isUpFetchEnable() || isUpFetching()) {
return;
}
if (positions <= mStartUpFetchPosition && mUpFetchListener != null) {
mUpFetchListener.onUpFetch();
}
}
public boolean isUpFetching() {
return mUpFetching;
}
public void setUpFetching(boolean upFetching) {
this.mUpFetching = upFetching;
}
public void setUpFetchListener(UpFetchListener upFetchListener) {
mUpFetchListener = upFetchListener;
}
public interface UpFetchListener {
void onUpFetch();
}
/**
* up fetch end
*/
public void setNotDoAnimationCount(int count) {
mLastPosition = count;
}
/**
* Set custom load more
*
* @param loadingView 加载视图
*/
public void setLoadMoreView(LoadMoreView loadingView) {
this.mLoadMoreView = loadingView;
}
/**
* Load more view count
*
* @return 0 or 1
*/
public int getLoadMoreViewCount() {
if (mRequestLoadMoreListener == null || !mLoadMoreEnable) {
return 0;
}
if (!mNextLoadEnable && mLoadMoreView.isLoadEndMoreGone()) {
return 0;
}
if (mData.size() == 0) {
return 0;
}
return 1;
}
/**
* Gets to load more locations
*
* @return
*/
public int getLoadMoreViewPosition() {
return getHeaderLayoutCount() + mData.size() + getFooterLayoutCount();
}
/**
* @return Whether the Adapter is actively showing load
* progress.
*/
public boolean isLoading() {
return mLoading;
}
/**
* Refresh end, no more data
*/
public void loadMoreEnd() {
loadMoreEnd(false);
}
/**
* Refresh end, no more data
*
* @param gone if true gone the load more view
*/
public void loadMoreEnd(boolean gone) {
if (getLoadMoreViewCount() == 0) {
return;
}
mLoading = false;
mNextLoadEnable = false;
mLoadMoreView.setLoadMoreEndGone(gone);
if (gone) {
notifyItemRemoved(getLoadMoreViewPosition());
} else {
mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_END);
notifyItemChanged(getLoadMoreViewPosition());
}
}
/**
* Refresh complete
*/
public void loadMoreComplete() {
if (getLoadMoreViewCount() == 0) {
return;
}
mLoading = false;
mNextLoadEnable = true;
mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_DEFAULT);
notifyItemChanged(getLoadMoreViewPosition());
}
/**
* Refresh failed
*/
public void loadMoreFail() {
if (getLoadMoreViewCount() == 0) {
return;
}
mLoading = false;
mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_FAIL);
notifyItemChanged(getLoadMoreViewPosition());
}
/**
* Set the enabled state of load more.
*
* @param enable True if load more is enabled, false otherwise.
*/
public void setEnableLoadMore(boolean enable) {
int oldLoadMoreCount = getLoadMoreViewCount();
mLoadMoreEnable = enable;
int newLoadMoreCount = getLoadMoreViewCount();
if (oldLoadMoreCount == 1) {
if (newLoadMoreCount == 0) {
notifyItemRemoved(getLoadMoreViewPosition());
}
} else {
if (newLoadMoreCount == 1) {
mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_DEFAULT);
notifyItemInserted(getLoadMoreViewPosition());
}
}
}
/**
* Returns the enabled status for load more.
*
* @return True if load more is enabled, false otherwise.
*/
public boolean isLoadMoreEnable() {
return mLoadMoreEnable;
}
/**
* Sets the duration of the animation.
*
* @param duration The length of the animation, in milliseconds.
*/
public void setDuration(int duration) {
mDuration = duration;
}
/**
* If you have added headeview, the notification view refreshes.
* Do not need to care about the number of headview, only need to pass in the position of the final view
*
* @param position
*/
public final void refreshNotifyItemChanged(int position) {
notifyItemChanged(position + getHeaderLayoutCount());
}
/**
* Same as QuickAdapter#QuickAdapter(Context,int) but with
* some initialization data.
*
* @param layoutResId The layout resource id of each item.
* @param data A new list is created out of this one to avoid mutable list
*/
public BaseQuickAdapter(@LayoutRes int layoutResId, @Nullable List<T> data) {
this.mData = data == null ? new ArrayList<T>() : data;
if (layoutResId != 0) {
this.mLayoutResId = layoutResId;
}
}
public BaseQuickAdapter(@Nullable List<T> data) {
this(0, data);
}
public BaseQuickAdapter(@LayoutRes int layoutResId) {
this(layoutResId, null);
}
/**
* setting up a new instance to data;
*
* @param data
*/
public void setNewData(@Nullable List<T> data) {
this.mData = data == null ? new ArrayList<T>() : data;
if (mRequestLoadMoreListener != null) {
mNextLoadEnable = true;
mLoadMoreEnable = true;
mLoading = false;
mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_DEFAULT);
}
mLastPosition = -1;
notifyDataSetChanged();
}
/**
* use Diff setting up a new instance to data
*
* @param baseQuickDiffCallback implementation {@link BaseQuickDiffCallback}
*/
public void setNewDiffData(@NonNull BaseQuickDiffCallback<T> baseQuickDiffCallback) {
setNewDiffData(baseQuickDiffCallback, false);
}
/**
* use Diff setting up a new instance to data.
* this is sync, if you need use async, see {@link #setNewDiffData(DiffUtil.DiffResult, List)}.
*
* @param baseQuickDiffCallback implementation {@link BaseQuickDiffCallback}.
* @param detectMoves Whether to detect the movement of the Item
*/
public void setNewDiffData(@NonNull BaseQuickDiffCallback<T> baseQuickDiffCallback, boolean detectMoves) {
if (getEmptyViewCount() == 1) {
// If the current view is an empty view, set the new data directly without diff
setNewData(baseQuickDiffCallback.getNewList());
return;
}
baseQuickDiffCallback.setOldList(this.getData());
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(baseQuickDiffCallback, detectMoves);
diffResult.dispatchUpdatesTo(new BaseQuickAdapterListUpdateCallback(this));
mData = baseQuickDiffCallback.getNewList();
}
/**
* use DiffResult setting up a new instance to data
*
* If you need to use async computing Diff, please use this method.
* You only need to tell the calculation result,
* this adapter does not care about the calculation process.
*
* @param diffResult DiffResult
* @param newData New Data
*/
public void setNewDiffData(@NonNull DiffUtil.DiffResult diffResult, @NonNull List<T> newData) {
if (getEmptyViewCount() == 1) {
// If the current view is an empty view, set the new data directly without diff
setNewData(newData);
return;
}
diffResult.dispatchUpdatesTo(new BaseQuickAdapterListUpdateCallback(BaseQuickAdapter.this));
mData = newData;
}
/**
* insert a item associated with the specified position of adapter
*
* @param position
* @param item
* @deprecated use {@link #addData(int, Object)} instead
*/
@Deprecated
public void add(@IntRange(from = 0) int position, @NonNull T item) {
addData(position, item);
}
/**
* add one new data in to certain location
*
* @param position
*/
public void addData(@IntRange(from = 0) int position, @NonNull T data) {
mData.add(position, data);
notifyItemInserted(position + getHeaderLayoutCount());
compatibilityDataSizeChanged(1);
}
/**
* add one new data
*/
public void addData(@NonNull T data) {
mData.add(data);
notifyItemInserted(mData.size() + getHeaderLayoutCount());
compatibilityDataSizeChanged(1);
}
/**
* remove the item associated with the specified position of adapter
*
* @param position
*/
public void remove(@IntRange(from = 0) int position) {
mData.remove(position);
int internalPosition = position + getHeaderLayoutCount();
notifyItemRemoved(internalPosition);
compatibilityDataSizeChanged(0);
notifyItemRangeChanged(internalPosition, mData.size() - internalPosition);
}
/**
* change data
*/
public void setData(@IntRange(from = 0) int index, @NonNull T data) {
mData.set(index, data);
notifyItemChanged(index + getHeaderLayoutCount());
}
/**
* add new data in to certain location
*
* @param position the insert position
* @param newData the new data collection
*/
public void addData(@IntRange(from = 0) int position, @NonNull Collection<? extends T> newData) {
mData.addAll(position, newData);
notifyItemRangeInserted(position + getHeaderLayoutCount(), newData.size());
compatibilityDataSizeChanged(newData.size());
}
/**
* add new data to the end of mData
*
* @param newData the new data collection
*/
public void addData(@NonNull Collection<? extends T> newData) {
mData.addAll(newData);
notifyItemRangeInserted(mData.size() - newData.size() + getHeaderLayoutCount(), newData.size());
compatibilityDataSizeChanged(newData.size());
}
/**
* use data to replace all item in mData. this method is different {@link #setNewData(List)},
* it doesn't change the mData reference
*
* @param data data collection
*/
public void replaceData(@NonNull Collection<? extends T> data) {
// 不是同一个引用才清空列表
if (data != mData) {
mData.clear();
mData.addAll(data);
}
notifyDataSetChanged();
}
/**
* compatible getLoadMoreViewCount and getEmptyViewCount may change
*
* @param size Need compatible data size
*/
private void compatibilityDataSizeChanged(int size) {
final int dataSize = mData == null ? 0 : mData.size();
if (dataSize == size) {
notifyDataSetChanged();
}
}
/**
* Get the data of list
*
* @return 列表数据
*/
@NonNull
public List<T> getData() {
return mData;
}
/**
* Get the data item associated with the specified position in the data set.
*
* @param position Position of the item whose data we want within the adapter's
* data set.
* @return The data at the specified position.
*/
@Nullable
public T getItem(@IntRange(from = 0) int position) {
if (position >= 0 && position < mData.size())
return mData.get(position);
else
return null;
}
/**
* if setHeadView will be return 1 if not will be return 0.
* notice: Deprecated! Use {@link ViewGroup#getChildCount()} of {@link #getHeaderLayout()} to replace.
*
* @return
*/
@Deprecated
public int getHeaderViewsCount() {
return getHeaderLayoutCount();
}
/**
* if mFooterLayout will be return 1 or not will be return 0.
* notice: Deprecated! Use {@link ViewGroup#getChildCount()} of {@link #getFooterLayout()} to replace.
*
* @return
*/
@Deprecated
public int getFooterViewsCount() {
return getFooterLayoutCount();
}
/**
* if addHeaderView will be return 1, if not will be return 0
*/
public int getHeaderLayoutCount() {
if (mHeaderLayout == null || mHeaderLayout.getChildCount() == 0) {
return 0;
}
return 1;
}
/**
* if addFooterView will be return 1, if not will be return 0
*/
public int getFooterLayoutCount() {
if (mFooterLayout == null || mFooterLayout.getChildCount() == 0) {
return 0;
}
return 1;
}
/**
* if show empty view will be return 1 or not will be return 0
*
* @return
*/
public int getEmptyViewCount() {
if (mEmptyLayout == null || mEmptyLayout.getChildCount() == 0) {
return 0;
}
if (!mIsUseEmpty) {
return 0;
}
if (mData.size() != 0) {
return 0;
}
return 1;
}
@Override
public int getItemCount() {
int count;
if (1 == getEmptyViewCount()) {
count = 1;
if (mHeadAndEmptyEnable && getHeaderLayoutCount() != 0) {
count++;
}
if (mFootAndEmptyEnable && getFooterLayoutCount() != 0) {
count++;
}
} else {
count = getHeaderLayoutCount() + mData.size() + getFooterLayoutCount() + getLoadMoreViewCount();
}
return count;
}
@Override
public int getItemViewType(int position) {
if (getEmptyViewCount() == 1) {
boolean header = mHeadAndEmptyEnable && getHeaderLayoutCount() != 0;
switch (position) {
case 0:
if (header) {
return HEADER_VIEW;
} else {
return EMPTY_VIEW;
}
case 1:
if (header) {
return EMPTY_VIEW;
} else {
return FOOTER_VIEW;
}
case 2:
return FOOTER_VIEW;
default:
return EMPTY_VIEW;
}
}
int numHeaders = getHeaderLayoutCount();
if (position < numHeaders) {
return HEADER_VIEW;
} else {
int adjPosition = position - numHeaders;
int adapterCount = mData.size();
if (adjPosition < adapterCount) {
return getDefItemViewType(adjPosition);
} else {
adjPosition = adjPosition - adapterCount;
int numFooters = getFooterLayoutCount();
if (adjPosition < numFooters) {
return FOOTER_VIEW;
} else {
return LOADING_VIEW;
}
}
}
}
protected int getDefItemViewType(int position) {
if (mMultiTypeDelegate != null) {
return mMultiTypeDelegate.getDefItemViewType(mData, position);
}
return super.getItemViewType(position);
}
@NonNull
@Override
public K onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
K baseViewHolder = null;
this.mContext = parent.getContext();
this.mLayoutInflater = LayoutInflater.from(mContext);
switch (viewType) {
case LOADING_VIEW:
baseViewHolder = getLoadingView(parent);
break;
case HEADER_VIEW:
baseViewHolder = createBaseViewHolder(mHeaderLayout);
break;
case EMPTY_VIEW:
baseViewHolder = createBaseViewHolder(mEmptyLayout);
break;
case FOOTER_VIEW:
baseViewHolder = createBaseViewHolder(mFooterLayout);
break;
default:
baseViewHolder = onCreateDefViewHolder(parent, viewType);
bindViewClickListener(baseViewHolder);
}
baseViewHolder.setAdapter(this);
return baseViewHolder;
}
private K getLoadingView(ViewGroup parent) {
View view = getItemView(mLoadMoreView.getLayoutId(), parent);
K holder = createBaseViewHolder(view);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mLoadMoreView.getLoadMoreStatus() == LoadMoreView.STATUS_FAIL) {
notifyLoadMoreToLoading();
}
if (mEnableLoadMoreEndClick && mLoadMoreView.getLoadMoreStatus() == LoadMoreView.STATUS_END) {
notifyLoadMoreToLoading();
}
}
});
return holder;
}
/**
* The notification starts the callback and loads more
*/
public void notifyLoadMoreToLoading() {
if (mLoadMoreView.getLoadMoreStatus() == LoadMoreView.STATUS_LOADING) {
return;
}
mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_DEFAULT);
notifyItemChanged(getLoadMoreViewPosition());
}
/**
* Load more without data when settings are clicked loaded
*
* @param enable
*/
public void enableLoadMoreEndClick(boolean enable) {
mEnableLoadMoreEndClick = enable;
}
/**
* Called when a view created by this adapter has been attached to a window.
* simple to solve item will layout using all
* {@link #setFullSpan(RecyclerView.ViewHolder)}
*
* @param holder
*/
@Override
public void onViewAttachedToWindow(@NonNull K holder) {
super.onViewAttachedToWindow(holder);
int type = holder.getItemViewType();
if (type == EMPTY_VIEW || type == HEADER_VIEW || type == FOOTER_VIEW || type == LOADING_VIEW) {
setFullSpan(holder);
} else {
addAnimation(holder);
}
}
/**
* When set to true, the item will layout using all span area. That means, if orientation
* is vertical, the view will have full width; if orientation is horizontal, the view will
* have full height.
* if the hold view use StaggeredGridLayoutManager they should using all span area
*
* @param holder True if this item should traverse all spans.
*/
protected void setFullSpan(RecyclerView.ViewHolder holder) {
if (holder.itemView.getLayoutParams() instanceof StaggeredGridLayoutManager.LayoutParams) {
StaggeredGridLayoutManager.LayoutParams params = (StaggeredGridLayoutManager.LayoutParams) holder
.itemView.getLayoutParams();
params.setFullSpan(true);
}
}
@Override
public void onAttachedToRecyclerView(@NonNull final RecyclerView recyclerView) {
super.onAttachedToRecyclerView(recyclerView);
RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
if (manager instanceof GridLayoutManager) {
final GridLayoutManager gridManager = ((GridLayoutManager) manager);
gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
int type = getItemViewType(position);
if (type == HEADER_VIEW && isHeaderViewAsFlow()) {
return 1;
}
if (type == FOOTER_VIEW && isFooterViewAsFlow()) {
return 1;
}
if (mSpanSizeLookup == null) {
return isFixedViewType(type) ? gridManager.getSpanCount() : 1;
} else {
return (isFixedViewType(type)) ? gridManager.getSpanCount() : mSpanSizeLookup.getSpanSize(gridManager,
position - getHeaderLayoutCount());
}
}
});
}
}
protected boolean isFixedViewType(int type) {
return type == EMPTY_VIEW || type == HEADER_VIEW || type == FOOTER_VIEW || type ==
LOADING_VIEW;
}
public void setHeaderViewAsFlow(boolean headerViewAsFlow) {
this.headerViewAsFlow = headerViewAsFlow;
}
public boolean isHeaderViewAsFlow() {
return headerViewAsFlow;
}
public void setFooterViewAsFlow(boolean footerViewAsFlow) {
this.footerViewAsFlow = footerViewAsFlow;
}
public boolean isFooterViewAsFlow() {
return footerViewAsFlow;
}
private SpanSizeLookup mSpanSizeLookup;
public interface SpanSizeLookup {
int getSpanSize(GridLayoutManager gridLayoutManager, int position);
}
/**
* @param spanSizeLookup instance to be used to query number of spans occupied by each item
*/
public void setSpanSizeLookup(SpanSizeLookup spanSizeLookup) {
this.mSpanSizeLookup = spanSizeLookup;
}
/**
* To bind different types of holder and solve different the bind events
*
* @param holder
* @param position
* @see #getDefItemViewType(int)
*/
@Override
public void onBindViewHolder(@NonNull K holder, int position) {
//Add up fetch logic, almost like load more, but simpler.
autoUpFetch(position);
//Do not move position, need to change before LoadMoreView binding
autoLoadMore(position);
int viewType = holder.getItemViewType();
switch (viewType) {
case 0:
convert(holder, getItem(position - getHeaderLayoutCount()));
break;
case LOADING_VIEW:
mLoadMoreView.convert(holder);
break;
case HEADER_VIEW:
break;
case EMPTY_VIEW:
break;
case FOOTER_VIEW:
break;
default:
convert(holder, getItem(position - getHeaderLayoutCount()));
break;
}
}
/**
* To bind different types of holder and solve different the bind events
*
* the ViewHolder is currently bound to old data and Adapter may run an efficient partial
* update using the payload info. If the payload is empty, Adapter run a full bind.
*
* @param holder The ViewHolder which should be updated to represent the contents of the
* item at the given position in the data set.
* @param position The position of the item within the adapter's data set.
* @param payloads A non-null list of merged payloads. Can be empty list if requires full
* update.
* @see #getDefItemViewType(int)
*/
@Override
public void onBindViewHolder(@NonNull K holder, int position, @NonNull List<Object> payloads) {
if (payloads.isEmpty()) {
onBindViewHolder(holder, position);
return;
}
//Add up fetch logic, almost like load more, but simpler.
autoUpFetch(position);
//Do not move position, need to change before LoadMoreView binding
autoLoadMore(position);
int viewType = holder.getItemViewType();
switch (viewType) {
case 0:
convertPayloads(holder, getItem(position - getHeaderLayoutCount()), payloads);
break;
case LOADING_VIEW:
mLoadMoreView.convert(holder);
break;
case HEADER_VIEW:
break;
case EMPTY_VIEW:
break;
case FOOTER_VIEW:
break;
default:
convertPayloads(holder, getItem(position - getHeaderLayoutCount()), payloads);
break;
}
}
private void bindViewClickListener(final BaseViewHolder baseViewHolder) {
if (baseViewHolder == null) {
return;
}
final View view = baseViewHolder.itemView;
if (getOnItemClickListener() != null) {
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = baseViewHolder.getAdapterPosition();
if (position == RecyclerView.NO_POSITION) {
return;
}
position -= getHeaderLayoutCount();
setOnItemClick(v, position);
}
});
}
if (getOnItemLongClickListener() != null) {
view.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
int position = baseViewHolder.getAdapterPosition();
if (position == RecyclerView.NO_POSITION) {
return false;
}
position -= getHeaderLayoutCount();
return setOnItemLongClick(v, position);
}
});
}
}
/**
* override this method if you want to override click event logic
*
* @param v
* @param position
*/
public void setOnItemClick(View v, int position) {
getOnItemClickListener().onItemClick(BaseQuickAdapter.this, v, position);
}
/**
* override this method if you want to override longClick event logic
*
* @param v
* @param position
* @return
*/
public boolean setOnItemLongClick(View v, int position) {
return getOnItemLongClickListener().onItemLongClick(BaseQuickAdapter.this, v, position);
}
private MultiTypeDelegate<T> mMultiTypeDelegate;
public void setMultiTypeDelegate(MultiTypeDelegate<T> multiTypeDelegate) {
mMultiTypeDelegate = multiTypeDelegate;
}
public MultiTypeDelegate<T> getMultiTypeDelegate() {
return mMultiTypeDelegate;
}
protected K onCreateDefViewHolder(ViewGroup parent, int viewType) {
int layoutId = mLayoutResId;
if (mMultiTypeDelegate != null) {
layoutId = mMultiTypeDelegate.getLayoutId(viewType);
}
return createBaseViewHolder(parent, layoutId);
}
protected K createBaseViewHolder(ViewGroup parent, int layoutResId) {
return createBaseViewHolder(getItemView(layoutResId, parent));
}
/**
* if you want to use subclass of BaseViewHolder in the adapter,
* you must override the method to create new ViewHolder.
*
* @param view view
* @return new ViewHolder
*/
@SuppressWarnings("unchecked")
protected K createBaseViewHolder(View view) {
Class temp = getClass();
Class z = null;
while (z == null && null != temp) {
z = getInstancedGenericKClass(temp);
temp = temp.getSuperclass();
}
K k;
// 泛型擦除会导致z为null
if (z == null) {
k = (K) new BaseViewHolder(view);
} else {
k = createGenericKInstance(z, view);
}
return k != null ? k : (K) new BaseViewHolder(view);
}
/**
* try to create Generic K instance
*
* @param z
* @param view
* @return
*/
@SuppressWarnings("unchecked")
private K createGenericKInstance(Class z, View view) {
try {
Constructor constructor;
// inner and unstatic class
if (z.isMemberClass() && !Modifier.isStatic(z.getModifiers())) {
constructor = z.getDeclaredConstructor(getClass(), View.class);
constructor.setAccessible(true);
return (K) constructor.newInstance(this, view);
} else {
constructor = z.getDeclaredConstructor(View.class);
constructor.setAccessible(true);
return (K) constructor.newInstance(view);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
/**
* get generic parameter K
*
* @param z
* @return
*/
private Class getInstancedGenericKClass(Class z) {
Type type = z.getGenericSuperclass();
if (type instanceof ParameterizedType) {
Type[] types = ((ParameterizedType) type).getActualTypeArguments();
for (Type temp : types) {
if (temp instanceof Class) {
Class tempClass = (Class) temp;
if (BaseViewHolder.class.isAssignableFrom(tempClass)) {
return tempClass;
}
} else if (temp instanceof ParameterizedType) {
Type rawType = ((ParameterizedType) temp).getRawType();
if (rawType instanceof Class && BaseViewHolder.class.isAssignableFrom((Class<?>) rawType)) {
return (Class<?>) rawType;
}
}
}
}
return null;
}
/**
* Return root layout of header
*/
public LinearLayout getHeaderLayout() {
return mHeaderLayout;
}
/**
* Return root layout of footer
*/
public LinearLayout getFooterLayout() {
return mFooterLayout;
}
/**
* Append header to the rear of the mHeaderLayout.
*
* @param header
*/
public int addHeaderView(View header) {
return addHeaderView(header, -1);
}
/**
* Add header view to mHeaderLayout and set header view position in mHeaderLayout.
* When index = -1 or index >= child count in mHeaderLayout,
* the effect of this method is the same as that of {@link #addHeaderView(View)}.
*
* @param header
* @param index the position in mHeaderLayout of this header.
* When index = -1 or index >= child count in mHeaderLayout,
* the effect of this method is the same as that of {@link #addHeaderView(View)}.
*/
public int addHeaderView(View header, int index) {
return addHeaderView(header, index, LinearLayout.VERTICAL);
}
/**
* @param header
* @param index
* @param orientation
*/
public int addHeaderView(View header,final int index, int orientation) {
if (mHeaderLayout == null) {
mHeaderLayout = new LinearLayout(header.getContext());
if (orientation == LinearLayout.VERTICAL) {
mHeaderLayout.setOrientation(LinearLayout.VERTICAL);
mHeaderLayout.setLayoutParams(new RecyclerView.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
} else {
mHeaderLayout.setOrientation(LinearLayout.HORIZONTAL);
mHeaderLayout.setLayoutParams(new RecyclerView.LayoutParams(WRAP_CONTENT, MATCH_PARENT));
}
}
final int childCount = mHeaderLayout.getChildCount();
int mIndex =index;
if (index < 0 || index > childCount) {
mIndex = childCount;
}
mHeaderLayout.addView(header, mIndex);
if (mHeaderLayout.getChildCount() == 1) {
int position = getHeaderViewPosition();
if (position != -1) {
notifyItemInserted(position);
}
}
return mIndex;
}
public int setHeaderView(View header) {
return setHeaderView(header, 0, LinearLayout.VERTICAL);
}
public int setHeaderView(View header, int index) {
return setHeaderView(header, index, LinearLayout.VERTICAL);
}
public int setHeaderView(View header, int index, int orientation) {
if (mHeaderLayout == null || mHeaderLayout.getChildCount() <= index) {
return addHeaderView(header, index, orientation);
} else {
mHeaderLayout.removeViewAt(index);
mHeaderLayout.addView(header, index);
return index;
}
}
/**
* Append footer to the rear of the mFooterLayout.
*
* @param footer
*/
public int addFooterView(View footer) {
return addFooterView(footer, -1, LinearLayout.VERTICAL);
}
public int addFooterView(View footer, int index) {
return addFooterView(footer, index, LinearLayout.VERTICAL);
}
/**
* Add footer view to mFooterLayout and set footer view position in mFooterLayout.
* When index = -1 or index >= child count in mFooterLayout,
* the effect of this method is the same as that of {@link #addFooterView(View)}.
*
* @param footer
* @param index the position in mFooterLayout of this footer.
* When index = -1 or index >= child count in mFooterLayout,
* the effect of this method is the same as that of {@link #addFooterView(View)}.
*/
public int addFooterView(View footer, int index, int orientation) {
if (mFooterLayout == null) {
mFooterLayout = new LinearLayout(footer.getContext());
if (orientation == LinearLayout.VERTICAL) {
mFooterLayout.setOrientation(LinearLayout.VERTICAL);
mFooterLayout.setLayoutParams(new RecyclerView.LayoutParams(MATCH_PARENT, WRAP_CONTENT));
} else {
mFooterLayout.setOrientation(LinearLayout.HORIZONTAL);
mFooterLayout.setLayoutParams(new RecyclerView.LayoutParams(WRAP_CONTENT, MATCH_PARENT));
}
}
final int childCount = mFooterLayout.getChildCount();
if (index < 0 || index > childCount) {
index = childCount;
}
mFooterLayout.addView(footer, index);
if (mFooterLayout.getChildCount() == 1) {
int position = getFooterViewPosition();
if (position != -1) {
notifyItemInserted(position);
}
}
return index;
}
public int setFooterView(View header) {
return setFooterView(header, 0, LinearLayout.VERTICAL);
}
public int setFooterView(View header, int index) {
return setFooterView(header, index, LinearLayout.VERTICAL);
}
public int setFooterView(View header, int index, int orientation) {
if (mFooterLayout == null || mFooterLayout.getChildCount() <= index) {
return addFooterView(header, index, orientation);
} else {
mFooterLayout.removeViewAt(index);
mFooterLayout.addView(header, index);
return index;
}
}
/**
* remove header view from mHeaderLayout.
* When the child count of mHeaderLayout is 0, mHeaderLayout will be set to null.
*
* @param header
*/
public void removeHeaderView(View header) {
if (getHeaderLayoutCount() == 0) return;
mHeaderLayout.removeView(header);
if (mHeaderLayout.getChildCount() == 0) {
int position = getHeaderViewPosition();
if (position != -1) {
notifyItemRemoved(position);
}
}
}
/**
* remove footer view from mFooterLayout,
* When the child count of mFooterLayout is 0, mFooterLayout will be set to null.
*
* @param footer
*/
public void removeFooterView(View footer) {
if (getFooterLayoutCount() == 0) return;
mFooterLayout.removeView(footer);
if (mFooterLayout.getChildCount() == 0) {
int position = getFooterViewPosition();
if (position != -1) {
notifyItemRemoved(position);
}
}
}
/**
* remove all header view from mHeaderLayout and set null to mHeaderLayout
*/
public void removeAllHeaderView() {
if (getHeaderLayoutCount() == 0) return;
mHeaderLayout.removeAllViews();
int position = getHeaderViewPosition();
if (position != -1) {
notifyItemRemoved(position);
}
}
/**
* remove all footer view from mFooterLayout and set null to mFooterLayout
*/
public void removeAllFooterView() {
if (getFooterLayoutCount() == 0) return;
mFooterLayout.removeAllViews();
int position = getFooterViewPosition();
if (position != -1) {
notifyItemRemoved(position);
}
}
private int getHeaderViewPosition() {
//Return to header view notify position
if (getEmptyViewCount() == 1) {
if (mHeadAndEmptyEnable) {
return 0;
}
} else {
return 0;
}
return -1;
}
private int getFooterViewPosition() {
//Return to footer view notify position
if (getEmptyViewCount() == 1) {
int position = 1;
if (mHeadAndEmptyEnable && getHeaderLayoutCount() != 0) {
position++;
}
if (mFootAndEmptyEnable) {
return position;
}
} else {
return getHeaderLayoutCount() + mData.size();
}
return -1;
}
public void setEmptyView(int layoutResId, ViewGroup viewGroup) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(layoutResId, viewGroup, false);
setEmptyView(view);
}
/**
* bind recyclerView {@link #bindToRecyclerView(RecyclerView)} before use!
* Recommend you to use {@link #setEmptyView(int, ViewGroup)}
*
* @see #bindToRecyclerView(RecyclerView)
*/
@Deprecated
public void setEmptyView(int layoutResId) {
checkNotNull();
setEmptyView(layoutResId, getRecyclerView());
}
public void setEmptyView(View emptyView) {
int oldItemCount = getItemCount();
boolean insert = false;
if (mEmptyLayout == null) {
mEmptyLayout = new FrameLayout(emptyView.getContext());
final RecyclerView.LayoutParams layoutParams = new RecyclerView.LayoutParams(RecyclerView.LayoutParams.MATCH_PARENT, RecyclerView.LayoutParams.MATCH_PARENT);
final ViewGroup.LayoutParams lp = emptyView.getLayoutParams();
if (lp != null) {
layoutParams.width = lp.width;
layoutParams.height = lp.height;
}
mEmptyLayout.setLayoutParams(layoutParams);
insert = true;
}
mEmptyLayout.removeAllViews();
mEmptyLayout.addView(emptyView);
mIsUseEmpty = true;
if (insert && getEmptyViewCount() == 1) {
int position = 0;
if (mHeadAndEmptyEnable && getHeaderLayoutCount() != 0) {
position++;
}
if (getItemCount() > oldItemCount) {
notifyItemInserted(position);
} else {
notifyDataSetChanged();
}
}
}
/**
* Call before {@link RecyclerView#setAdapter(RecyclerView.Adapter)}
*
* @param isHeadAndEmpty false will not show headView if the data is empty true will show emptyView and headView
*/
public void setHeaderAndEmpty(boolean isHeadAndEmpty) {
setHeaderFooterEmpty(isHeadAndEmpty, false);
}
/**
* set emptyView show if adapter is empty and want to show headview and footview
* Call before {@link RecyclerView#setAdapter(RecyclerView.Adapter)}
*
* @param isHeadAndEmpty
* @param isFootAndEmpty
*/
public void setHeaderFooterEmpty(boolean isHeadAndEmpty, boolean isFootAndEmpty) {
mHeadAndEmptyEnable = isHeadAndEmpty;
mFootAndEmptyEnable = isFootAndEmpty;
}
/**
* Set whether to use empty view
*
* @param isUseEmpty
*/
public void isUseEmpty(boolean isUseEmpty) {
mIsUseEmpty = isUseEmpty;
}
/**
* When the current adapter is empty, the BaseQuickAdapter can display a special view
* called the empty view. The empty view is used to provide feedback to the user
* that no data is available in this AdapterView.
*
* @return The view to show if the adapter is empty.
*/
public View getEmptyView() {
return mEmptyLayout;
}
@Deprecated
public void setAutoLoadMoreSize(int preLoadNumber) {
setPreLoadNumber(preLoadNumber);
}
public void setPreLoadNumber(int preLoadNumber) {
if (preLoadNumber > 1) {
mPreLoadNumber = preLoadNumber;
}
}
private void autoLoadMore(int position) {
if (getLoadMoreViewCount() == 0) {
return;
}
if (position < getItemCount() - mPreLoadNumber) {
return;
}
if (mLoadMoreView.getLoadMoreStatus() != LoadMoreView.STATUS_DEFAULT) {
return;
}
mLoadMoreView.setLoadMoreStatus(LoadMoreView.STATUS_LOADING);
if (!mLoading) {
mLoading = true;
if (getRecyclerView() != null) {
getRecyclerView().post(new Runnable() {
@Override
public void run() {
mRequestLoadMoreListener.onLoadMoreRequested();
}
});
} else {
mRequestLoadMoreListener.onLoadMoreRequested();
}
}
}
/**
* add animation when you want to show time
*
* @param holder
*/
private void addAnimation(RecyclerView.ViewHolder holder) {
if (mOpenAnimationEnable) {
if (!mFirstOnlyEnable || holder.getLayoutPosition() > mLastPosition) {
BaseAnimation animation = null;
if (mCustomAnimation != null) {
animation = mCustomAnimation;
} else {
animation = mSelectAnimation;
}
for (Animator anim : animation.getAnimators(holder.itemView)) {
startAnim(anim, holder.getLayoutPosition());
}
mLastPosition = holder.getLayoutPosition();
}
}
}
/**
* set anim to start when loading
*
* @param anim
* @param index
*/
protected void startAnim(Animator anim, int index) {
anim.setDuration(mDuration).start();
anim.setInterpolator(mInterpolator);
}
/**
* @param layoutResId ID for an XML layout resource to load
* @param parent Optional view to be the parent of the generated hierarchy or else simply an object that
* provides a set of LayoutParams values for root of the returned
* hierarchy
* @return view will be return
*/
protected View getItemView(@LayoutRes int layoutResId, ViewGroup parent) {
return mLayoutInflater.inflate(layoutResId, parent, false);
}
public interface RequestLoadMoreListener {
void onLoadMoreRequested();
}
/**
* Set the view animation type.
*
* @param animationType One of {@link #ALPHAIN}, {@link #SCALEIN}, {@link #SLIDEIN_BOTTOM},
* {@link #SLIDEIN_LEFT}, {@link #SLIDEIN_RIGHT}.
*/
public void openLoadAnimation(@AnimationType int animationType) {
this.mOpenAnimationEnable = true;
mCustomAnimation = null;
switch (animationType) {
case ALPHAIN:
mSelectAnimation = new AlphaInAnimation();
break;
case SCALEIN:
mSelectAnimation = new ScaleInAnimation();
break;
case SLIDEIN_BOTTOM:
mSelectAnimation = new SlideInBottomAnimation();
break;
case SLIDEIN_LEFT:
mSelectAnimation = new SlideInLeftAnimation();
break;
case SLIDEIN_RIGHT:
mSelectAnimation = new SlideInRightAnimation();
break;
default:
break;
}
}
/**
* Set Custom ObjectAnimator
*
* @param animation ObjectAnimator
*/
public void openLoadAnimation(BaseAnimation animation) {
this.mOpenAnimationEnable = true;
this.mCustomAnimation = animation;
}
/**
* To open the animation when loading
*/
public void openLoadAnimation() {
this.mOpenAnimationEnable = true;
}
/**
* To close the animation when loading
*/
public void closeLoadAnimation() {
this.mOpenAnimationEnable = false;
}
/**
* {@link #addAnimation(RecyclerView.ViewHolder)}
*
* @param firstOnly true just show anim when first loading false show anim when load the data every time
*/
public void isFirstOnly(boolean firstOnly) {
this.mFirstOnlyEnable = firstOnly;
}
/**
* Implement this method and use the helper to adapt the view to the given item.
*
* @param helper A fully initialized helper.
* @param item The item that needs to be displayed.
*/
protected abstract void convert(@NonNull K helper, T item);
/**
* Optional implementation this method and use the helper to adapt the view to the given item.
*
* If {@link DiffUtil.Callback#getChangePayload(int, int)} is implemented,
* then {@link BaseQuickAdapter#convert(BaseViewHolder, Object)} will not execute, and will
* perform this method, Please implement this method for partial refresh.
*
* If use {@link RecyclerView.Adapter#notifyItemChanged(int, Object)} with payload,
* Will execute this method.
*
*
* @param helper A fully initialized helper.
* @param item The item that needs to be displayed.
* @param payloads payload info.
*/
protected void convertPayloads(@NonNull K helper, T item, @NonNull List<Object> payloads) {}
/**
* get the specific view by position,e.g. getViewByPosition(2, R.id.textView)
* <p>
* bind recyclerView {@link #bindToRecyclerView(RecyclerView)} before use!
*
* @see #bindToRecyclerView(RecyclerView)
*/
@Nullable
public View getViewByPosition(int position, @IdRes int viewId) {
checkNotNull();
return getViewByPosition(getRecyclerView(), position, viewId);
}
@Nullable
public View getViewByPosition(RecyclerView recyclerView, int position, @IdRes int viewId) {
if (recyclerView == null) {
return null;
}
BaseViewHolder viewHolder = (BaseViewHolder) recyclerView.findViewHolderForLayoutPosition(position);
if (viewHolder == null) {
return null;
}
return viewHolder.getView(viewId);
}
/**
* Get the row id associated with the specified position in the list.
*
* @param position The position of the item within the adapter's data set whose row id we want.
* @return The id of the item at the specified position.
*/
@Override
public long getItemId(int position) {
return position;
}
@SuppressWarnings("unchecked")
private int recursiveExpand(int position, @NonNull List list) {
int count = list.size();
int pos = position + list.size() - 1;
for (int i = list.size() - 1; i >= 0; i--, pos--) {
if (list.get(i) instanceof IExpandable) {
IExpandable item = (IExpandable) list.get(i);
if (item.isExpanded() && hasSubItems(item)) {
List subList = item.getSubItems();
mData.addAll(pos + 1, subList);
int subItemCount = recursiveExpand(pos + 1, subList);
count += subItemCount;
}
}
}
return count;
}
/**
* Expand an expandable item
*
* @param position position of the item
* @param animate expand items with animation
* @param shouldNotify notify the RecyclerView to rebind items, <strong>false</strong> if you want to do it
* yourself.
* @return the number of items that have been added.
*/
@SuppressWarnings("unchecked")
public int expand(@IntRange(from = 0) int position, boolean animate, boolean shouldNotify) {
position -= getHeaderLayoutCount();
IExpandable expandable = getExpandableItem(position);
if (expandable == null) {
return 0;
}
if (!hasSubItems(expandable)) {
expandable.setExpanded(true);
notifyItemChanged(position);
return 0;
}
int subItemCount = 0;
if (!expandable.isExpanded()) {
List list = expandable.getSubItems();
mData.addAll(position + 1, list);
subItemCount += recursiveExpand(position + 1, list);
expandable.setExpanded(true);
// subItemCount += list.size();
}
int parentPos = position + getHeaderLayoutCount();
if (shouldNotify) {
if (animate) {
notifyItemChanged(parentPos);
notifyItemRangeInserted(parentPos + 1, subItemCount);
} else {
notifyDataSetChanged();
}
}
return subItemCount;
}
/**
* Expand an expandable item
*
* @param position position of the item, which includes the header layout count.
* @param animate expand items with animation
* @return the number of items that have been added.
*/
public int expand(@IntRange(from = 0) int position, boolean animate) {
return expand(position, animate, true);
}
/**
* Expand an expandable item with animation.
*
* @param position position of the item, which includes the header layout count.
* @return the number of items that have been added.
*/
public int expand(@IntRange(from = 0) int position) {
return expand(position, true, true);
}
public int expandAll(int position, boolean animate, boolean notify) {
position -= getHeaderLayoutCount();
T endItem = null;
if (position + 1 < this.mData.size()) {
endItem = getItem(position + 1);
}
IExpandable expandable = getExpandableItem(position);
if (expandable == null) {
return 0;
}
if (!hasSubItems(expandable)) {
expandable.setExpanded(true);
notifyItemChanged(position);
return 0;
}
int count = expand(position + getHeaderLayoutCount(), false, false);
for (int i = position + 1; i < this.mData.size(); i++) {
T item = getItem(i);
if (item != null && item.equals(endItem)) {
break;
}
if (isExpandable(item)) {
count += expand(i + getHeaderLayoutCount(), false, false);
}
}
if (notify) {
if (animate) {
notifyItemRangeInserted(position + getHeaderLayoutCount() + 1, count);
} else {
notifyDataSetChanged();
}
}
return count;
}
/**
* expand the item and all its subItems
*
* @param position position of the item, which includes the header layout count.
* @param init whether you are initializing the recyclerView or not.
* if <strong>true</strong>, it won't notify recyclerView to redraw UI.
* @return the number of items that have been added to the adapter.
*/
public int expandAll(int position, boolean init) {
return expandAll(position, true, !init);
}
public void expandAll() {
for (int i = mData.size() - 1 + getHeaderLayoutCount(); i >= getHeaderLayoutCount(); i--) {
expandAll(i, false, false);
}
}
@SuppressWarnings("unchecked")
private int recursiveCollapse(@IntRange(from = 0) int position) {
T item = getItem(position);
if (item == null || !isExpandable(item)) {
return 0;
}
IExpandable expandable = (IExpandable) item;
if (!expandable.isExpanded()) {
return 0;
}
List<T> collapseList = new ArrayList<>();
int itemLevel = expandable.getLevel();
T itemTemp;
for (int i = position + 1, n = mData.size(); i < n; i++) {
itemTemp = mData.get(i);
if (itemTemp instanceof IExpandable && ((IExpandable) itemTemp).getLevel() == itemLevel) {
break;
}
collapseList.add(itemTemp);
}
mData.removeAll(collapseList);
return collapseList.size();
}
/**
* Collapse an expandable item that has been expanded..
*
* @param position the position of the item, which includes the header layout count.
* @param animate collapse with animation or not.
* @param notify notify the recyclerView refresh UI or not.
* @return the number of subItems collapsed.
*/
public int collapse(@IntRange(from = 0) int position, boolean animate, boolean notify) {
position -= getHeaderLayoutCount();
IExpandable expandable = getExpandableItem(position);
if (expandable == null) {
return 0;
}
int subItemCount = recursiveCollapse(position);
expandable.setExpanded(false);
int parentPos = position + getHeaderLayoutCount();
if (notify) {
if (animate) {
notifyItemChanged(parentPos);
notifyItemRangeRemoved(parentPos + 1, subItemCount);
} else {
notifyDataSetChanged();
}
}
return subItemCount;
}
/**
* Collapse an expandable item that has been expanded..
*
* @param position the position of the item, which includes the header layout count.
* @return the number of subItems collapsed.
*/
public int collapse(@IntRange(from = 0) int position) {
return collapse(position, true, true);
}
/**
* Collapse an expandable item that has been expanded..
*
* @param position the position of the item, which includes the header layout count.
* @return the number of subItems collapsed.
*/
public int collapse(@IntRange(from = 0) int position, boolean animate) {
return collapse(position, animate, true);
}
private int getItemPosition(T item) {
return item != null && mData != null && !mData.isEmpty() ? mData.indexOf(item) : -1;
}
public boolean hasSubItems(IExpandable item) {
if (item == null) {
return false;
}
List list = item.getSubItems();
return list != null && list.size() > 0;
}
public boolean isExpandable(T item) {
return item != null && item instanceof IExpandable;
}
private IExpandable getExpandableItem(int position) {
T item = getItem(position);
if (isExpandable(item)) {
return (IExpandable) item;
} else {
return null;
}
}
/**
* Get the parent item position of the IExpandable item
*
* @return return the closest parent item position of the IExpandable.
* if the IExpandable item's level is 0, return itself position.
* if the item's level is negative which mean do not implement this, return a negative
* if the item is not exist in the data list, return a negative.
*/
public int getParentPosition(@NonNull T item) {
int position = getItemPosition(item);
if (position == -1) {
return -1;
}
// if the item is IExpandable, return a closest IExpandable item position whose level smaller than this.
// if it is not, return the closest IExpandable item position whose level is not negative
int level;
if (item instanceof IExpandable) {
level = ((IExpandable) item).getLevel();
} else {
level = Integer.MAX_VALUE;
}
if (level == 0) {
return position;
} else if (level == -1) {
return -1;
}
for (int i = position; i >= 0; i--) {
T temp = mData.get(i);
if (temp instanceof IExpandable) {
IExpandable expandable = (IExpandable) temp;
if (expandable.getLevel() >= 0 && expandable.getLevel() < level) {
return i;
}
}
}
return -1;
}
/**
* Interface definition for a callback to be invoked when an itemchild in this
* view has been clicked
*/
public interface OnItemChildClickListener {
/**
* callback method to be invoked when an itemchild in this view has been click
* @param adapter
* @param view The view whihin the ItemView that was clicked
* @param position The position of the view int the adapter
*/
void onItemChildClick(BaseQuickAdapter adapter, View view, int position);
}
/**
* Interface definition for a callback to be invoked when an childView in this
* view has been clicked and held.
*/
public interface OnItemChildLongClickListener {
/**
* callback method to be invoked when an item in this view has been
* click and held
* @param adapter this BaseQuickAdapter adapter
* @param view The childView whihin the itemView that was clicked and held.
* @param position The position of the view int the adapter
* @return true if the callback consumed the long click ,false otherwise
*/
boolean onItemChildLongClick(BaseQuickAdapter adapter, View view, int position);
}
/**
* Interface definition for a callback to be invoked when an item in this
* view has been clicked and held.
*/
public interface OnItemLongClickListener {
/**
* callback method to be invoked when an item in this view has been
* click and held
*
* @param adapter the adpater
* @param view The view whihin the RecyclerView that was clicked and held.
* @param position The position of the view int the adapter
* @return true if the callback consumed the long click ,false otherwise
*/
boolean onItemLongClick(BaseQuickAdapter adapter, View view, int position);
}
/**
* Interface definition for a callback to be invoked when an item in this
* RecyclerView itemView has been clicked.
*/
public interface OnItemClickListener {
/**
* Callback method to be invoked when an item in this RecyclerView has
* been clicked.
*
* @param adapter the adpater
* @param view The itemView within the RecyclerView that was clicked (this
* will be a view provided by the adapter)
* @param position The position of the view in the adapter.
*/
void onItemClick(BaseQuickAdapter adapter, View view, int position);
}
/**
* Register a callback to be invoked when an item in this RecyclerView has
* been clicked.
*
* @param listener The callback that will be invoked.
*/
public void setOnItemClickListener(@Nullable OnItemClickListener listener) {
mOnItemClickListener = listener;
}
/**
* Register a callback to be invoked when an itemchild in View has
* been clicked
*
* @param listener The callback that will run
*/
public void setOnItemChildClickListener(OnItemChildClickListener listener) {
mOnItemChildClickListener = listener;
}
/**
* Register a callback to be invoked when an item in this RecyclerView has
* been long clicked and held
*
* @param listener The callback that will run
*/
public void setOnItemLongClickListener(OnItemLongClickListener listener) {
mOnItemLongClickListener = listener;
}
/**
* Register a callback to be invoked when an itemchild in this View has
* been long clicked and held
*
* @param listener The callback that will run
*/
public void setOnItemChildLongClickListener(OnItemChildLongClickListener listener) {
mOnItemChildLongClickListener = listener;
}
/**
* @return The callback to be invoked with an item in this RecyclerView has
* been long clicked and held, or null id no callback as been set.
*/
public final OnItemLongClickListener getOnItemLongClickListener() {
return mOnItemLongClickListener;
}
/**
* @return The callback to be invoked with an item in this RecyclerView has
* been clicked and held, or null id no callback as been set.
*/
public final OnItemClickListener getOnItemClickListener() {
return mOnItemClickListener;
}
/**
* @return The callback to be invoked with an itemchild in this RecyclerView has
* been clicked, or null id no callback has been set.
*/
@Nullable
public final OnItemChildClickListener getOnItemChildClickListener() {
return mOnItemChildClickListener;
}
/**
* @return The callback to be invoked with an itemChild in this RecyclerView has
* been long clicked, or null id no callback has been set.
*/
@Nullable
public final OnItemChildLongClickListener getOnItemChildLongClickListener() {
return mOnItemChildLongClickListener;
}
}
package com.chad.library.adapter.base;
import android.util.SparseIntArray;
import android.view.ViewGroup;
import androidx.annotation.IntRange;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import com.chad.library.adapter.base.entity.IExpandable;
import com.chad.library.adapter.base.entity.MultiItemEntity;
import com.chad.library.adapter.base.entity.SectionMultiEntity;
import java.util.List;
/**
* https://github.com/CymChad/BaseRecyclerViewAdapterHelper
*/
public abstract class BaseSectionMultiItemQuickAdapter<T extends SectionMultiEntity, K extends BaseViewHolder> extends BaseQuickAdapter<T, K> {
/**
* layouts indexed with their types
*/
private SparseIntArray layouts;
private static final int DEFAULT_VIEW_TYPE = -0xff;
public static final int TYPE_NOT_FOUND = -404;
protected int mSectionHeadResId;
protected static final int SECTION_HEADER_VIEW = 0x00000444;
/**
* Same as QuickAdapter#QuickAdapter(Context,int) but with
* some initialization data.
*
* @param sectionHeadResId The section head layout id for each item
* @param data A new list is created out of this one to avoid mutable list
*/
public BaseSectionMultiItemQuickAdapter(int sectionHeadResId, List<T> data) {
super(data);
this.mSectionHeadResId = sectionHeadResId;
}
@Override
protected int getDefItemViewType(int position) {
T item = mData.get(position);
if (item != null) {
// check the item type include header or not
return item.isHeader ? SECTION_HEADER_VIEW : item.getItemType();
}
return DEFAULT_VIEW_TYPE;
}
protected void setDefaultViewTypeLayout(@LayoutRes int layoutResId) {
addItemType(DEFAULT_VIEW_TYPE, layoutResId);
}
@Override
protected K onCreateDefViewHolder(ViewGroup parent, int viewType) {
// add this to check viewType of section
if (viewType == SECTION_HEADER_VIEW)
return createBaseViewHolder(getItemView(mSectionHeadResId, parent));
return createBaseViewHolder(parent, getLayoutId(viewType));
}
private int getLayoutId(int viewType) {
return layouts.get(viewType, TYPE_NOT_FOUND);
}
/**
* collect layout types you need
*
* @param type The key of layout type
* @param layoutResId The layoutResId of layout type
*/
protected void addItemType(int type, @LayoutRes int layoutResId) {
if (layouts == null) {
layouts = new SparseIntArray();
}
layouts.put(type, layoutResId);
}
@Override
protected boolean isFixedViewType(int type) {
return super.isFixedViewType(type) || type == SECTION_HEADER_VIEW;
}
@Override
public void onBindViewHolder(@NonNull K holder, int position) {
switch (holder.getItemViewType()) {
case SECTION_HEADER_VIEW:
setFullSpan(holder);
convertHead(holder, getItem(position - getHeaderLayoutCount()));
break;
default:
super.onBindViewHolder(holder, position);
break;
}
}
protected abstract void convertHead(K helper, T item);
@Override
public void remove(@IntRange(from = 0L) int position) {
if (mData == null || position < 0
|| position >= mData.size()) return;
T entity = mData.get(position);
if (entity instanceof IExpandable) {
removeAllChild((IExpandable) entity, position);
}
removeDataFromParent(entity);
super.remove(position);
}
/**
* 移除父控件时,若父控件处于展开状态,则先移除其所有的子控件
*
* @param parent 父控件实体
* @param parentPosition 父控件位置
*/
protected void removeAllChild(IExpandable parent, int parentPosition) {
if (parent.isExpanded()) {
List<MultiItemEntity> chidChilds = parent.getSubItems();
if (chidChilds == null || chidChilds.size() == 0) return;
int childSize = chidChilds.size();
for (int i = 0; i < childSize; i++) {
remove(parentPosition + 1);
}
}
}
/**
* 移除子控件时,移除父控件实体类中相关子控件数据,避免关闭后再次展开数据重现
*
* @param child 子控件实体
*/
protected void removeDataFromParent(T child) {
int position = getParentPosition(child);
if (position >= 0) {
IExpandable parent = (IExpandable) mData.get(position);
parent.getSubItems().remove(child);
}
}
}
package com.chad.library.adapter.base;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import com.chad.library.adapter.base.entity.SectionEntity;
import java.util.List;
/**
* https://github.com/CymChad/BaseRecyclerViewAdapterHelper
*/
public abstract class BaseSectionQuickAdapter<T extends SectionEntity, K extends BaseViewHolder> extends BaseQuickAdapter<T, K> {
protected int mSectionHeadResId;
protected static final int SECTION_HEADER_VIEW = 0x00000444;
/**
* Same as QuickAdapter#QuickAdapter(Context,int) but with
* some initialization data.
*
* @param sectionHeadResId The section head layout id for each item
* @param layoutResId The layout resource id of each item.
* @param data A new list is created out of this one to avoid mutable list
*/
public BaseSectionQuickAdapter(int layoutResId, int sectionHeadResId, List<T> data) {
super(layoutResId, data);
this.mSectionHeadResId = sectionHeadResId;
}
@Override
protected int getDefItemViewType(int position) {
return mData.get(position).isHeader ? SECTION_HEADER_VIEW : 0;
}
@Override
protected K onCreateDefViewHolder(ViewGroup parent, int viewType) {
if (viewType == SECTION_HEADER_VIEW)
return createBaseViewHolder(getItemView(mSectionHeadResId, parent));
return super.onCreateDefViewHolder(parent, viewType);
}
@Override
protected boolean isFixedViewType(int type) {
return super.isFixedViewType(type) || type == SECTION_HEADER_VIEW;
}
@Override
public void onBindViewHolder(@NonNull K holder, int position) {
switch (holder.getItemViewType()) {
case SECTION_HEADER_VIEW:
setFullSpan(holder);
convertHead(holder, getItem(position - getHeaderLayoutCount()));
break;
default:
super.onBindViewHolder(holder, position);
break;
}
}
protected abstract void convertHead(K helper, T item);
}
/**
* Copyright 2013 Joan Zapata
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.chad.library.adapter.base;
import android.graphics.Bitmap;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.util.Linkify;
import android.util.SparseArray;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.widget.Adapter;
import android.widget.AdapterView;
import android.widget.Checkable;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.RatingBar;
import android.widget.TextView;
import androidx.annotation.ColorInt;
import androidx.annotation.DrawableRes;
import androidx.annotation.IdRes;
import androidx.annotation.StringRes;
import androidx.recyclerview.widget.RecyclerView;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* https://github.com/CymChad/BaseRecyclerViewAdapterHelper
*/
public class BaseViewHolder extends RecyclerView.ViewHolder {
/**
* Views indexed with their IDs
*/
private final SparseArray<View> views;
public Set<Integer> getNestViews() {
return nestViews;
}
private final HashSet<Integer> nestViews;
private final LinkedHashSet<Integer> childClickViewIds;
private final LinkedHashSet<Integer> itemChildLongClickViewIds;
private BaseQuickAdapter adapter;
/**
* use itemView instead
*/
@Deprecated
public View convertView;
/**
* Package private field to retain the associated user object and detect a change
*/
private Object associatedObject;
public BaseViewHolder(final View view) {
super(view);
this.views = new SparseArray<>();
this.childClickViewIds = new LinkedHashSet<>();
this.itemChildLongClickViewIds = new LinkedHashSet<>();
this.nestViews = new HashSet<>();
convertView = view;
}
public HashSet<Integer> getItemChildLongClickViewIds() {
return itemChildLongClickViewIds;
}
public HashSet<Integer> getChildClickViewIds() {
return childClickViewIds;
}
/**
* use itemView instead
*
* @return the ViewHolder root view
*/
@Deprecated
public View getConvertView() {
return convertView;
}
/**
* Will set the text of a TextView.
*
* @param viewId The view id.
* @param value The text to put in the text view.
* @return The BaseViewHolder for chaining.
*/
public BaseViewHolder setText(@IdRes int viewId, CharSequence value) {
TextView view = getView(viewId);
view.setText(value);
return this;
}
public BaseViewHolder setText(@IdRes int viewId, @StringRes int strId) {
TextView view = getView(viewId);
view.setText(strId);
return this;
}
/**
* Will set the image of an ImageView from a resource id.
*
* @param viewId The view id.
* @param imageResId The image resource id.
* @return The BaseViewHolder for chaining.
*/
public BaseViewHolder setImageResource(@IdRes int viewId, @DrawableRes int imageResId) {
ImageView view = getView(viewId);
view.setImageResource(imageResId);
return this;
}
/**
* Will set background color of a view.
*
* @param viewId The view id.
* @param color A color, not a resource id.
* @return The BaseViewHolder for chaining.
*/
public BaseViewHolder setBackgroundColor(@IdRes int viewId, @ColorInt int color) {
View view = getView(viewId);
view.setBackgroundColor(color);
return this;
}
/**
* Will set background of a view.
*
* @param viewId The view id.
* @param backgroundRes A resource to use as a background.
* @return The BaseViewHolder for chaining.
*/
public BaseViewHolder setBackgroundRes(@IdRes int viewId, @DrawableRes int backgroundRes) {
View view = getView(viewId);
view.setBackgroundResource(backgroundRes);
return this;
}
/**
* Will set text color of a TextView.
*
* @param viewId The view id.
* @param textColor The text color (not a resource id).
* @return The BaseViewHolder for chaining.
*/
public BaseViewHolder setTextColor(@IdRes int viewId, @ColorInt int textColor) {
TextView view = getView(viewId);
view.setTextColor(textColor);
return this;
}
/**
* Will set the image of an ImageView from a drawable.
*
* @param viewId The view id.
* @param drawable The image drawable.
* @return The BaseViewHolder for chaining.
*/
public BaseViewHolder setImageDrawable(@IdRes int viewId, Drawable drawable) {
ImageView view = getView(viewId);
view.setImageDrawable(drawable);
return this;
}
/**
* Add an action to set the image of an image view. Can be called multiple times.
*/
public BaseViewHolder setImageBitmap(@IdRes int viewId, Bitmap bitmap) {
ImageView view = getView(viewId);
view.setImageBitmap(bitmap);
return this;
}
/**
* Add an action to set the alpha of a view. Can be called multiple times.
* Alpha between 0-1.
*/
public BaseViewHolder setAlpha(@IdRes int viewId, float value) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
getView(viewId).setAlpha(value);
} else {
// Pre-honeycomb hack to set Alpha value
AlphaAnimation alpha = new AlphaAnimation(value, value);
alpha.setDuration(0);
alpha.setFillAfter(true);
getView(viewId).startAnimation(alpha);
}
return this;
}
/**
* Set a view visibility to VISIBLE (true) or GONE (false).
*
* @param viewId The view id.
* @param visible True for VISIBLE, false for GONE.
* @return The BaseViewHolder for chaining.
*/
public BaseViewHolder setGone(@IdRes int viewId, boolean visible) {
View view = getView(viewId);
view.setVisibility(visible ? View.VISIBLE : View.GONE);
return this;
}
/**
* Set a view visibility to VISIBLE (true) or INVISIBLE (false).
*
* @param viewId The view id.
* @param visible True for VISIBLE, false for INVISIBLE.
* @return The BaseViewHolder for chaining.
*/
public BaseViewHolder setVisible(@IdRes int viewId, boolean visible) {
View view = getView(viewId);
view.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
return this;
}
/**
* Add links into a TextView.
*
* @param viewId The id of the TextView to linkify.
* @return The BaseViewHolder for chaining.
*/
public BaseViewHolder linkify(@IdRes int viewId) {
TextView view = getView(viewId);
Linkify.addLinks(view, Linkify.ALL);
return this;
}
/**
* Apply the typeface to the given viewId, and enable subpixel rendering.
*/
public BaseViewHolder setTypeface(@IdRes int viewId, Typeface typeface) {
TextView view = getView(viewId);
view.setTypeface(typeface);
view.setPaintFlags(view.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG);
return this;
}
/**
* Apply the typeface to all the given viewIds, and enable subpixel rendering.
*/
public BaseViewHolder setTypeface(Typeface typeface, int... viewIds) {
for (int viewId : viewIds) {
TextView view = getView(viewId);
view.setTypeface(typeface);
view.setPaintFlags(view.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG);
}
return this;
}
/**
* Sets the progress of a ProgressBar.
*
* @param viewId The view id.
* @param progress The progress.
* @return The BaseViewHolder for chaining.
*/
public BaseViewHolder setProgress(@IdRes int viewId, int progress) {
ProgressBar view = getView(viewId);
view.setProgress(progress);
return this;
}
/**
* Sets the progress and max of a ProgressBar.
*
* @param viewId The view id.
* @param progress The progress.
* @param max The max value of a ProgressBar.
* @return The BaseViewHolder for chaining.
*/
public BaseViewHolder setProgress(@IdRes int viewId, int progress, int max) {
ProgressBar view = getView(viewId);
view.setMax(max);
view.setProgress(progress);
return this;
}
/**
* Sets the range of a ProgressBar to 0...max.
*
* @param viewId The view id.
* @param max The max value of a ProgressBar.
* @return The BaseViewHolder for chaining.
*/
public BaseViewHolder setMax(@IdRes int viewId, int max) {
ProgressBar view = getView(viewId);
view.setMax(max);
return this;
}
/**
* Sets the rating (the number of stars filled) of a RatingBar.
*
* @param viewId The view id.
* @param rating The rating.
* @return The BaseViewHolder for chaining.
*/
public BaseViewHolder setRating(@IdRes int viewId, float rating) {
RatingBar view = getView(viewId);
view.setRating(rating);
return this;
}
/**
* Sets the rating (the number of stars filled) and max of a RatingBar.
*
* @param viewId The view id.
* @param rating The rating.
* @param max The range of the RatingBar to 0...max.
* @return The BaseViewHolder for chaining.
*/
public BaseViewHolder setRating(@IdRes int viewId, float rating, int max) {
RatingBar view = getView(viewId);
view.setMax(max);
view.setRating(rating);
return this;
}
/**
* Sets the on click listener of the view.
*
* @param viewId The view id.
* @param listener The on click listener;
* @return The BaseViewHolder for chaining.
*/
@Deprecated
public BaseViewHolder setOnClickListener(@IdRes int viewId, View.OnClickListener listener) {
View view = getView(viewId);
view.setOnClickListener(listener);
return this;
}
/**
* add childView id
*
* @param viewIds add the child views id can support childview click
* @return if you use adapter bind listener
* @link {(adapter.setOnItemChildClickListener(listener))}
* <p>
* or if you can use recyclerView.addOnItemTouch(listerer) wo also support this menthod
*/
@SuppressWarnings("unchecked")
public BaseViewHolder addOnClickListener(@IdRes final int ...viewIds) {
for (int viewId : viewIds) {
childClickViewIds.add(viewId);
final View view = getView(viewId);
if (view != null) {
if (!view.isClickable()) {
view.setClickable(true);
}
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (adapter.getOnItemChildClickListener() != null) {
int position = getAdapterPosition();
if (position == RecyclerView.NO_POSITION) {
return;
}
position -= adapter.getHeaderLayoutCount();
adapter.getOnItemChildClickListener().onItemChildClick(adapter, v, position);
}
}
});
}
}
return this;
}
/**
* set nestview id
*
* @param viewIds add the child views id can support childview click
* @return
*/
public BaseViewHolder setNestView(@IdRes int ... viewIds) {
for (int viewId : viewIds) {
nestViews.add(viewId);
}
addOnClickListener(viewIds);
addOnLongClickListener(viewIds);
return this;
}
/**
* add long click view id
*
* @param viewIds
* @return if you use adapter bind listener
* @link {(adapter.setOnItemChildLongClickListener(listener))}
* <p>
* or if you can use recyclerView.addOnItemTouch(listerer) wo also support this menthod
*/
@SuppressWarnings("unchecked")
public BaseViewHolder addOnLongClickListener(@IdRes final int ... viewIds) {
for (int viewId : viewIds) {
itemChildLongClickViewIds.add(viewId);
final View view = getView(viewId);
if (view != null) {
if (!view.isLongClickable()) {
view.setLongClickable(true);
}
view.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (adapter.getOnItemChildLongClickListener() == null) {
return false;
}
int position = getAdapterPosition();
if (position == RecyclerView.NO_POSITION) {
return false;
}
position -= adapter.getHeaderLayoutCount();
return adapter.getOnItemChildLongClickListener().onItemChildLongClick(adapter, v, position);
}
});
}
}
return this;
}
/**
* Sets the on touch listener of the view.
*
* @param viewId The view id.
* @param listener The on touch listener;
* @return The BaseViewHolder for chaining.
*/
@Deprecated
public BaseViewHolder setOnTouchListener(@IdRes int viewId, View.OnTouchListener listener) {
View view = getView(viewId);
view.setOnTouchListener(listener);
return this;
}
/**
* Sets the on long click listener of the view.
*
* @param viewId The view id.
* @param listener The on long click listener;
* @return The BaseViewHolder for chaining.
* Please use {@link #addOnLongClickListener} (adapter.setOnItemChildLongClickListener(listener))}
*/
@Deprecated
public BaseViewHolder setOnLongClickListener(@IdRes int viewId, View.OnLongClickListener listener) {
View view = getView(viewId);
view.setOnLongClickListener(listener);
return this;
}
/**
* Sets the listview or gridview's item click listener of the view
*
* @param viewId The view id.
* @param listener The item on click listener;
* @return The BaseViewHolder for chaining.
* Please use {@link #addOnClickListener} (int)} (adapter.setOnItemChildClickListener(listener))}
*/
@Deprecated
public BaseViewHolder setOnItemClickListener(@IdRes int viewId, AdapterView.OnItemClickListener listener) {
AdapterView view = getView(viewId);
view.setOnItemClickListener(listener);
return this;
}
/**
* Sets the listview or gridview's item long click listener of the view
*
* @param viewId The view id.
* @param listener The item long click listener;
* @return The BaseViewHolder for chaining.
*/
public BaseViewHolder setOnItemLongClickListener(@IdRes int viewId, AdapterView.OnItemLongClickListener listener) {
AdapterView view = getView(viewId);
view.setOnItemLongClickListener(listener);
return this;
}
/**
* Sets the listview or gridview's item selected click listener of the view
*
* @param viewId The view id.
* @param listener The item selected click listener;
* @return The BaseViewHolder for chaining.
*/
public BaseViewHolder setOnItemSelectedClickListener(@IdRes int viewId, AdapterView.OnItemSelectedListener listener) {
AdapterView view = getView(viewId);
view.setOnItemSelectedListener(listener);
return this;
}
/**
* Sets the on checked change listener of the view.
*
* @param viewId The view id.
* @param listener The checked change listener of compound button.
* @return The BaseViewHolder for chaining.
*/
public BaseViewHolder setOnCheckedChangeListener(@IdRes int viewId, CompoundButton.OnCheckedChangeListener listener) {
CompoundButton view = getView(viewId);
view.setOnCheckedChangeListener(listener);
return this;
}
/**
* Sets the tag of the view.
*
* @param viewId The view id.
* @param tag The tag;
* @return The BaseViewHolder for chaining.
*/
public BaseViewHolder setTag(@IdRes int viewId, Object tag) {
View view = getView(viewId);
view.setTag(tag);
return this;
}
/**
* Sets the tag of the view.
*
* @param viewId The view id.
* @param key The key of tag;
* @param tag The tag;
* @return The BaseViewHolder for chaining.
*/
public BaseViewHolder setTag(@IdRes int viewId, int key, Object tag) {
View view = getView(viewId);
view.setTag(key, tag);
return this;
}
/**
* Sets the checked status of a checkable.
*
* @param viewId The view id.
* @param checked The checked status;
* @return The BaseViewHolder for chaining.
*/
public BaseViewHolder setChecked(@IdRes int viewId, boolean checked) {
View view = getView(viewId);
// View unable cast to Checkable
if (view instanceof Checkable) {
((Checkable) view).setChecked(checked);
}
return this;
}
/**
* Set the enabled state of this view.
*
* @param viewId The view id.
* @param enable The checked status;
* @return The BaseViewHolder for chaining.
*/
public BaseViewHolder setEnabled(@IdRes int viewId,boolean enable) {
View view = getView(viewId);
view.setEnabled(enable);
return this;
}
/**
* Sets the adapter of a adapter view.
*
* @param viewId The view id.
* @param adapter The adapter;
* @return The BaseViewHolder for chaining.
*/
@SuppressWarnings("unchecked")
public BaseViewHolder setAdapter(@IdRes int viewId, Adapter adapter) {
AdapterView view = getView(viewId);
view.setAdapter(adapter);
return this;
}
/**
* Sets the adapter of a adapter view.
*
* @param adapter The adapter;
* @return The BaseViewHolder for chaining.
*/
protected BaseViewHolder setAdapter(BaseQuickAdapter adapter) {
this.adapter = adapter;
return this;
}
@SuppressWarnings("unchecked")
public <T extends View> T getView(@IdRes int viewId) {
View view = views.get(viewId);
if (view == null) {
view = itemView.findViewById(viewId);
views.put(viewId, view);
}
return (T) view;
}
/**
* Retrieves the last converted object on this view.
*/
public Object getAssociatedObject() {
return associatedObject;
}
/**
* Should be called during convert
*/
public void setAssociatedObject(Object associatedObject) {
this.associatedObject = associatedObject;
}
}
package com.chad.library.adapter.base;
import android.util.SparseArray;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.chad.library.adapter.base.provider.BaseItemProvider;
import com.chad.library.adapter.base.util.MultiTypeDelegate;
import com.chad.library.adapter.base.util.ProviderDelegate;
import java.util.List;
/**
* https://github.com/chaychan
* @author ChayChan
* @description:
* When there are multiple entries, avoid too much business logic in convert(),Put the logic of each item in the corresponding ItemProvider
* 当有多种条目的时候,避免在convert()中做太多的业务逻辑,把逻辑放在对应的ItemProvider中
* @date 2018/3/21 9:55
*/
public abstract class MultipleItemRvAdapter<T,V extends BaseViewHolder> extends BaseQuickAdapter<T, V> {
private SparseArray<BaseItemProvider> mItemProviders;
protected ProviderDelegate mProviderDelegate;
public MultipleItemRvAdapter(@Nullable List<T> data) {
super(data);
}
/**
* 用于adapter构造函数完成参数的赋值后调用
* Called after the assignment of the argument to the adapter constructor
*/
public void finishInitialize() {
mProviderDelegate = new ProviderDelegate();
setMultiTypeDelegate(new MultiTypeDelegate<T>() {
@Override
protected int getItemType(T t) {
return getViewType(t);
}
});
registerItemProvider();
mItemProviders = mProviderDelegate.getItemProviders();
for (int i = 0; i < mItemProviders.size(); i++) {
int key = mItemProviders.keyAt(i);
BaseItemProvider provider = mItemProviders.get(key);
provider.mData = mData;
getMultiTypeDelegate().registerItemType(key, provider.layout());
}
}
protected abstract int getViewType(T t);
public abstract void registerItemProvider();
@Override
protected void convert(@NonNull V helper, T item) {
int itemViewType = helper.getItemViewType();
BaseItemProvider provider = mItemProviders.get(itemViewType);
provider.mContext = helper.itemView.getContext();
int position = helper.getLayoutPosition() - getHeaderLayoutCount();
provider.convert(helper, item, position);
bindClick(helper, item, position, provider);
}
private void bindClick(final V helper, final T item, final int position, final BaseItemProvider provider) {
OnItemClickListener clickListener = getOnItemClickListener();
OnItemLongClickListener longClickListener = getOnItemLongClickListener();
if (clickListener != null && longClickListener != null){
//如果已经设置了子条目点击监听和子条目长按监听
// If you have set up a sub-entry click monitor and sub-entries long press listen
return;
}
View itemView = helper.itemView;
if (clickListener == null){
//如果没有设置点击监听,则回调给itemProvider
//Callback to itemProvider if no click listener is set
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
provider.onClick(helper, item, position);
}
});
}
if (longClickListener == null){
//如果没有设置长按监听,则回调给itemProvider
// If you do not set a long press listener, callback to the itemProvider
itemView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
return provider.onLongClick(helper, item, position);
}
});
}
}
}
package com.chad.library.adapter.base.animation;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.view.View;
/**
* https://github.com/CymChad/BaseRecyclerViewAdapterHelper
*/
public class AlphaInAnimation implements BaseAnimation {
private static final float DEFAULT_ALPHA_FROM = 0f;
private final float mFrom;
public AlphaInAnimation() {
this(DEFAULT_ALPHA_FROM);
}
public AlphaInAnimation(float from) {
mFrom = from;
}
@Override
public Animator[] getAnimators(View view) {
return new Animator[]{ObjectAnimator.ofFloat(view, "alpha", mFrom, 1f)};
}
}
package com.chad.library.adapter.base.animation;
import android.animation.Animator;
import android.view.View;
/**
* https://github.com/CymChad/BaseRecyclerViewAdapterHelper
*/
public interface BaseAnimation {
Animator[] getAnimators(View view);
}
package com.chad.library.adapter.base.animation;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.view.View;
/**
* https://github.com/CymChad/BaseRecyclerViewAdapterHelper
*/
public class ScaleInAnimation implements BaseAnimation {
private static final float DEFAULT_SCALE_FROM = .5f;
private final float mFrom;
public ScaleInAnimation() {
this(DEFAULT_SCALE_FROM);
}
public ScaleInAnimation(float from) {
mFrom = from;
}
@Override
public Animator[] getAnimators(View view) {
ObjectAnimator scaleX = ObjectAnimator.ofFloat(view, "scaleX", mFrom, 1f);
ObjectAnimator scaleY = ObjectAnimator.ofFloat(view, "scaleY", mFrom, 1f);
return new ObjectAnimator[]{scaleX, scaleY};
}
}
package com.chad.library.adapter.base.animation;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.view.View;
/**
* https://github.com/CymChad/BaseRecyclerViewAdapterHelper
*/
public class SlideInBottomAnimation implements BaseAnimation {
@Override
public Animator[] getAnimators(View view) {
return new Animator[]{
ObjectAnimator.ofFloat(view, "translationY", view.getMeasuredHeight(), 0)
};
}
}
package com.chad.library.adapter.base.animation;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.view.View;
/**
* https://github.com/CymChad/BaseRecyclerViewAdapterHelper
*/
public class SlideInLeftAnimation implements BaseAnimation {
@Override
public Animator[] getAnimators(View view) {
return new Animator[]{
ObjectAnimator.ofFloat(view, "translationX", -view.getRootView().getWidth(), 0)
};
}
}
package com.chad.library.adapter.base.animation;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.view.View;
/**
* https://github.com/CymChad/BaseRecyclerViewAdapterHelper
*/
public class SlideInRightAnimation implements BaseAnimation {
@Override
public Animator[] getAnimators(View view) {
return new Animator[]{
ObjectAnimator.ofFloat(view, "translationX", view.getRootView().getWidth(), 0)
};
}
}
package com.chad.library.adapter.base.callback;
import android.graphics.Canvas;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.RecyclerView;
import com.chad.library.R;
import com.chad.library.adapter.base.BaseItemDraggableAdapter;
import com.chad.library.adapter.base.BaseQuickAdapter;
/**
*
* @author luoxw
* @date 2016/6/20
*/
public class ItemDragAndSwipeCallback extends ItemTouchHelper.Callback {
// private static final String TAG = ItemDragAndSwipeCallback.class.getSimpleName();
private BaseItemDraggableAdapter mAdapter;
private float mMoveThreshold = 0.1f;
private float mSwipeThreshold = 0.7f;
private int mDragMoveFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT;
private int mSwipeMoveFlags = ItemTouchHelper.END;
public ItemDragAndSwipeCallback(BaseItemDraggableAdapter adapter) {
mAdapter = adapter;
}
@Override
public boolean isLongPressDragEnabled() {
return false;
}
@Override
public boolean isItemViewSwipeEnabled() {
return mAdapter.isItemSwipeEnable();
}
@Override
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG
&& !isViewCreateByAdapter(viewHolder)) {
mAdapter.onItemDragStart(viewHolder);
viewHolder.itemView.setTag(R.id.BaseQuickAdapter_dragging_support, true);
} else if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE
&& !isViewCreateByAdapter(viewHolder)) {
mAdapter.onItemSwipeStart(viewHolder);
viewHolder.itemView.setTag(R.id.BaseQuickAdapter_swiping_support, true);
}
super.onSelectedChanged(viewHolder, actionState);
}
@Override
public void clearView(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
super.clearView(recyclerView, viewHolder);
if (isViewCreateByAdapter(viewHolder)) {
return;
}
if (viewHolder.itemView.getTag(R.id.BaseQuickAdapter_dragging_support) != null
&& (Boolean) viewHolder.itemView.getTag(R.id.BaseQuickAdapter_dragging_support)) {
mAdapter.onItemDragEnd(viewHolder);
viewHolder.itemView.setTag(R.id.BaseQuickAdapter_dragging_support, false);
}
if (viewHolder.itemView.getTag(R.id.BaseQuickAdapter_swiping_support) != null
&& (Boolean) viewHolder.itemView.getTag(R.id.BaseQuickAdapter_swiping_support)) {
mAdapter.onItemSwipeClear(viewHolder);
viewHolder.itemView.setTag(R.id.BaseQuickAdapter_swiping_support, false);
}
}
@Override
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
if (isViewCreateByAdapter(viewHolder)) {
return makeMovementFlags(0, 0);
}
return makeMovementFlags(mDragMoveFlags, mSwipeMoveFlags);
}
@Override
public boolean onMove(@NonNull RecyclerView recyclerView,@NonNull RecyclerView.ViewHolder source,@NonNull RecyclerView.ViewHolder target) {
return source.getItemViewType() == target.getItemViewType();
}
@Override
public void onMoved(@NonNull RecyclerView recyclerView,@NonNull RecyclerView.ViewHolder source, int fromPos,@NonNull RecyclerView.ViewHolder target, int toPos, int x, int y) {
super.onMoved(recyclerView, source, fromPos, target, toPos, x, y);
mAdapter.onItemDragMoving(source, target);
}
@Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
if (!isViewCreateByAdapter(viewHolder)) {
mAdapter.onItemSwiped(viewHolder);
}
}
@Override
public float getMoveThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
return mMoveThreshold;
}
@Override
public float getSwipeThreshold(@NonNull RecyclerView.ViewHolder viewHolder) {
return mSwipeThreshold;
}
/**
* Set the fraction that the user should move the View to be considered as swiped.
* The fraction is calculated with respect to RecyclerView's bounds.
* <p>
* Default value is .5f, which means, to swipe a View, user must move the View at least
* half of RecyclerView's width or height, depending on the swipe direction.
*
* @param swipeThreshold A float value that denotes the fraction of the View size. Default value
* is .8f .
*/
public void setSwipeThreshold(float swipeThreshold) {
mSwipeThreshold = swipeThreshold;
}
/**
* Set the fraction that the user should move the View to be considered as it is
* dragged. After a view is moved this amount, ItemTouchHelper starts checking for Views
* below it for a possible drop.
*
* @param moveThreshold A float value that denotes the fraction of the View size. Default value is
* .1f .
*/
public void setMoveThreshold(float moveThreshold) {
mMoveThreshold = moveThreshold;
}
/**
* <p>Set the drag movement direction.</p>
* <p>The value should be ItemTouchHelper.UP, ItemTouchHelper.DOWN, ItemTouchHelper.LEFT, ItemTouchHelper.RIGHT or their combination.</p>
* You can combine them like ItemTouchHelper.UP | ItemTouchHelper.DOWN, it means that the item could only move up and down when dragged.
*
* @param dragMoveFlags the drag movement direction. Default value is ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT.
*/
public void setDragMoveFlags(int dragMoveFlags) {
mDragMoveFlags = dragMoveFlags;
}
/**
* <p>Set the swipe movement direction.</p>
* <p>The value should be ItemTouchHelper.START, ItemTouchHelper.END or their combination.</p>
* You can combine them like ItemTouchHelper.START | ItemTouchHelper.END, it means that the item could swipe to both left or right.
*
* @param swipeMoveFlags the swipe movement direction. Default value is ItemTouchHelper.END.
*/
public void setSwipeMoveFlags(int swipeMoveFlags) {
mSwipeMoveFlags = swipeMoveFlags;
}
@Override
public void onChildDrawOver(@NonNull Canvas c, @NonNull RecyclerView recyclerView,@NonNull RecyclerView.ViewHolder viewHolder,
float dX, float dY, int actionState, boolean isCurrentlyActive) {
super.onChildDrawOver(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE
&& !isViewCreateByAdapter(viewHolder)) {
View itemView = viewHolder.itemView;
c.save();
if (dX > 0) {
c.clipRect(itemView.getLeft(), itemView.getTop(),
itemView.getLeft() + dX, itemView.getBottom());
c.translate(itemView.getLeft(), itemView.getTop());
} else {
c.clipRect(itemView.getRight() + dX, itemView.getTop(),
itemView.getRight(), itemView.getBottom());
c.translate(itemView.getRight() + dX, itemView.getTop());
}
mAdapter.onItemSwiping(c, viewHolder, dX, dY, isCurrentlyActive);
c.restore();
}
}
private boolean isViewCreateByAdapter(@NonNull RecyclerView.ViewHolder viewHolder) {
int type = viewHolder.getItemViewType();
return type == BaseQuickAdapter.HEADER_VIEW || type == BaseQuickAdapter.LOADING_VIEW
|| type == BaseQuickAdapter.FOOTER_VIEW || type == BaseQuickAdapter.EMPTY_VIEW;
}
}
package com.chad.library.adapter.base.diff;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.ListUpdateCallback;
import com.chad.library.adapter.base.BaseQuickAdapter;
public final class BaseQuickAdapterListUpdateCallback implements ListUpdateCallback {
@NonNull
private final BaseQuickAdapter mAdapter;
public BaseQuickAdapterListUpdateCallback(@NonNull BaseQuickAdapter adapter) {
this.mAdapter = adapter;
}
public void onInserted(int position, int count) {
this.mAdapter.notifyItemRangeInserted(position + mAdapter.getHeaderLayoutCount(), count);
}
public void onRemoved(int position, int count) {
this.mAdapter.notifyItemRangeRemoved(position + mAdapter.getHeaderLayoutCount(), count);
}
public void onMoved(int fromPosition, int toPosition) {
this.mAdapter.notifyItemMoved(fromPosition + mAdapter.getHeaderLayoutCount(), toPosition + mAdapter.getHeaderLayoutCount());
}
@Override
public void onChanged(int position, int count, @Nullable Object payload) {
this.mAdapter.notifyItemRangeChanged(position + mAdapter.getHeaderLayoutCount(), count, payload);
}
}
package com.chad.library.adapter.base.diff;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.DiffUtil;
import java.util.ArrayList;
import java.util.List;
/**
* Extend this method to quickly implement DiffUtil
*
* @param <T> Data type
*/
public abstract class BaseQuickDiffCallback<T> extends DiffUtil.Callback {
private List<T> newList;
private List<T> oldList;
public BaseQuickDiffCallback(@Nullable List<T> newList) {
this.newList = newList == null ? new ArrayList<T>() : newList;
}
public List<T> getNewList() {
return newList;
}
public List<T> getOldList() {
return oldList;
}
public void setOldList(@Nullable List<T> oldList) {
this.oldList = oldList == null ? new ArrayList<T>() : oldList;
}
@Override
public int getOldListSize() {
return oldList.size();
}
@Override
public int getNewListSize() {
return newList.size();
}
@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return areItemsTheSame(oldList.get(oldItemPosition), newList.get(newItemPosition));
}
@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return areContentsTheSame(oldList.get(oldItemPosition), newList.get(newItemPosition));
}
@Nullable
@Override
public Object getChangePayload(int oldItemPosition, int newItemPosition) {
return getChangePayload(oldList.get(oldItemPosition), newList.get(newItemPosition));
}
/**
* @param oldItem New data
* @param newItem old Data
* @return Return false if items are no same
*/
protected abstract boolean areItemsTheSame(@NonNull T oldItem, @NonNull T newItem);
/**
* @param oldItem New data
* @param newItem old Data
* @return Return false if item content are no same
*/
protected abstract boolean areContentsTheSame(@NonNull T oldItem, @NonNull T newItem);
/**
* Optional implementation
*
* @param oldItem New data
* @param newItem old Data
* @return Payload info
*/
@Nullable
protected Object getChangePayload(@NonNull T oldItem, @NonNull T newItem) {
return null;
}
}
package com.chad.library.adapter.base.entity;
import java.util.ArrayList;
import java.util.List;
/**
* <p>A helper to implement expandable item.</p>
* <p>if you don't want to extent a class, you can also implement the interface IExpandable</p>
* Created by luoxw on 2016/8/9.
*/
public abstract class AbstractExpandableItem<T> implements IExpandable<T> {
protected boolean mExpandable = false;
protected List<T> mSubItems;
@Override
public boolean isExpanded() {
return mExpandable;
}
@Override
public void setExpanded(boolean expanded) {
mExpandable = expanded;
}
@Override
public List<T> getSubItems() {
return mSubItems;
}
public boolean hasSubItem() {
return mSubItems != null && mSubItems.size() > 0;
}
public void setSubItems(List<T> list) {
mSubItems = list;
}
public T getSubItem(int position) {
if (hasSubItem() && position < mSubItems.size()) {
return mSubItems.get(position);
} else {
return null;
}
}
public int getSubItemPosition(T subItem) {
return mSubItems != null ? mSubItems.indexOf(subItem) : -1;
}
public void addSubItem(T subItem) {
if (mSubItems == null) {
mSubItems = new ArrayList<>();
}
mSubItems.add(subItem);
}
public void addSubItem(int position, T subItem) {
if (mSubItems != null && position >= 0 && position < mSubItems.size()) {
mSubItems.add(position, subItem);
} else {
addSubItem(subItem);
}
}
public boolean contains(T subItem) {
return mSubItems != null && mSubItems.contains(subItem);
}
public boolean removeSubItem(T subItem) {
return mSubItems != null && mSubItems.remove(subItem);
}
public boolean removeSubItem(int position) {
if (mSubItems != null && position >= 0 && position < mSubItems.size()) {
mSubItems.remove(position);
return true;
}
return false;
}
}
package com.chad.library.adapter.base.entity;
import java.util.List;
/**
* implement the interface if the item is expandable
* Created by luoxw on 2016/8/8.
*/
public interface IExpandable<T> {
boolean isExpanded();
void setExpanded(boolean expanded);
List<T> getSubItems();
/**
* Get the level of this item. The level start from 0.
* If you don't care about the level, just return a negative.
*/
int getLevel();
}
package com.chad.library.adapter.base.entity;
/**
* https://github.com/CymChad/BaseRecyclerViewAdapterHelper
*/
public interface MultiItemEntity {
int getItemType();
}
package com.chad.library.adapter.base.entity;
import java.io.Serializable;
/**
* https://github.com/CymChad/BaseRecyclerViewAdapterHelper
*/
public abstract class SectionEntity<T> implements Serializable {
public boolean isHeader;
public T t;
public String header;
public SectionEntity(boolean isHeader, String header) {
this.isHeader = isHeader;
this.header = header;
this.t = null;
}
public SectionEntity(T t) {
this.isHeader = false;
this.header = null;
this.t = t;
}
}
package com.chad.library.adapter.base.entity;
import java.io.Serializable;
/**
* https://github.com/CymChad/BaseRecyclerViewAdapterHelper
*/
public abstract class SectionMultiEntity<T> implements Serializable, MultiItemEntity {
public boolean isHeader;
public T t;
public String header;
public SectionMultiEntity(boolean isHeader, String header) {
this.isHeader = isHeader;
this.header = header;
this.t = null;
}
public SectionMultiEntity(T t) {
this.isHeader = false;
this.header = null;
this.t = t;
}
}
package com.chad.library.adapter.base.listener;
import android.view.View;
import com.chad.library.adapter.base.BaseQuickAdapter;
/**
* Created by AllenCoder on 2016/8/03.
* A convenience class to extend when you only want to OnItemChildClickListener for a subset
* of all the SimpleClickListener. This implements all methods in the
* {@link SimpleClickListener}
**/
public abstract class OnItemChildClickListener extends SimpleClickListener {
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
}
@Override
public void onItemLongClick(BaseQuickAdapter adapter, View view, int position) {
}
@Override
public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
onSimpleItemChildClick(adapter, view, position);
}
@Override
public void onItemChildLongClick(BaseQuickAdapter adapter, View view, int position) {
}
public abstract void onSimpleItemChildClick(BaseQuickAdapter adapter, View view, int position);
}
package com.chad.library.adapter.base.listener;
import android.view.View;
import com.chad.library.adapter.base.BaseQuickAdapter;
/**
* Created by AllenCoder on 2016/8/03.
* A convenience class to extend when you only want to OnItemChildLongClickListener for a subset
* of all the SimpleClickListener. This implements all methods in the
* {@link SimpleClickListener}
**/
public abstract class OnItemChildLongClickListener extends SimpleClickListener {
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
}
@Override
public void onItemLongClick(BaseQuickAdapter adapter, View view, int position) {
}
@Override
public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
}
@Override
public void onItemChildLongClick(BaseQuickAdapter adapter, View view, int position) {
onSimpleItemChildLongClick(adapter, view, position);
}
public abstract void onSimpleItemChildLongClick(BaseQuickAdapter adapter, View view, int position);
}
package com.chad.library.adapter.base.listener;
import android.view.View;
import com.chad.library.adapter.base.BaseQuickAdapter;
/**
* Created by AllenCoder on 2016/8/03.
* <p>
* <p>
* A convenience class to extend when you only want to OnItemClickListener for a subset
* of all the SimpleClickListener. This implements all methods in the
* {@link SimpleClickListener}
*/
public abstract class OnItemClickListener extends SimpleClickListener {
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
onSimpleItemClick(adapter, view, position);
}
@Override
public void onItemLongClick(BaseQuickAdapter adapter, View view, int position) {
}
@Override
public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
}
@Override
public void onItemChildLongClick(BaseQuickAdapter adapter, View view, int position) {
}
public abstract void onSimpleItemClick(BaseQuickAdapter adapter, View view, int position);
}
package com.chad.library.adapter.base.listener;
import androidx.recyclerview.widget.RecyclerView;
/**
* Created by luoxw on 2016/6/20.
*/
public interface OnItemDragListener {
void onItemDragStart(RecyclerView.ViewHolder viewHolder, int pos);
void onItemDragMoving(RecyclerView.ViewHolder source, int from, RecyclerView.ViewHolder target, int to);
void onItemDragEnd(RecyclerView.ViewHolder viewHolder, int pos);
}
package com.chad.library.adapter.base.listener;
import android.view.View;
import com.chad.library.adapter.base.BaseQuickAdapter;
/**
* create by: allen on 16/8/3.
*/
public abstract class OnItemLongClickListener extends SimpleClickListener {
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
}
@Override
public void onItemLongClick(BaseQuickAdapter adapter, View view, int position) {
onSimpleItemLongClick(adapter, view, position);
}
@Override
public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
}
@Override
public void onItemChildLongClick(BaseQuickAdapter adapter, View view, int position) {
}
public abstract void onSimpleItemLongClick(BaseQuickAdapter adapter, View view, int position);
}
package com.chad.library.adapter.base.listener;
import android.graphics.Canvas;
import androidx.recyclerview.widget.RecyclerView;
/**
* Created by luoxw on 2016/6/23.
*/
public interface OnItemSwipeListener {
/**
* Called when the swipe action start.
*/
void onItemSwipeStart(RecyclerView.ViewHolder viewHolder, int pos);
/**
* Called when the swipe action is over.
* If you change the view on the start, you should reset is here, no matter the item has swiped or not.
*
* @param pos If the view is swiped, pos will be negative.
*/
void clearView(RecyclerView.ViewHolder viewHolder, int pos);
/**
* Called when item is swiped, the view is going to be removed from the adapter.
*/
void onItemSwiped(RecyclerView.ViewHolder viewHolder, int pos);
/**
* Draw on the empty edge when swipe moving
*
* @param canvas the empty edge's canvas
* @param viewHolder The ViewHolder which is being interacted by the User or it was
* interacted and simply animating to its original position
* @param dX The amount of horizontal displacement caused by user's action
* @param dY The amount of vertical displacement caused by user's action
* @param isCurrentlyActive True if this view is currently being controlled by the user or
* false it is simply animating back to its original state.
*/
void onItemSwipeMoving(Canvas canvas, RecyclerView.ViewHolder viewHolder, float dX, float dY, boolean isCurrentlyActive);
}
package com.chad.library.adapter.base.listener;
import android.os.Build;
import androidx.core.view.GestureDetectorCompat;
import androidx.recyclerview.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.View;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import java.util.Set;
import static com.chad.library.adapter.base.BaseQuickAdapter.EMPTY_VIEW;
import static com.chad.library.adapter.base.BaseQuickAdapter.FOOTER_VIEW;
import static com.chad.library.adapter.base.BaseQuickAdapter.HEADER_VIEW;
import static com.chad.library.adapter.base.BaseQuickAdapter.LOADING_VIEW;
/**
* Created by AllenCoder on 2016/8/03.
* <p>
* This can be useful for applications that wish to implement various forms of click and longclick and childView click
* manipulation of item views within the RecyclerView. SimpleClickListener may intercept
* a touch interaction already in progress even if the SimpleClickListener is already handling that
* gesture stream itself for the purposes of scrolling.
*
* @see RecyclerView.OnItemTouchListener
*/
public abstract class SimpleClickListener implements RecyclerView.OnItemTouchListener {
public static String TAG = "SimpleClickListener";
private GestureDetectorCompat mGestureDetector;
private RecyclerView recyclerView;
protected BaseQuickAdapter baseQuickAdapter;
private boolean mIsPrepressed = false;
private boolean mIsShowPress = false;
private View mPressedView = null;
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
if (recyclerView == null) {
this.recyclerView = rv;
this.baseQuickAdapter = (BaseQuickAdapter) recyclerView.getAdapter();
mGestureDetector = new GestureDetectorCompat(recyclerView.getContext(), new ItemTouchHelperGestureListener(recyclerView));
} else if (recyclerView != rv) {
this.recyclerView = rv;
this.baseQuickAdapter = (BaseQuickAdapter) recyclerView.getAdapter();
mGestureDetector = new GestureDetectorCompat(recyclerView.getContext(), new ItemTouchHelperGestureListener(recyclerView));
}
if (!mGestureDetector.onTouchEvent(e) && e.getActionMasked() == MotionEvent.ACTION_UP && mIsShowPress) {
if (mPressedView != null) {
BaseViewHolder vh = (BaseViewHolder) recyclerView.getChildViewHolder(mPressedView);
if (vh == null || !isHeaderOrFooterView(vh.getItemViewType())) {
mPressedView.setPressed(false);
}
}
mIsShowPress = false;
mIsPrepressed = false;
}
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
mGestureDetector.onTouchEvent(e);
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
private class ItemTouchHelperGestureListener implements GestureDetector.OnGestureListener {
private RecyclerView recyclerView;
@Override
public boolean onDown(MotionEvent e) {
mIsPrepressed = true;
mPressedView = recyclerView.findChildViewUnder(e.getX(), e.getY());
return false;
}
@Override
public void onShowPress(MotionEvent e) {
if (mIsPrepressed && mPressedView != null) {
mIsShowPress = true;
}
}
ItemTouchHelperGestureListener(RecyclerView recyclerView) {
this.recyclerView = recyclerView;
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
if (mIsPrepressed && mPressedView != null) {
if (recyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
return false;
}
final View pressedView = mPressedView;
BaseViewHolder vh = (BaseViewHolder) recyclerView.getChildViewHolder(pressedView);
int position = vh.getAdapterPosition();
if(position == RecyclerView.NO_POSITION){
return false;
}
if (isHeaderOrFooterPosition(position)) {
return false;
}
position -= baseQuickAdapter.getHeaderLayoutCount();
Set<Integer> childClickViewIds = vh.getChildClickViewIds();
Set<Integer> nestViewIds = vh.getNestViews();
if (childClickViewIds != null && childClickViewIds.size() > 0) {
for (Integer childClickViewId : childClickViewIds) {
View childView = pressedView.findViewById(childClickViewId);
if (childView != null) {
if (inRangeOfView(childView, e) && childView.isEnabled()) {
if (nestViewIds != null && nestViewIds.contains(childClickViewId)) {
return false;
}
setPressViewHotSpot(e, childView);
childView.setPressed(true);
onItemChildClick(baseQuickAdapter, childView, position);
resetPressedView(childView);
return true;
} else {
childView.setPressed(false);
}
}
}
setPressViewHotSpot(e, pressedView);
mPressedView.setPressed(true);
for (Integer childClickViewId : childClickViewIds) {
View childView = pressedView.findViewById(childClickViewId);
if (childView != null) {
childView.setPressed(false);
}
}
onItemClick(baseQuickAdapter, pressedView, position);
} else {
setPressViewHotSpot(e, pressedView);
mPressedView.setPressed(true);
if (childClickViewIds != null && childClickViewIds.size() > 0) {
for (Integer childClickViewId : childClickViewIds) {
View childView = pressedView.findViewById(childClickViewId);
if (childView != null) {
childView.setPressed(false);
}
}
}
onItemClick(baseQuickAdapter, pressedView, position);
}
resetPressedView(pressedView);
}
return true;
}
private void resetPressedView(final View pressedView) {
if (pressedView != null) {
pressedView.postDelayed(new Runnable() {
@Override
public void run() {
if (pressedView != null) {
pressedView.setPressed(false);
}
}
}, 50);
}
mIsPrepressed = false;
mPressedView = null;
}
@Override
public void onLongPress(MotionEvent e) {
boolean isChildLongClick = false;
if (recyclerView.getScrollState() != RecyclerView.SCROLL_STATE_IDLE) {
return;
}
if (mIsPrepressed && mPressedView != null) {
mPressedView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
BaseViewHolder vh = (BaseViewHolder) recyclerView.getChildViewHolder(mPressedView);
int position = vh.getAdapterPosition();
if (position == RecyclerView.NO_POSITION) {
return;
}
if (!isHeaderOrFooterPosition(position)) {
Set<Integer> longClickViewIds = vh.getItemChildLongClickViewIds();
Set<Integer> nestViewIds = vh.getNestViews();
if (longClickViewIds != null && longClickViewIds.size() > 0) {
for (Integer longClickViewId : longClickViewIds) {
View childView = mPressedView.findViewById(longClickViewId);
if (inRangeOfView(childView, e) && childView.isEnabled()) {
if (nestViewIds != null && nestViewIds.contains(longClickViewId)) {
isChildLongClick = true;
break;
}
setPressViewHotSpot(e, childView);
onItemChildLongClick(baseQuickAdapter, childView, position - baseQuickAdapter.getHeaderLayoutCount());
childView.setPressed(true);
mIsShowPress = true;
isChildLongClick = true;
break;
}
}
}
if (!isChildLongClick) {
onItemLongClick(baseQuickAdapter, mPressedView, position - baseQuickAdapter.getHeaderLayoutCount());
setPressViewHotSpot(e, mPressedView);
mPressedView.setPressed(true);
if (longClickViewIds != null) {
for (Integer longClickViewId : longClickViewIds) {
View childView = mPressedView.findViewById(longClickViewId);
if (childView != null) {
childView.setPressed(false);
}
}
}
mIsShowPress = true;
}
}
}
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return false;
}
}
private void setPressViewHotSpot(final MotionEvent e, final View mPressedView) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
/**
* when click Outside the region ,mPressedView is null
*/
if (mPressedView != null && mPressedView.getBackground() != null) {
mPressedView.getBackground().setHotspot(e.getRawX(), e.getY() - mPressedView.getY());
}
}
}
/**
* Callback method to be invoked when an item in this AdapterView has
* been clicked.
* @param adapter
* @param view The view within the AdapterView that was clicked (this
* will be a view provided by the adapter)
* @param position The position of the view in the adapter.
*/
public abstract void onItemClick(BaseQuickAdapter adapter, View view, int position);
/**
* callback method to be invoked when an item in this view has been
* click and held
* @param adapter
* @param view The view whihin the AbsListView that was clicked
* @param position The position of the view int the adapter
* @return true if the callback consumed the long click ,false otherwise
*/
public abstract void onItemLongClick(BaseQuickAdapter adapter, View view, int position);
/**
* callback method to be invoked when an itemchild in this view has been click
* @param adapter
* @param view The view whihin the AbsListView that was clicked
* @param position The position of the view int the adapter
* @return true if the callback consumed the long click ,false otherwise
*/
public abstract void onItemChildClick(BaseQuickAdapter adapter, View view, int position);
/**
* callback method to be invoked when an item in this view has been
* click and held
* @param adapter
* @param view The view whihin the AbsListView that was clicked
* @param position The position of the view int the adapter
* @return true if the callback consumed the long click ,false otherwise
*/
public abstract void onItemChildLongClick(BaseQuickAdapter adapter, View view, int position);
public boolean inRangeOfView(View view, MotionEvent ev) {
int[] location = new int[2];
if (view == null || !view.isShown()) {
return false;
}
view.getLocationOnScreen(location);
int x = location[0];
int y = location[1];
if (ev.getRawX() < x
|| ev.getRawX() > (x + view.getWidth())
|| ev.getRawY() < y
|| ev.getRawY() > (y + view.getHeight())) {
return false;
}
return true;
}
private boolean isHeaderOrFooterPosition(int position) {
/**
* have a headview and EMPTY_VIEW FOOTER_VIEW LOADING_VIEW
*/
if (baseQuickAdapter == null) {
if (recyclerView != null) {
baseQuickAdapter = (BaseQuickAdapter) recyclerView.getAdapter();
} else {
return false;
}
}
int type = baseQuickAdapter.getItemViewType(position);
return (type == EMPTY_VIEW || type == HEADER_VIEW || type == FOOTER_VIEW || type == LOADING_VIEW);
}
private boolean isHeaderOrFooterView(int type) {
return (type == EMPTY_VIEW || type == HEADER_VIEW || type == FOOTER_VIEW || type == LOADING_VIEW);
}
}
package com.chad.library.adapter.base.loadmore;
import androidx.annotation.IdRes;
import androidx.annotation.LayoutRes;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
/**
* Created by BlingBling on 2016/11/11.
*/
public abstract class LoadMoreView {
public static final int STATUS_DEFAULT = 1;
public static final int STATUS_LOADING = 2;
public static final int STATUS_FAIL = 3;
public static final int STATUS_END = 4;
private int mLoadMoreStatus = STATUS_DEFAULT;
private boolean mLoadMoreEndGone = false;
public void setLoadMoreStatus(int loadMoreStatus) {
this.mLoadMoreStatus = loadMoreStatus;
}
public int getLoadMoreStatus() {
return mLoadMoreStatus;
}
public void convert(BaseViewHolder holder) {
switch (mLoadMoreStatus) {
case STATUS_LOADING:
visibleLoading(holder, true);
visibleLoadFail(holder, false);
visibleLoadEnd(holder, false);
break;
case STATUS_FAIL:
visibleLoading(holder, false);
visibleLoadFail(holder, true);
visibleLoadEnd(holder, false);
break;
case STATUS_END:
visibleLoading(holder, false);
visibleLoadFail(holder, false);
visibleLoadEnd(holder, true);
break;
case STATUS_DEFAULT:
visibleLoading(holder, false);
visibleLoadFail(holder, false);
visibleLoadEnd(holder, false);
break;
default:
break;
}
}
private void visibleLoading(BaseViewHolder holder, boolean visible) {
holder.setGone(getLoadingViewId(), visible);
}
private void visibleLoadFail(BaseViewHolder holder, boolean visible) {
holder.setGone(getLoadFailViewId(), visible);
}
private void visibleLoadEnd(BaseViewHolder holder, boolean visible) {
final int loadEndViewId = getLoadEndViewId();
if (loadEndViewId != 0) {
holder.setGone(loadEndViewId, visible);
}
}
public final void setLoadMoreEndGone(boolean loadMoreEndGone) {
this.mLoadMoreEndGone = loadMoreEndGone;
}
public final boolean isLoadEndMoreGone() {
if (getLoadEndViewId() == 0) {
return true;
}
return mLoadMoreEndGone;
}
/**
* No more data is hidden
*
* @return true for no more data hidden load more
* @deprecated Use {@link BaseQuickAdapter#loadMoreEnd(boolean)} instead.
*/
@Deprecated
public boolean isLoadEndGone() {
return mLoadMoreEndGone;
}
/**
* load more layout
*
* @return
*/
public abstract
@LayoutRes
int getLayoutId();
/**
* loading view
*
* @return
*/
protected abstract
@IdRes
int getLoadingViewId();
/**
* load fail view
*
* @return
*/
protected abstract
@IdRes
int getLoadFailViewId();
/**
* load end view, you can return 0
*
* @return
*/
protected abstract
@IdRes
int getLoadEndViewId();
}
package com.chad.library.adapter.base.loadmore;
import com.chad.library.R;
/**
* Created by BlingBling on 2016/10/11.
*/
public final class SimpleLoadMoreView extends LoadMoreView {
@Override
public int getLayoutId() {
return R.layout.brvah_quick_view_load_more;
}
@Override
protected int getLoadingViewId() {
return R.id.load_more_loading_view;
}
@Override
protected int getLoadFailViewId() {
return R.id.load_more_load_fail_view;
}
@Override
protected int getLoadEndViewId() {
return R.id.load_more_load_end_view;
}
}
package com.chad.library.adapter.base.provider;
import android.content.Context;
import com.chad.library.adapter.base.BaseViewHolder;
import java.util.List;
/**
* https://github.com/chaychan
* @author ChayChan
* @description: The base class of ItemProvider
* @date 2018/3/21 10:41
*/
public abstract class BaseItemProvider<T,V extends BaseViewHolder> {
public Context mContext;
public List<T> mData;
//子类须重写该方法返回viewType
//Rewrite this method to return viewType
public abstract int viewType();
//子类须重写该方法返回layout
//Rewrite this method to return layout
public abstract int layout();
public abstract void convert(V helper, T data, int position);
//子类若想实现条目点击事件则重写该方法
//Subclasses override this method if you want to implement an item click event
public void onClick(V helper, T data, int position){};
//子类若想实现条目长按事件则重写该方法
//Subclasses override this method if you want to implement an item long press event
public boolean onLongClick(V helper, T data, int position){return false;};
}
package com.chad.library.adapter.base.util;
/**
* @author ChayChan
* @description: ItemProviderException
* @date 2018/4/12 9:10
*/
public class ItemProviderException extends NullPointerException {
public ItemProviderException(String message) {
super(message);
}
}
package com.chad.library.adapter.base.util;
import android.util.SparseIntArray;
import androidx.annotation.LayoutRes;
import java.util.List;
import static com.chad.library.adapter.base.BaseMultiItemQuickAdapter.TYPE_NOT_FOUND;
/**
* help you to achieve multi type easily
* <p>
* Created by tysheng
* Date: 2017/4/6 08:41.
* Email: tyshengsx@gmail.com
* <p>
* <p>
* more information: https://github.com/CymChad/BaseRecyclerViewAdapterHelper/issues/968
*/
public abstract class MultiTypeDelegate<T> {
private static final int DEFAULT_VIEW_TYPE = -0xff;
private SparseIntArray layouts;
private boolean autoMode, selfMode;
public MultiTypeDelegate(SparseIntArray layouts) {
this.layouts = layouts;
}
public MultiTypeDelegate() {
}
public final int getDefItemViewType(List<T> data, int position) {
T item = data.get(position);
return item != null ? getItemType(item) : DEFAULT_VIEW_TYPE;
}
/**
* get the item type from specific entity.
*
* @param t entity
* @return item type
*/
protected abstract int getItemType(T t);
public final int getLayoutId(int viewType) {
return this.layouts.get(viewType, TYPE_NOT_FOUND);
}
private void addItemType(int type, @LayoutRes int layoutResId) {
if (this.layouts == null) {
this.layouts = new SparseIntArray();
}
this.layouts.put(type, layoutResId);
}
/**
* auto increase type vale, start from 0.
*
* @param layoutResIds layout id arrays
* @return MultiTypeDelegate
*/
public MultiTypeDelegate registerItemTypeAutoIncrease(@LayoutRes int... layoutResIds) {
autoMode = true;
checkMode(selfMode);
for (int i = 0; i < layoutResIds.length; i++) {
addItemType(i, layoutResIds[i]);
}
return this;
}
/**
* set your own type one by one.
*
* @param type type value
* @param layoutResId layout id
* @return MultiTypeDelegate
*/
public MultiTypeDelegate registerItemType(int type, @LayoutRes int layoutResId) {
selfMode = true;
checkMode(autoMode);
addItemType(type, layoutResId);
return this;
}
private void checkMode(boolean mode) {
if (mode) {
throw new IllegalArgumentException("Don't mess two register mode");
}
}
}
package com.chad.library.adapter.base.util;
import android.util.SparseArray;
import com.chad.library.adapter.base.provider.BaseItemProvider;
/**
* https://github.com/chaychan
* @author ChayChan
* @date 2018/3/21 11:04
*/
public class ProviderDelegate {
private SparseArray<BaseItemProvider> mItemProviders = new SparseArray<>();
public void registerProvider(BaseItemProvider provider){
if (provider == null){
throw new ItemProviderException("ItemProvider can not be null");
}
int viewType = provider.viewType();
if (mItemProviders.get(viewType) == null){
mItemProviders.put(viewType,provider);
}
}
public SparseArray<BaseItemProvider> getItemProviders(){
return mItemProviders;
}
}
package com.chad.library.adapter.base.util;
import android.view.MotionEvent;
public class TouchEventUtil {
public static String getTouchAction(int actionId) {
String actionName = "Unknow:id=" + actionId;
switch (actionId) {
case MotionEvent.ACTION_DOWN:
actionName = "ACTION_DOWN";
break;
case MotionEvent.ACTION_MOVE:
actionName = "ACTION_MOVE";
break;
case MotionEvent.ACTION_UP:
actionName = "ACTION_UP";
break;
case MotionEvent.ACTION_CANCEL:
actionName = "ACTION_CANCEL";
break;
case MotionEvent.ACTION_OUTSIDE:
actionName = "ACTION_OUTSIDE";
break;
default:
break;
}
return actionName;
}
}
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<rotate
android:drawable="@drawable/brvah_sample_footer_loading"
android:duration="500"
android:fromDegrees="0.0"
android:pivotX="50.0%"
android:pivotY="50.0%"
android:toDegrees="360.0" />
</item>
</layer-list>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_40">
<LinearLayout
android:id="@+id/load_more_loading_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="horizontal">
<ProgressBar
android:id="@+id/loading_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="?android:attr/progressBarStyleSmall"
android:layout_marginRight="@dimen/dp_4"/>
<TextView
android:id="@+id/loading_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/dp_4"
android:text="@string/brvah_loading"
android:textColor="@android:color/black"
android:textSize="@dimen/sp_14"/>
</LinearLayout>
<FrameLayout
android:id="@+id/load_more_load_fail_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<TextView
android:id="@+id/tv_prompt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/brvah_load_failed"/>
</FrameLayout>
<FrameLayout
android:id="@+id/load_more_load_end_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/brvah_load_end"
android:textColor="@android:color/darker_gray"/>
</FrameLayout>
</FrameLayout>
\ No newline at end of file
<resources>
<string name="brvah_loading">Loading...</string>
<string name="brvah_load_failed">load more failed</string>
<string name="brvah_load_end">No more data</string>
</resources>
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="def_height">50dp</dimen>
<dimen name="dp_4">4dp</dimen>
<dimen name="dp_10">10dp</dimen>
<dimen name="dp_40">40dp</dimen>
<dimen name="sp_14">14sp</dimen>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="BaseQuickAdapter_viewholder_support" type="id"/>
<item name="BaseQuickAdapter_swiping_support" type="id"/>
<item name="BaseQuickAdapter_dragging_support" type="id"/>
<item name="BaseQuickAdapter_databinding_support" type="id"/>
</resources>
\ No newline at end of file
<resources>
<string name="brvah_app_name">Library</string>
<string name="brvah_loading">正在加载中...</string>
<string name="brvah_load_failed">加载失败,请点我重试</string>
<string name="brvah_load_end">没有更多数据</string>
</resources>
include ':library'
include ':FastBleLib' include ':FastBleLib'
include ':app' include ':app'
rootProject.name = "BluToysApplication" rootProject.name = "BluToysApplication"
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment