左晓为主开发手持机充值管理机
zuojincheng
2025-03-21 8521954fa97bdfc54123afb4a72755ece311db06
feat(general): 更新登录逻辑和用户信息展示

- 修改登录 Activity 以支持新的登录逻辑
- 添加用户信息获取和展示功能- 更新数据库以存储用户信息- 优化 NFC 相关工具类
- 调整项目对话框样式
1 文件已重命名
36个文件已添加
41个文件已修改
1个文件已删除
3749 ■■■■■ 已修改文件
README.md 274 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/proguard-rules.pro 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/com/dayu/recharge/activity/LoginActivity.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
baselibrary/libs/avi.library-2.1.3.aar 补丁 | 查看 | 原始文档 | blame | 历史
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NativeNfcReadHelper.java 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/build.gradle 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/proguard-rules.pro 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/AndroidManifest.xml 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/BaseApplication.kt 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/activity/LoginActivity.kt 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/activity/MainActivity.kt 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/activity/ManageListActivity.kt 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/activity/MyFragment.kt 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/activity/NfcWreatActivity.kt 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/AreaCard.kt 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/BaseCard.kt 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/CheckCard.kt 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/ClearCard.kt 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/DebugCard.kt 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/DomainSettingCard.kt 47 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/FetchDataCard.kt 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/GpsCard.kt 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/IpSettingCard.kt 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/UserCard.kt 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/card/ValveTimeCard.kt 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/net/LoginResult.kt 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/bean/net/UserInfoResult.kt 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/dao/AppDataBase.kt 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/dao/BaseDaoSingleton.kt 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/model/CardInfoModel.kt 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/net/ApiManager.kt 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/net/MyIntercepterApplication.kt 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/tool/BaseCommon.kt 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/tool/CardCommon.kt 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/tool/GeBaseHelper.kt 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/tool/NfcReadHelper.kt 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/java/com/dayu/general/view/ProjectDialog.kt 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/layout/activity_manage_list_ge.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/layout/activity_manager_read.xml 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
generallibrary/src/main/res/layout/fragment_my.xml 117 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
gradlew 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
gradlew.bat 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
henanlibrary/build.gradle 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
henanlibrary/proguard-rules.pro 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
local.properties 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/AVLoadingIndicatorView.java 419 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/Indicator.java 201 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallBeatIndicator.java 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallClipRotateIndicator.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallClipRotateMultipleIndicator.java 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallClipRotatePulseIndicator.java 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallGridBeatIndicator.java 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallGridPulseIndicator.java 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallPulseIndicator.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallPulseRiseIndicator.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallPulseSyncIndicator.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallRotateIndicator.java 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallScaleIndicator.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallScaleMultipleIndicator.java 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallScaleRippleIndicator.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallScaleRippleMultipleIndicator.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallSpinFadeLoaderIndicator.java 114 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallTrianglePathIndicator.java 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallZigZagDeflectIndicator.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallZigZagIndicator.java 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/CubeTransitionIndicator.java 106 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/LineScaleIndicator.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/LineScalePartyIndicator.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/LineScalePulseOutIndicator.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/LineScalePulseOutRapidIndicator.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/LineSpinFadeLoaderIndicator.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/PacmanIndicator.java 115 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/SemiCircleSpinIndicator.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/SquareSpinIndicator.java 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/java/com/wang/avi/indicators/TriangleSkewSpinIndicator.java 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/res/values/attrs.xml 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pickerviewlibrary/src/main/res/values/styles.xml 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
qihealonelibrary/build.gradle 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
qiheonlinelibrary/build.gradle 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
README.md
New file
@@ -0,0 +1,274 @@
# 充值系统 (Recharge System)
这是一个基于Android的充值系统项目,采用模块化架构设计,使用Room数据库进行数据持久化存储。
## 项目结构
项目包含以下模块:
- `app`: 主应用模块
- `baselibrary`: 基础库,包含基本工具类和通用组件
- `generallibrary`: 通用功能库,包含数据库操作等通用功能
- `henanlibrary`: 河南地区特定功能模块
- `qihealonelibrary`: 齐河单机版功能模块
- `qiheonlinelibrary`: 齐河在线版功能模块
- `ocridcardlibrary`: 身份证识别模块
- `easysocket`: Socket通信模块
- `pickerviewlibrary`: 选择器视图库
## 技术栈
- 开发语言:Kotlin & Java
- 数据库:Room
- 网络通信:Retrofit & Socket
- 依赖注入:未使用
- 异步处理:RxJava
- 权限管理:XXPermissions
- 视图绑定:
  - ViewBinding:用于安全高效地访问视图
  - DataBinding:用于数据驱动UI的MVVM架构实现
## 视图绑定配置
### ViewBinding
在模块级build.gradle中启用ViewBinding:
```gradle
android {
    buildFeatures {
        viewBinding true
    }
}
```
使用示例:
```kotlin
class ExampleActivity : AppCompatActivity() {
    private lateinit var binding: ActivityExampleBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityExampleBinding.inflate(layoutInflater)
        setContentView(binding.root)
        // 直接访问视图
        binding.textView.text = "Hello ViewBinding"
    }
}
```
### DataBinding
在模块级build.gradle中启用DataBinding:
```gradle
android {
    buildFeatures {
        dataBinding true
    }
}
```
使用示例:
1. 布局文件:
```xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="user"
            type="com.example.User" />
    </data>
    <LinearLayout>
        <TextView
            android:text="@{user.name}" />
    </LinearLayout>
</layout>
```
2. Activity中使用:
```kotlin
class ExampleActivity : AppCompatActivity() {
    private lateinit var binding: ActivityExampleBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = DataBindingUtil.setContentView(this, R.layout.activity_example)
        binding.user = User("张三")
        binding.lifecycleOwner = this
    }
}
```
### 最佳实践
- ViewBinding:
  - 用于简单的视图访问场景
  - 替代findViewById,避免空指针异常
  - 编译时类型安全
- DataBinding:
  - 用于实现MVVM架构
  - 数据驱动UI更新
  - 双向绑定支持
  - 自定义绑定适配器
  - 表达式支持
## 数据库结构
### GeneralLibrary 数据库
```kotlin
@Database(entities = [PassWordCardBean::class, CardData::class, ProjectDataBean::class], version = 1)
```
主要实体:
- PassWordCardBean: 密码卡数据
- CardData: 卡片数据
- ProjectDataBean: 项目数据
## 开发环境要求
- Android Studio Arctic Fox或更高版本
- JDK 8或更高版本
- Android SDK API 23或更高版本
- Gradle 7.0或更高版本
## 构建与运行
1. 克隆项目:
```bash
git clone [项目地址]
```
2. 在Android Studio中打开项目
3. 同步Gradle文件
4. 构建项目:
```bash
./gradlew build
```
5. 运行应用:
   - 通过Android Studio运行
   - 或使用命令行:`./gradlew installDebug`
## 模块说明
### BaseLibrary
基础功能库,提供:
- 基础Activity
- 通用工具类
- 基础UI组件
### GeneralLibrary
通用功能模块,包含:
- Room数据库实现
- 数据访问对象(DAO)
- 实体类定义
### 其他模块
- HenanlLibrary: 河南地区特定功能
- QiheAloneLibrary: 齐河单机版特定功能
- QiheOnlineLibrary: 齐河在线版特定功能
- OCRIDCardLibrary: 身份证识别功能
- EasySocket: Socket通信实现
- PickerViewLibrary: 选择器控件
## 自定义组件使用说明
### TitleBar 标题栏组件
TitleBar是一个自定义的标题栏组件,提供了左中右三个位置的文本和图片设置功能。
#### XML属性配置
```xml
<com.dayu.baselibrary.view.TitleBar
    android:id="@+id/titleBar"
    android:layout_width="match_parent"
    android:layout_height="@dimen/dimen_title_height"
    app:leftText="返回"
    app:leftImage="@drawable/ic_back"
    app:centerText="标题"
    app:centerImage="@drawable/ic_logo"
    app:rightText="更多"
    app:rightImage="@drawable/ic_more"/>
```
#### 代码中使用
1. 设置文本和图片
```kotlin
titleBar.apply {
    setLeftText("返回")
    setLeftImage(R.drawable.ic_back)
    setCenterText("标题")
    setRightText("更多")
    setRightImage(R.drawable.ic_more)
}
```
2. 点击事件监听
```kotlin
// 方式1:使用类型常量(推荐)
titleBar.setOnItemclickListner(TitleBar.ClickType_LEFT_IMAGE) { finish() }
titleBar.setOnItemclickListner(TitleBar.ClickType_RIGHT_TEXT) { showMenu() }
// 方式2:使用位置和类型常量(已废弃)
titleBar.setOnItemclickListner(TitleBar.IMAGE, TitleBar.LEFT) { finish() }
```
#### 点击类型常量说明
- `ClickType_LEFT_TEXT`: 左侧文本点击
- `ClickType_LEFT_IMAGE`: 左侧图片点击
- `ClickType_CENTER_TEXT`: 中间文本点击
- `ClickType_CENTER_IMAGE`: 中间图片点击
- `ClickType_RIGHT_TEXT`: 右侧文本点击
- `ClickType_RIGHT_IMAGE`: 右侧图片点击
#### 其他功能
```kotlin
// 设置右侧按钮状态
titleBar.setRightStatus(false) // 禁用右侧按钮
// 设置右侧图片可见性
titleBar.setRightIMGVisibility(View.GONE)
// 获取中间的TextView
val titleTextView = titleBar.getTitleTextView()
// 获取右侧布局
val rightLayout = titleBar.getLlRight()
```
#### 注意事项
1. 点击事件只有在对应的视图可见时才会生效
2. 设置文本或图片时,如果传入null或0,对应的视图将被隐藏
3. 组件默认使用垂直线性布局,确保在布局文件中设置合适的高度
## 注意事项
1. 数据库迁移
   - 当修改数据库结构时,需要更新版本号
   - 提供相应的Migration策略
2. 权限处理
   - 确保在使用相关功能前申请必要权限
   - 使用XXPermissions进行权限管理
3. 数据安全
   - 敏感数据需要加密存储
   - 注意用户数据的安全处理
## 贡献指南
1. Fork 项目
2. 创建特性分支
3. 提交更改
4. 推送到分支
5. 创建Pull Request
## 许可证
[添加许可证信息]
## 联系方式
[添加联系方式]
app/proguard-rules.pro
@@ -143,4 +143,13 @@
#其他
-keep class com.contrarywind.** {*;}
-keep class com.bigkoo.** {*;}
-keep class org.** {*;}
-keep class org.** {*;}
# Room 数据库
-keep class * extends androidx.room.RoomDatabase
-keep class * extends androidx.room.Entity
-keep class * extends androidx.room.Dao
-keep @androidx.room.Entity class *
-keepclassmembers class * {
    @androidx.room.* *;
}
app/src/main/java/com/dayu/recharge/activity/LoginActivity.java
@@ -130,7 +130,7 @@
            } else if (type == BaseCommon.Generalv1Library) {
                binding.nameLL.setVisibility(View.VISIBLE);
                getGeneralV1Permission();
                ProjectDialog projectDialog=new ProjectDialog(this);
                ProjectDialog projectDialog=new ProjectDialog(this,MyApplication.myApplication);
                projectDialog.show();
            }
            MyApplication.myApplication.initApplication();
baselibrary/libs/avi.library-2.1.3.aar
Binary files differ
baselibrary/src/main/java/com/dayu/baselibrary/tools/nfc/NativeNfcReadHelper.java
@@ -386,12 +386,19 @@
                mfc.connect();
                //获取当前卡号
                boolean isOpen = false;
                for (int i = 0; i < listKeyA.size(); i++) {
                    if (mfc.authenticateSectorWithKeyA(0, listKeyA.get(i))) {
                if (!listKeyA.isEmpty()){
                    for (int i = 0; i < listKeyA.size(); i++) {
                        if (mfc.authenticateSectorWithKeyA(0, listKeyA.get(i))) {
                            isOpen = true;
                            break;
                        }
                    }
                }else if (!listA_PS.isEmpty()){
                    if (mfc.authenticateSectorWithKeyA(0,   listA_PS.get(0))){
                        isOpen = true;
                        break;
                    }
                }
                if (isOpen) {
                    int bIndex = mfc.sectorToBlock(0);
                    byte[] data = mfc.readBlock(bIndex + 0);
generallibrary/build.gradle
@@ -1,12 +1,13 @@
plugins {
    id 'com.android.library'
    id 'org.jetbrains.kotlin.android'
    id 'kotlin-kapt'
}
android {
    namespace 'com.dayu.general'
    compileSdk 34
    ndkVersion '21.0.6113669'
    defaultConfig {
        minSdk 23
@@ -46,16 +47,20 @@
    implementation 'androidx.core:core-ktx:1.12.0'
    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation 'com.google.android.material:material:1.11.0'
    implementation "androidx.activity:activity-ktx:1.8.2"
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0"
    implementation "androidx.fragment:fragment-ktx:1.6.2"
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.2.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
    compileOnly project(':pickerviewlibrary')
    //数据库
    implementation "androidx.room:room-runtime:2.3.0"
    implementation "androidx.room:room-ktx:2.3.0"
    runtimeOnly("androidx.room:room-common:2.3.0")
    annotationProcessor "androidx.room:room-compiler:2.3.0"
    kapt "androidx.room:room-compiler:2.3.0"
    //权限申请
    compileOnly 'com.github.getActivity:XXPermissions:18.5'
@@ -80,7 +85,7 @@
    //建议添加 ViewPager2 的明确依赖
    implementation "androidx.viewpager2:viewpager2:1.1.0-beta01"
    implementation "androidx.fragment:fragment:1.6.2"
    implementation files('../baselibrary/libs/avi.library-2.1.3.aar')
    implementation 'com.tencent.bugly:crashreport:4.1.9.3'
}
generallibrary/proguard-rules.pro
@@ -18,4 +18,12 @@
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
#-renamesourcefileattribute SourceFile
# Room 数据库
-keep class * extends androidx.room.RoomDatabase
-keep class * extends androidx.room.Entity
-keep class * extends androidx.room.Dao
-keep @androidx.room.Entity class *
-keepclassmembers class * {
    @androidx.room.* *;
}
generallibrary/src/main/AndroidManifest.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.NFC" />
    <!--用于访问网络,网络定位需要上网-->
@@ -50,7 +51,12 @@
        <activity android:name="com.dayu.general.activity.ManageListActivity" />
        <activity android:name="com.dayu.general.activity.SearchUserActivity"/>
        <activity android:name="com.dayu.general.activity.NfcWreatActivity" />
        <activity android:name="com.dayu.general.activity.NewCardActivity"/>
        <activity android:name=".activity.MainActivity"/>
        <activity
            android:name=".activity.ManagerReadActivity"
            android:screenOrientation="portrait"
            android:windowSoftInputMode="adjustResize"/>
        <meta-data
generallibrary/src/main/java/com/dayu/general/BaseApplication.kt
@@ -3,6 +3,7 @@
import android.app.Application
import android.nfc.Tag
import com.dayu.general.dao.BaseDaoSingleton
import com.dayu.general.dao.ProjectDataDao
class BaseApplication private constructor() {
@@ -15,29 +16,44 @@
        @Volatile
        private var myApplication: BaseApplication? = null
        private var Tag : String ?= ""
        var projectDataDao = BaseDaoSingleton.getInstance(application)?.projectDataDao()
        var tag: String = ""
        var token: String = ""
        var userId: String = ""
        var userName: String = ""
        var userPhone: String = ""
        //片区信息
        var blockId:String=""
        var blockName:String=""
        var projectDataDao: ProjectDataDao? = null
        @JvmStatic
        fun getInstance(application: Application): BaseApplication {
            if (myApplication == null) {
                myApplication = BaseApplication()
                BaseApplication.application = application
                myApplication = BaseApplication().apply {
                    // 通过实例调用 init()
                    init()
                }
            }
           return myApplication as BaseApplication
            return myApplication as BaseApplication
        }
    }
    fun init() {
     if (projectDataDao!=null){
         val projectDataBean = projectDataDao?.findFirst()
         if (projectDataBean!=null){
             Tag = projectDataBean.projectTag
         }
     }
     fun init() {
        projectDataDao = application?.let { BaseDaoSingleton.getInstance(it)?.projectDataDao() }
        if (projectDataDao != null) {
            val projectDataBean = projectDataDao?.findFirst()
            if (projectDataBean != null) {
                tag = projectDataBean.projectTag
            }
        }
    }
}
generallibrary/src/main/java/com/dayu/general/activity/LoginActivity.kt
@@ -1,8 +1,12 @@
package com.dayu.general.activity
import android.app.Activity
import android.content.Context
import android.content.Intent
import com.dayu.baselibrary.net.subscribers.SubscriberListener
import com.dayu.baselibrary.utils.ToastUtil
import com.dayu.general.BaseApplication
import com.dayu.general.bean.net.LoginResult
import com.dayu.general.bean.net.SearchUserResult
import com.dayu.general.net.ApiManager
import com.dayu.general.net.BaseResponse
@@ -16,7 +20,7 @@
    companion object {
        @JvmStatic
        fun login(phone: String, password: String, myContext: Context) {
        fun login(phone: String, password: String, myContext: Activity) {
            val map = mutableMapOf<String, Any>()
            if (phone.isNotEmpty()) {
@@ -27,18 +31,21 @@
                map["password"] = password
            }
            map["orgTag"] = "ym"
            map["orgTag"] = BaseApplication.tag
            // 使用正确的类型参数
            ApiManager.getInstance().requestPostLoading(
                myContext,
                "sso/sso/loginJson",
                SearchUserResult::class.java,
                LoginResult::class.java,
                map,
                object : SubscriberListener<BaseResponse<SearchUserResult>>() {
                    override fun onNext(t: BaseResponse<SearchUserResult>) {
                object : SubscriberListener<BaseResponse<LoginResult>>() {
                    override fun onNext(t: BaseResponse<LoginResult>) {
                        if (t.success) {
                            BaseApplication.token = t.content?.token ?: ""
                            BaseApplication.userId = t.content?.id ?: ""
                            val intent = Intent(myContext, MainActivity::class.java)
                            myContext.startActivity(intent)
                        } else {
                            // 处理搜索失败的情况
                            ToastUtil.show(t.msg)
generallibrary/src/main/java/com/dayu/general/activity/MainActivity.kt
@@ -4,9 +4,16 @@
import android.view.LayoutInflater
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import com.dayu.baselibrary.net.subscribers.SubscriberListener
import com.dayu.baselibrary.utils.ToastUtil
import com.dayu.general.BaseApplication
import com.dayu.general.R
import com.dayu.general.adapter.TabAdapter
import com.dayu.general.bean.net.LoginResult
import com.dayu.general.bean.net.UserInfoResult
import com.dayu.general.databinding.ActivityMainBinding
import com.dayu.general.net.ApiManager
import com.dayu.general.net.BaseResponse
class MainActivity : BaseActivity() {
@@ -19,8 +26,35 @@
        setupFragments()
        initView()
        initTab()
        getUserInfo();
    }
    private fun getUserInfo() {
        // 使用正确的类型参数
        ApiManager.getInstance().requestGetLoading(
            this,
            "base/user/getUserInfos/" + BaseApplication.userId,
            UserInfoResult::class.java,
            null,
            object : SubscriberListener<BaseResponse<UserInfoResult>>() {
                override fun onNext(t: BaseResponse<UserInfoResult>) {
                    if (t.success) {
                        BaseApplication.userName = t.content?.userName ?: ""
                        BaseApplication.userPhone = t.content?.phone ?: ""
                        BaseApplication.blockName = t.content?.blockName ?: ""
                    } else {
                        // 处理搜索失败的情况
                        ToastUtil.show(t.msg)
                    }
                }
                override fun onError(e: Throwable?) {
                    super.onError(e)
                    ToastUtil.show("搜索失败: ${e?.message ?: "未知错误"}")
                }
            }
        )
    }
generallibrary/src/main/java/com/dayu/general/activity/ManageListActivity.kt
@@ -1,6 +1,7 @@
package com.dayu.general.activity
import android.os.Bundle
import com.dayu.baselibrary.view.TitleBar.ClickType_LEFT_IMAGE
import com.dayu.general.databinding.ActivityManageListGeBinding
class ManageListActivity : BaseActivity() {
@@ -10,6 +11,11 @@
        super.onCreate(savedInstanceState)
        binding = ActivityManageListGeBinding.inflate(layoutInflater)
        setContentView(binding?.root)
        initView()
    }
    fun initView() {
        binding?.titleBar?.setOnItemclickListner(ClickType_LEFT_IMAGE) { this.finish() }
    }
}
generallibrary/src/main/java/com/dayu/general/activity/MyFragment.kt
@@ -1,10 +1,12 @@
package com.dayu.general.activity
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.dayu.general.BaseApplication
import com.dayu.general.databinding.FragmentMyBinding
class MyFragment : Fragment() {
@@ -17,4 +19,39 @@
        binding = FragmentMyBinding.inflate(inflater, container, false)
        return binding?.root
    }
    override fun onResume() {
        super.onResume()
        if (BaseApplication.userName.isNotEmpty()) {
            binding?.myName?.text = BaseApplication.userName
        } else {
            binding?.myName?.text = "未登录"
        }
        if (BaseApplication.userPhone.isNotEmpty()) {
            binding?.myPhone?.text = BaseApplication.userPhone
        } else {
            binding?.myPhone?.text = "未登录"
        }
        if (BaseApplication.blockName.isNotEmpty()) {
            binding?.myAdName?.text = BaseApplication.blockName
        } else {
            binding?.myAdName?.text = "未登录"
        }
    }
    fun logout() {
        BaseApplication.userId = ""
        BaseApplication.userName = ""
        BaseApplication.userPhone = ""
        BaseApplication.blockId = ""
        BaseApplication.blockName = ""
        binding?.myName?.text = "未登录"
        binding?.myPhone?.text = "未登录"
        binding?.myAdName?.text = "未登录"
        var intent= Intent(activity,LoginActivity::class.java)
        startActivity(intent)
        activity?.finish()
    }
}
generallibrary/src/main/java/com/dayu/general/activity/NfcWreatActivity.kt
@@ -2,7 +2,7 @@
import android.content.Intent
import android.os.Bundle
import com.dayu.general.bean.card.CardCommon
import com.dayu.general.tool.CardCommon
import com.dayu.general.databinding.ActivityNfcWriteGeBinding
/**
@@ -40,9 +40,11 @@
    }
    override fun onNfcBack(intent: Intent?) {
        TODO("Not yet implemented")
        when(cardType){
            CardCommon.CHECK_CARD->{
                binding?.cardData?.text = "写用户卡"
            }
        }
    }
}
generallibrary/src/main/java/com/dayu/general/bean/card/AreaCard.kt
@@ -2,6 +2,7 @@
import com.dayu.baselibrary.tools.BcdUtil
import com.dayu.baselibrary.tools.HexUtil
import com.dayu.general.tool.CardCommon
import java.io.Serializable
/**
@@ -10,11 +11,7 @@
 */
class AreaCard : BaseCard(), Serializable {
    companion object {
        const val CARD_TYPE = "B0"  // 卡类型固定为0xB0
        const val IDENTIFY_CODE_A0 = 0xA0.toByte()  // 识别码A0
        const val IDENTIFY_CODE_B1 = 0xB1.toByte()  // 识别码B1
        const val IDENTIFY_CODE_C2 = 0xC2.toByte()  // 识别码C2
        const val IDENTIFY_CODE_89 = 0x89.toByte()  // 识别码89
        const val CARD_TYPE = CardCommon.REGION_CARD  // 卡类型固定为0xB0
    }
    var areaNumber: Int = 0     // 国家行政区域号(12位BCD,精确到村)
generallibrary/src/main/java/com/dayu/general/bean/card/BaseCard.kt
@@ -1,14 +1,23 @@
package com.dayu.general.bean.card
import com.dayu.baselibrary.dao.AppDatabase
import com.dayu.baselibrary.tools.HexUtil
import com.dayu.general.bean.db.CardData
import com.dayu.general.dao.AppDataBase
import com.dayu.general.tool.CardCommon
import com.tencent.bugly.crashreport.CrashReport
open class BaseCard {
    var cardData: String? = null //标识码
    companion object {
        const val IDENTIFY_CODE_A0 = 0xA0.toByte()  // 识别码A0
        const val IDENTIFY_CODE_B1 = 0xB1.toByte()  // 识别码B1
        const val IDENTIFY_CODE_C2 = 0xC2.toByte()  // 识别码C2
        const val IDENTIFY_CODE_89 = 0x89.toByte()  // 识别码89
    }
    fun setCardData(baseDao: AppDataBase, cardType: String?) {
        try {
            val cardDataBean: CardData =
generallibrary/src/main/java/com/dayu/general/bean/card/CheckCard.kt
@@ -1,6 +1,8 @@
package com.dayu.general.bean.card
import com.dayu.baselibrary.tools.HexUtil
import com.dayu.general.tool.BaseCommon
import com.dayu.general.tool.CardCommon
import java.io.Serializable
/**
@@ -9,11 +11,7 @@
 */
class CheckCard : BaseCard(), Serializable {
    companion object {
        const val CARD_TYPE = "B3"              // 卡类型:检查卡
        const val IDENTIFY_CODE_A0 = 0xA0.toByte()  // 识别码A0
        const val IDENTIFY_CODE_B1 = 0xB1.toByte()  // 识别码B1
        const val IDENTIFY_CODE_C2 = 0xC2.toByte()  // 识别码C2
        const val IDENTIFY_CODE_89 = 0x89.toByte()  // 识别码89
        const val CARD_TYPE = CardCommon.CHECK_CARD              // 卡类型:检查卡
    }
    /**
generallibrary/src/main/java/com/dayu/general/bean/card/ClearCard.kt
@@ -1,6 +1,7 @@
package com.dayu.general.bean.card
import com.dayu.baselibrary.tools.HexUtil
import com.dayu.general.tool.CardCommon
import java.io.Serializable
/**
@@ -9,11 +10,7 @@
 */
class ClearCard : BaseCard(), Serializable {
    companion object {
        const val CARD_TYPE = "C1"              // 卡类型:清零卡
        const val IDENTIFY_CODE_A0 = 0xA0.toByte()  // 识别码A0
        const val IDENTIFY_CODE_B1 = 0xB1.toByte()  // 识别码B1
        const val IDENTIFY_CODE_C2 = 0xC2.toByte()  // 识别码C2
        const val IDENTIFY_CODE_89 = 0x89.toByte()  // 识别码89
        const val CARD_TYPE = CardCommon.CLEAN_CARD_TYPE           // 卡类型:清零卡
    }
    /**
generallibrary/src/main/java/com/dayu/general/bean/card/DebugCard.kt
@@ -1,6 +1,7 @@
package com.dayu.general.bean.card
import com.dayu.baselibrary.tools.HexUtil
import com.dayu.general.tool.CardCommon
import java.io.Serializable
/**
@@ -12,12 +13,7 @@
 */
class DebugCard : BaseCard(), Serializable {
    companion object {
        const val CARD_TYPE = "B4"              // 卡类型:调试卡
        const val IDENTIFY_CODE_A0 = 0xA0.toByte()  // 识别码A0
        const val IDENTIFY_CODE_B1 = 0xB1.toByte()  // 识别码B1
        const val IDENTIFY_CODE_C2 = 0xC2.toByte()  // 识别码C2
        const val IDENTIFY_CODE_89 = 0x89.toByte()  // 识别码89
        const val CARD_TYPE = CardCommon.DEBUG_CARD              // 卡类型:调试卡
        const val AUTO_CLOSE_TIMEOUT = 60_000L  // 自动关闭超时时间(1分钟)
    }
generallibrary/src/main/java/com/dayu/general/bean/card/DomainSettingCard.kt
@@ -1,6 +1,7 @@
package com.dayu.general.bean.card
import com.dayu.baselibrary.tools.HexUtil
import com.dayu.general.tool.CardCommon
import java.io.Serializable
/**
@@ -9,12 +10,9 @@
 */
class DomainSettingCard : BaseCard(), Serializable {
    companion object {
        const val CARD_TYPE = "B6"              // 卡类型:域名设置卡
        const val IDENTIFY_CODE_A0 = 0xA0.toByte()  // 识别码A0
        const val IDENTIFY_CODE_B1 = 0xB1.toByte()  // 识别码B1
        const val IDENTIFY_CODE_C2 = 0xC2.toByte()  // 识别码C2
        const val IDENTIFY_CODE_89 = 0x89.toByte()  // 识别码89
        const val CARD_TYPE = CardCommon.AREA_CARD              // 卡类型:域名设置卡
        const val MAX_DOMAIN_ROUTE = 4          // 最大域名路数
        const val MAX_DOMAIN_LENGTH = 38        // 最大域名长度
    }
@@ -31,8 +29,8 @@
            return false
        }
        return data[0].contentEquals(getZeroBytes()) &&
               data[1].contentEquals(getOneBytes()) &&
               data[2].contentEquals(getTwoBytes())
                data[1].contentEquals(getOneBytes()) &&
                data[2].contentEquals(getTwoBytes())
    }
    /**
@@ -41,30 +39,31 @@
    fun getBean(data: List<ByteArray>): DomainSettingCard? {
        try {
            val domainSettingCard = DomainSettingCard()
            // 解析第0块
            val zero = data[0]
            // 验证卡类型(8位)
            if (HexUtil.byteToHex(zero[8]) != CARD_TYPE) {
                return null
            }
            // 验证识别码(9-12位)
            if (zero[9] != IDENTIFY_CODE_A0 ||
                zero[10] != IDENTIFY_CODE_B1 ||
                zero[11] != IDENTIFY_CODE_C2 ||
                zero[12] != IDENTIFY_CODE_89) {
                zero[12] != IDENTIFY_CODE_89
            ) {
                return null
            }
            // 解析域名路数(13位)
            val routeNumber = zero[13].toInt()
            if (routeNumber !in 1..MAX_DOMAIN_ROUTE) {
                return null
            }
            domainSettingCard.domainRouteNumber = routeNumber
            // 解析域名长度(14位)
            domainSettingCard.domainLength = zero[14].toInt()
@@ -116,22 +115,22 @@
                for (i in domain.length.coerceAtMost(8) until 8) {
                    data[i] = 0
                }
                // 设置卡类型(8位)
                data[8] = HexUtil.hexToByte(CARD_TYPE)
                // 设置识别码(9-12位)
                data[9] = IDENTIFY_CODE_A0
                data[10] = IDENTIFY_CODE_B1
                data[11] = IDENTIFY_CODE_C2
                data[12] = IDENTIFY_CODE_89
                // 设置域名路数(13位)
                data[13] = domainRouteNumber.toByte()
                // 设置域名长度(14位)
                data[14] = domain.length.toByte()
                // 设置校验和(15位)
                data[15] = getByteSum(data)
            } catch (e: Exception) {
@@ -156,7 +155,7 @@
                for (i in (domain.length - 8).coerceAtMost(15) until 15) {
                    data[i] = 0
                }
                // 设置校验和(15位)
                data[15] = getByteSum(data)
            } catch (e: Exception) {
@@ -181,7 +180,7 @@
                for (i in (domain.length - 23).coerceAtMost(15) until 15) {
                    data[i] = 0
                }
                // 设置校验和(15位)
                data[15] = getByteSum(data)
            } catch (e: Exception) {
@@ -195,9 +194,9 @@
     * 验证域名格式是否正确
     */
    fun isValidDomain(): Boolean {
        return domain.isNotEmpty() &&
               domain.length <= MAX_DOMAIN_LENGTH &&
               domain.matches(Regex("^[a-zA-Z0-9.-]+$"))
        return domain.isNotEmpty() &&
                domain.length <= MAX_DOMAIN_LENGTH &&
                domain.matches(Regex("^[a-zA-Z0-9.-]+$"))
    }
    /**
generallibrary/src/main/java/com/dayu/general/bean/card/FetchDataCard.kt
@@ -2,6 +2,8 @@
import com.dayu.baselibrary.tools.BcdUtil
import com.dayu.baselibrary.tools.HexUtil
import com.dayu.general.tool.CardCommon.Companion.ELECTRIC_PRICE_CARD
import com.dayu.general.tool.CardCommon.Companion.MANAGE_CRAD
import java.io.Serializable
/**
@@ -10,12 +12,9 @@
 */
class FetchDataCard : BaseCard(), Serializable {
    companion object {
        const val CARD_TYPE_NEED_FETCH = "B1"    // 需要刷卡取数
        const val CARD_TYPE_FETCH_SUCCESS = "B2"  // 刷卡取数返写成功
        const val IDENTIFY_CODE_A0 = 0xA0.toByte()  // 识别码A0
        const val IDENTIFY_CODE_B1 = 0xB1.toByte()  // 识别码B1
        const val IDENTIFY_CODE_C2 = 0xC2.toByte()  // 识别码C2
        const val IDENTIFY_CODE_89 = 0x89.toByte()  // 识别码89
        const val CARD_TYPE_NEED_FETCH = ELECTRIC_PRICE_CARD    // 需要刷卡取数
        const val CARD_TYPE_FETCH_SUCCESS = MANAGE_CRAD  // 刷卡取数返写成功
    }
    var areaNumber: Int = 0      // 国家行政区域号(12位BCD,精确到村)
generallibrary/src/main/java/com/dayu/general/bean/card/GpsCard.kt
@@ -1,6 +1,7 @@
package com.dayu.general.bean.card
import com.dayu.baselibrary.tools.HexUtil
import com.dayu.general.tool.CardCommon.Companion.GPS_CARD
import java.io.Serializable
/**
@@ -9,11 +10,8 @@
 */
class GpsCard : BaseCard(), Serializable {
    companion object {
        const val CARD_TYPE = "B7"              // 卡类型:GPS定位卡
        const val IDENTIFY_CODE_A0 = 0xA0.toByte()  // 识别码A0
        const val IDENTIFY_CODE_B1 = 0xB1.toByte()  // 识别码B1
        const val IDENTIFY_CODE_C2 = 0xC2.toByte()  // 识别码C2
        const val IDENTIFY_CODE_89 = 0x89.toByte()  // 识别码89
        const val CARD_TYPE =GPS_CARD              // 卡类型:GPS定位卡
    }
    /**
generallibrary/src/main/java/com/dayu/general/bean/card/IpSettingCard.kt
@@ -1,6 +1,7 @@
package com.dayu.general.bean.card
import com.dayu.baselibrary.tools.HexUtil
import com.dayu.general.tool.CardCommon.Companion.IP_CARD
import java.io.Serializable
/**
@@ -9,11 +10,7 @@
 */
class IpSettingCard : BaseCard(), Serializable {
    companion object {
        const val CARD_TYPE = "B5"              // 卡类型:IP设置卡
        const val IDENTIFY_CODE_A0 = 0xA0.toByte()  // 识别码A0
        const val IDENTIFY_CODE_B1 = 0xB1.toByte()  // 识别码B1
        const val IDENTIFY_CODE_C2 = 0xC2.toByte()  // 识别码C2
        const val IDENTIFY_CODE_89 = 0x89.toByte()  // 识别码89
        const val CARD_TYPE = IP_CARD              // 卡类型:IP设置卡
        
        const val MAX_IP_ROUTE = 4              // 最大IP路数
    }
generallibrary/src/main/java/com/dayu/general/bean/card/UserCard.kt
@@ -3,6 +3,7 @@
import com.dayu.baselibrary.bean.BaseUserCardCard
import com.dayu.baselibrary.tools.BcdUtil
import com.dayu.baselibrary.tools.HexUtil
import com.dayu.general.tool.CardCommon.Companion.USER_CARD_TYPE_1
import java.io.Serializable
import java.util.*
@@ -10,7 +11,7 @@
 * 通用项目用户卡结构
 */
class UserCard : BaseCard(), Serializable {
    var cardType: String = "A1" // 卡类型:A1终端写卡 A8刷卡开泵后值 A2叠加充值
    var cardType: String = USER_CARD_TYPE_1 // 卡类型:A1终端写卡 A8刷卡开泵后值 A2叠加充值
    var areaNumber: Int = 0 // 国家行政区域号(12位BCD,精确到村)
    var userCode: String = "" // 用户编号BCD
    var userCodeNumber: Int = 0 // 用户卡编号(HEX)
generallibrary/src/main/java/com/dayu/general/bean/card/ValveTimeCard.kt
@@ -1,6 +1,7 @@
package com.dayu.general.bean.card
import com.dayu.baselibrary.tools.HexUtil
import com.dayu.general.tool.CardCommon.Companion.VALVE_TIME_CARD
import java.io.Serializable
/**
@@ -9,11 +10,7 @@
 */
class ValveTimeCard : BaseCard(), Serializable {
    companion object {
        const val CARD_TYPE = "B8"              // 卡类型:配置开关阀时间卡
        const val IDENTIFY_CODE_A0 = 0xA0.toByte()  // 识别码A0
        const val IDENTIFY_CODE_B1 = 0xB1.toByte()  // 识别码B1
        const val IDENTIFY_CODE_C2 = 0xC2.toByte()  // 识别码C2
        const val IDENTIFY_CODE_89 = 0x89.toByte()  // 识别码89
        const val CARD_TYPE = VALVE_TIME_CARD              // 卡类型:配置开关阀时间卡
    }
    var valveTime: Int = 0    // 开关阀时间(秒)
generallibrary/src/main/java/com/dayu/general/bean/net/LoginResult.kt
New file
@@ -0,0 +1,9 @@
package com.dayu.general.bean.net
class LoginResult(
    var id: String,
    var name: String,
    var phone: String,
    var token: String
) {
}
generallibrary/src/main/java/com/dayu/general/bean/net/UserInfoResult.kt
New file
@@ -0,0 +1,26 @@
package com.dayu.general.bean.net
// 用户信息结果类
class UserInfoResult(
    // 区块ID
    var blockId: String,
    // 区块名称
    var blockName: String,
    // 用户ID
    var id: String,
    // 权限列表
    var permissions: List<String>,
    // 手机号
    var phone: String,
    // 角色ID列表
    var roleIds: List<String>,
    // 角色名称列表
    var roleNames: List<String>,
    // 状态ID
    var stateId: String?,
    // 状态名称
    var stateName: String,
    // 用户名称
    var userName: String=""
) {
}
generallibrary/src/main/java/com/dayu/general/dao/AppDataBase.kt
@@ -4,8 +4,9 @@
import androidx.room.RoomDatabase
import com.dayu.general.bean.db.CardData
import com.dayu.general.bean.db.PassWordCardBean
import com.dayu.general.bean.db.ProjectDataBean
@Database(entities = [PassWordCardBean::class, CardData::class], version = 1, exportSchema = false)
@Database(entities = [PassWordCardBean::class, CardData::class, ProjectDataBean::class], version = 1, exportSchema = false)
abstract class AppDataBase : RoomDatabase() {
    abstract fun cardDataDao(): CardDataDao
    abstract fun projectDataDao(): ProjectDataDao
generallibrary/src/main/java/com/dayu/general/dao/BaseDaoSingleton.kt
@@ -13,27 +13,20 @@
        @JvmField
        val SqlitePath: String =
            Environment.getExternalStorageDirectory().absolutePath + File.separator + ".dayu" + File.separator + "data" + File.separator
        @JvmStatic
        fun getInstance(context: Context?): AppDataBase? {
        fun getInstance(context: Context): AppDataBase {
            if (baseDao == null) {
                baseDao = Room.databaseBuilder<AppDataBase>(
                    context!!,
                    context,
                    AppDataBase::class.java,
                    SqlitePath + "ConfigurationData_generalV1"
                ).allowMainThreadQueries().build()
            }
            return baseDao
            return baseDao as AppDataBase
        }
    }
    var AsynchBaseDao: AppDataBase? = null
    fun getAsynchInstance(context: Context?): AppDataBase? {
        if (AsynchBaseDao == null) {
generallibrary/src/main/java/com/dayu/general/model/CardInfoModel.kt
New file
@@ -0,0 +1,22 @@
package com.dayu.general.model
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class CardInfoModel : ViewModel() {
    val cardNumber = MutableLiveData<String>()
    val remark = MutableLiveData<String>()
    init {
        cardNumber.value = ""
        remark.value = ""
    }
    fun setCardNumber(number: String) {
        cardNumber.value = number
    }
    fun setRemark(remarkText: String) {
        remark.value = remarkText
    }
}
generallibrary/src/main/java/com/dayu/general/net/ApiManager.kt
@@ -136,6 +136,7 @@
                    val response = BaseResponse<T>().apply {
                        code = temp.code
                        msg = temp.msg ?: ""
                        success = temp.success
                    }
                    // 处理token失效的情况
generallibrary/src/main/java/com/dayu/general/net/MyIntercepterApplication.kt
@@ -1,5 +1,6 @@
package com.dayu.general.net
import com.dayu.general.BaseApplication
import com.tencent.bugly.crashreport.CrashReport
import okhttp3.Interceptor
import okhttp3.Protocol
@@ -48,6 +49,8 @@
            } else {
            }
            builder.addHeader("tag", BaseApplication.tag)
            builder.addHeader("token", BaseApplication.token)
            return builder.build()
        } catch (e: Exception) {
            e.printStackTrace()
generallibrary/src/main/java/com/dayu/general/tool/BaseCommon.kt
@@ -9,6 +9,10 @@
  companion object{
      val YuanMo: Int = 1
      val QiHe: Int = 2
  }
generallibrary/src/main/java/com/dayu/general/tool/CardCommon.kt
File was renamed from generallibrary/src/main/java/com/dayu/general/bean/card/CardCommon.kt
@@ -1,4 +1,4 @@
package com.dayu.general.bean.card
package com.dayu.general.tool
class CardCommon {
generallibrary/src/main/java/com/dayu/general/tool/GeBaseHelper.kt
@@ -8,7 +8,7 @@
import javax.crypto.Cipher
import javax.crypto.spec.SecretKeySpec
class GeBaseHelper(private val context: Context) : BaseNFCHelper() {
open class GeBaseHelper(private val context: Context) : BaseNFCHelper() {
    companion object {
generallibrary/src/main/java/com/dayu/general/tool/NfcReadHelper.kt
New file
@@ -0,0 +1,91 @@
package com.dayu.general.tool
import android.app.Activity
import android.content.Intent
import com.dayu.baselibrary.tools.nfc.BaseNfcReadHelper
import com.dayu.baselibrary.tools.nfc.NfcReadAdapter
/**
 * NFC读取工具类的Kotlin实现
 */
class NfcReadHelper private constructor(intent: Intent, activity: Activity) : GeBaseHelper(activity) {
    private val adapter: NfcReadAdapter = NfcReadAdapter(intent, activity)
    companion object {
        private var helper: NfcReadHelper? = null
        /**
         * 单例初始化
         */
        @JvmStatic
        fun getInstance(intent: Intent, activity: Activity): NfcReadHelper {
            if (helper == null) {
                helper = NfcReadHelper(intent, activity)
            }
            return helper!!
        }
    }
    /**
     * 获取卡号
     */
    fun getCardNumber(): String {
        return try {
            adapter.cardNumber
        } catch (e: Exception) {
            e.printStackTrace()
            ""
        }
    }
    /**
     * 获取卡片类型和卡号
     */
    fun getCardTypeAndCardNumber(): String {
        return try {
            adapter.cradTypeAndCardNumber
        } catch (e: Exception) {
            e.printStackTrace()
            ""
        }
    }
    /**
     * 读取NFC卡的全部信息
     */
    fun getAllData(callback: BaseNfcReadHelper.NFCCallMapback) {
        try {
            adapter.getAllData(callback)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
    /**
     * 获取一个扇区的数据
     */
    fun getOneSectorData(): List<ByteArray>? {
        return try {
            adapter.onesectorData
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
    }
    /**
     * 读取NFC卡的特定扇区信息
     */
    fun getData(a: Int, b: Int, callback: BaseNfcReadHelper.NFCCallByteback) {
        try {
            adapter.getData(a, b, callback)
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}
generallibrary/src/main/java/com/dayu/general/view/ProjectDialog.kt
@@ -1,5 +1,6 @@
package com.dayu.general.view
import android.app.Application
import android.app.Dialog
import android.content.Context
import android.os.Bundle
@@ -8,6 +9,8 @@
import android.widget.RadioGroup
import android.widget.TextView
import com.dayu.baselibrary.view.ConfirmDialog
import com.dayu.general.BaseApplication
import com.dayu.general.BaseApplication.Companion.application
import com.dayu.general.R
import com.dayu.general.bean.db.ProjectDataBean
import com.dayu.general.dao.BaseDaoSingleton
@@ -18,12 +21,12 @@
 * Author: zuo
 * Date: 2025/3/17
 */
class ProjectDialog(context: Context):Dialog(context,com.dayu.baselibrary.R.style.ws_pay_showSelfDialog){
class ProjectDialog(private val mContext: Context,private val myApplication: Application):Dialog(mContext,com.dayu.baselibrary.R.style.ws_pay_showSelfDialog){
    var confirmDialog: ConfirmDialog? = null
    var mLibraryBack: LibraryBack? = null
    var isChose: Boolean = false
    var projectDataDao = BaseDaoSingleton.getInstance(context)?.projectDataDao()
    var projectDataDao = BaseDaoSingleton.getInstance(mContext)?.projectDataDao()
    var projectBean: ProjectDataBean = ProjectDataBean()
    var type: Int = 0
    var data: String = ""
@@ -48,12 +51,14 @@
                    R.id.yuanMouLibrary -> {
                        type = BaseCommon.YuanMo
                        projectBean.projectType = type
                        data = "确认选择河南版本吗?"
                        projectBean.projectTag="ym"
                        data = "确认选择元谋项目吗?"
                    }
                    R.id.qiHeLibrary -> {
                        type = BaseCommon.QiHe
                        projectBean.projectType = type
                        data = "确认选择齐河单机版本吗?"
                        projectBean.projectTag="qh"
                        data = "确认选择齐河项目吗?"
                    }
                }
@@ -63,8 +68,9 @@
            okBtn.setOnClickListener {
                if (isChose) {
                    // 二次确认
                    confirmDialog = ConfirmDialog(context, data) {
                    confirmDialog = ConfirmDialog(mContext, data) {
                        projectDataDao?.insert(projectBean)
                        BaseApplication.getInstance(myApplication).init()
                        mLibraryBack?.listener(type)
                        dismiss()
                        confirmDialog?.dismiss()
generallibrary/src/main/res/layout/activity_manage_list_ge.xml
@@ -76,7 +76,7 @@
                android:id="@+id/tv_clean_card"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="清理卡"
                android:text="清零卡"
                android:textSize="16sp"
                android:textColor="#333333"
                android:padding="16dp"
generallibrary/src/main/res/layout/activity_manager_read.xml
New file
@@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable
            name="viewModel"
            type="com.dayu.general.model.CardInfoModel" />
    </data>
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <com.dayu.baselibrary.view.TitleBar
            android:id="@+id/titleBar"
            android:layout_width="match_parent"
            android:layout_height="@dimen/dimen_title_height"
            android:background="@color/title_bar_bg"
            android:elevation="4dp"
            app:centerText="制作管理卡"
            tools:ignore="MissingConstraints" />
        <LinearLayout
            android:id="@+id/data_layout"
            android:layout_width="match_parent"
            android:layout_below="@+id/titleBar"
            android:orientation="vertical"
            android:layout_height="wrap_content">
            <LinearLayout
                android:layout_width="match_parent"
                android:orientation="vertical"
                android:layout_height="wrap_content">
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="horizontal"
                    android:padding="16dp">
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="卡号:"
                        android:textColor="#333333"
                        android:textSize="16sp"/>
                    <TextView
                        android:id="@+id/card_number_tv"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:textColor="#333333"
                        android:textSize="16sp"
                        android:text="@{viewModel.cardNumber}"/>
                </LinearLayout>
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="horizontal"
                    android:padding="16dp">
                    <TextView
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:text="备注:"
                        android:textColor="#333333"
                        android:textSize="16sp"/>
                    <EditText
                        android:id="@+id/remark_et"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:background="@null"
                        android:hint="请输入备注信息"
                        android:textSize="16sp"
                        android:text="@={viewModel.remark}"/>
                </LinearLayout>
            </LinearLayout>
        </LinearLayout>
        <LinearLayout
            android:id="@+id/recharge_read_LL"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_below="@+id/data_layout"
            android:orientation="vertical"
            android:visibility="visible">
            <androidx.cardview.widget.CardView
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_margin="16dp"
                app:cardCornerRadius="8dp"
                app:cardElevation="2dp">
                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:orientation="vertical"
                    android:padding="16dp">
                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="16dp"
                        android:gravity="center"
                        android:text="请将卡贴在设备上进行读卡"
                        android:textColor="#333333"
                        android:textSize="@dimen/text_size"
                        android:textStyle="bold" />
                    <ImageView
                        android:layout_width="200dp"
                        android:layout_height="200dp"
                        android:layout_gravity="center"
                        android:scaleType="fitCenter"
                        android:src="@mipmap/nfc_write" />
                </LinearLayout>
            </androidx.cardview.widget.CardView>
        </LinearLayout>
    </RelativeLayout>
</layout>
generallibrary/src/main/res/layout/fragment_my.xml
@@ -3,8 +3,8 @@
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:background="#F5F5F5">
    android:background="#F5F5F5"
    android:orientation="vertical">
    <com.dayu.baselibrary.view.TitleBar
        android:id="@+id/titleBar"
@@ -42,33 +42,73 @@
                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="12dp"
                        android:text="基本信息"
                        android:textColor="#333333"
                        android:textSize="16sp"
                        android:textStyle="bold"
                        android:layout_marginBottom="12dp"/>
                        android:textStyle="bold" />
                    <LinearLayout
                        android:id="@+id/my_village"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="8dp"
                        android:orientation="horizontal"
                        android:visibility="gone"
                        android:layout_marginBottom="8dp">
                        android:visibility="gone">
                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="设备编号:"
                            android:textSize="@dimen/text_size"
                            android:textColor="#666666" />
                            android:textColor="#666666"
                            android:textSize="@dimen/text_size" />
                        <TextView
                            android:id="@+id/my_villageNum"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:textSize="@dimen/text_size"
                            android:textColor="#333333" />
                            android:textColor="#333333"
                            android:textSize="@dimen/text_size" />
                    </LinearLayout>
                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="8dp">
                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="用户名称:"
                            android:textColor="#666666"
                            android:textSize="@dimen/text_size" />
                        <TextView
                            android:id="@+id/my_name"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:textColor="#333333"
                            android:textSize="@dimen/text_size" />
                    </LinearLayout>
                    <LinearLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="8dp">
                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="手机号:"
                            android:textColor="#666666"
                            android:textSize="@dimen/text_size" />
                        <TextView
                            android:id="@+id/my_phone"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:textColor="#333333"
                            android:textSize="@dimen/text_size" />
                    </LinearLayout>
                    <LinearLayout
@@ -96,7 +136,8 @@
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="8dp"
                        android:orientation="horizontal">
                        android:orientation="horizontal"
                        android:visibility="gone">
                        <TextView
                            android:layout_width="wrap_content"
@@ -117,7 +158,8 @@
                        android:id="@+id/my_waterPriceLL"
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:orientation="horizontal">
                        android:orientation="horizontal"
                        android:visibility="gone">
                        <TextView
                            android:layout_width="wrap_content"
@@ -153,18 +195,18 @@
                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="12dp"
                        android:text="记录管理"
                        android:textColor="#333333"
                        android:textSize="16sp"
                        android:textStyle="bold"
                        android:layout_marginBottom="12dp"/>
                        android:textStyle="bold" />
                    <RelativeLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="12dp"
                        android:padding="8dp"
                        android:background="#F9F9F9">
                        android:background="#F9F9F9"
                        android:padding="8dp">
                        <ImageView
                            android:id="@+id/card_icon"
@@ -180,8 +222,8 @@
                            android:layout_height="wrap_content"
                            android:layout_centerVertical="true"
                            android:layout_marginStart="8dp"
                            android:layout_toEndOf="@+id/card_icon"
                            android:layout_toStartOf="@+id/my_newCardOut"
                            android:layout_toEndOf="@+id/card_icon"
                            android:text="开卡记录"
                            android:textColor="#333333"
                            android:textSize="@dimen/text_size" />
@@ -194,8 +236,8 @@
                            android:layout_centerVertical="true"
                            android:background="@drawable/rounded_button_bg"
                            android:paddingStart="12dp"
                            android:paddingEnd="12dp"
                            android:paddingTop="4dp"
                            android:paddingEnd="12dp"
                            android:paddingBottom="4dp"
                            android:text="导出记录"
                            android:textColor="@color/white"
@@ -205,8 +247,8 @@
                    <RelativeLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:padding="8dp"
                        android:background="#F9F9F9">
                        android:background="#F9F9F9"
                        android:padding="8dp">
                        <ImageView
                            android:id="@+id/recharge_icon"
@@ -222,8 +264,8 @@
                            android:layout_height="wrap_content"
                            android:layout_centerVertical="true"
                            android:layout_marginStart="8dp"
                            android:layout_toEndOf="@+id/recharge_icon"
                            android:layout_toStartOf="@+id/my_rechargeOut"
                            android:layout_toEndOf="@+id/recharge_icon"
                            android:text="充值记录"
                            android:textColor="#333333"
                            android:textSize="@dimen/text_size" />
@@ -236,8 +278,8 @@
                            android:layout_centerVertical="true"
                            android:background="@drawable/rounded_button_bg"
                            android:paddingStart="12dp"
                            android:paddingEnd="12dp"
                            android:paddingTop="4dp"
                            android:paddingEnd="12dp"
                            android:paddingBottom="4dp"
                            android:text="导出记录"
                            android:textColor="@color/white"
@@ -262,11 +304,30 @@
                    <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="12dp"
                        android:text="系统设置"
                        android:textColor="#333333"
                        android:textSize="16sp"
                        android:textStyle="bold"
                        android:layout_marginBottom="12dp"/>
                        android:textStyle="bold" />
                    <RelativeLayout
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:orientation="vertical"
                        android:layout_marginBottom="8dp">
                        <TextView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:text="退出登录"
                            android:textColor="#000000"
                            android:textSize="@dimen/text_size" />
                        <ImageView
                            android:layout_width="wrap_content"
                            android:layout_height="wrap_content"
                            android:layout_alignParentEnd="true"
                            android:src="@drawable/ic_arrow_right"/>
                    </RelativeLayout>
                    <TextView
                        android:id="@+id/sys_ip"
@@ -274,10 +335,10 @@
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="12dp"
                        android:background="#F9F9F9"
                        android:padding="12dp"
                        android:drawableStart="@android:drawable/ic_menu_manage"
                        android:drawablePadding="8dp"
                        android:drawableTint="#666666"
                        android:padding="12dp"
                        android:text="IP设置"
                        android:textColor="#333333"
                        android:textSize="@dimen/text_size"
@@ -289,10 +350,10 @@
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="12dp"
                        android:background="#F9F9F9"
                        android:padding="12dp"
                        android:drawableStart="@android:drawable/ic_menu_edit"
                        android:drawablePadding="8dp"
                        android:drawableTint="#666666"
                        android:padding="12dp"
                        android:text="用户补卡"
                        android:textColor="#333333"
                        android:textSize="@dimen/text_size"
@@ -304,10 +365,10 @@
                        android:layout_height="wrap_content"
                        android:layout_marginBottom="12dp"
                        android:background="#F9F9F9"
                        android:padding="12dp"
                        android:drawableStart="@android:drawable/ic_lock_lock"
                        android:drawablePadding="8dp"
                        android:drawableTint="#666666"
                        android:padding="12dp"
                        android:text="登录密码设置"
                        android:textColor="#333333"
                        android:textSize="@dimen/text_size"
@@ -318,10 +379,10 @@
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        android:background="#F9F9F9"
                        android:padding="12dp"
                        android:drawableStart="@android:drawable/ic_menu_compass"
                        android:drawablePadding="8dp"
                        android:drawableTint="#666666"
                        android:padding="12dp"
                        android:text="未连接数据中心"
                        android:textColor="#333333"
                        android:textSize="@dimen/text_size"
gradlew
@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
@@ -55,7 +57,7 @@
#       Darwin, MinGW, and NonStop.
#
#   (3) This script is generated from the Groovy template
#       https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
#       https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
#       within the Gradle project.
#
#       You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,8 @@
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
gradlew.bat
@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -43,11 +45,11 @@
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@@ -57,11 +59,11 @@
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
henanlibrary/build.gradle
@@ -53,7 +53,7 @@
    compileOnly group: 'net.sourceforge.jexcelapi', name: 'jxl', version: '2.6.12'
//    compileOnly 'com.wang.avi:library:2.1.3'
    implementation files('../baselibrary/libs/avi.library-2.1.3.aar')
    //地址选择
    compileOnly project(':pickerviewlibrary')
    implementation project(':easysocket')
henanlibrary/proguard-rules.pro
@@ -150,4 +150,13 @@
-keep class com.dayu.henanlibrary.card.** {*;}
-keep class com.dayu.henanlibrary.dbBean.** {*;}
-keep class com.dayu.henanlibrary.net.** {*;}
-keep class com.dayu.henanlibrary.socketBean.** {*;}
-keep class com.dayu.henanlibrary.socketBean.** {*;}
# Room 数据库
-keep class * extends androidx.room.RoomDatabase
-keep class * extends androidx.room.Entity
-keep class * extends androidx.room.Dao
-keep @androidx.room.Entity class *
-keepclassmembers class * {
    @androidx.room.* *;
}
local.properties
@@ -4,5 +4,6 @@
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
#Mon Aug 19 09:59:12 CST 2024
sdk.dir=D\:\\android\\sdk
#Wed Mar 19 16:09:32 CST 2025
#sdk.dir=C\:\\Users\\User\\AppData\\Local\\Android\\Sdk
sdk.dir=D\:\\android\\sdk
pickerviewlibrary/src/main/java/com/wang/avi/AVLoadingIndicatorView.java
New file
@@ -0,0 +1,419 @@
package com.wang.avi;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.animation.AnimationUtils;
import com.example.pickerviewlibrary.R;
import com.wang.avi.indicators.BallPulseIndicator;
public class AVLoadingIndicatorView extends View {
    private static final String TAG="AVLoadingIndicatorView";
    private static final BallPulseIndicator DEFAULT_INDICATOR=new BallPulseIndicator();
    private static final int MIN_SHOW_TIME = 500; // ms
    private static final int MIN_DELAY = 500; // ms
    private long mStartTime = -1;
    private boolean mPostedHide = false;
    private boolean mPostedShow = false;
    private boolean mDismissed = false;
    private final Runnable mDelayedHide = new Runnable() {
        @Override
        public void run() {
            mPostedHide = false;
            mStartTime = -1;
            setVisibility(View.GONE);
        }
    };
    private final Runnable mDelayedShow = new Runnable() {
        @Override
        public void run() {
            mPostedShow = false;
            if (!mDismissed) {
                mStartTime = System.currentTimeMillis();
                setVisibility(View.VISIBLE);
            }
        }
    };
    int mMinWidth;
    int mMaxWidth;
    int mMinHeight;
    int mMaxHeight;
    private Indicator mIndicator;
    private int mIndicatorColor;
    private boolean mShouldStartAnimationDrawable;
    public AVLoadingIndicatorView(Context context) {
        super(context);
        init(context, null,0,0);
    }
    public AVLoadingIndicatorView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs,0, R.style.AVLoadingIndicatorView);
    }
    public AVLoadingIndicatorView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs,defStyleAttr,R.style.AVLoadingIndicatorView);
    }
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public AVLoadingIndicatorView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context,attrs,defStyleAttr,R.style.AVLoadingIndicatorView);
    }
    private void init(Context context,AttributeSet attrs,int defStyleAttr, int defStyleRes) {
        mMinWidth = 24;
        mMaxWidth = 48;
        mMinHeight = 24;
        mMaxHeight = 48;
        final TypedArray a = context.obtainStyledAttributes(
                attrs, R.styleable.AVLoadingIndicatorView, defStyleAttr, defStyleRes);
        mMinWidth = a.getDimensionPixelSize(R.styleable.AVLoadingIndicatorView_minWidth, mMinWidth);
        mMaxWidth = a.getDimensionPixelSize(R.styleable.AVLoadingIndicatorView_maxWidth, mMaxWidth);
        mMinHeight = a.getDimensionPixelSize(R.styleable.AVLoadingIndicatorView_minHeight, mMinHeight);
        mMaxHeight = a.getDimensionPixelSize(R.styleable.AVLoadingIndicatorView_maxHeight, mMaxHeight);
        String indicatorName=a.getString(R.styleable.AVLoadingIndicatorView_indicatorName);
        mIndicatorColor=a.getColor(R.styleable.AVLoadingIndicatorView_indicatorColor, Color.WHITE);
        setIndicator(indicatorName);
        if (mIndicator==null){
            setIndicator(DEFAULT_INDICATOR);
        }
        a.recycle();
    }
    public Indicator getIndicator() {
        return mIndicator;
    }
    public void setIndicator(Indicator d) {
        if (mIndicator != d) {
            if (mIndicator != null) {
                mIndicator.setCallback(null);
                unscheduleDrawable(mIndicator);
            }
            mIndicator = d;
            //need to set indicator color again if you didn't specified when you update the indicator .
            setIndicatorColor(mIndicatorColor);
            if (d != null) {
                d.setCallback(this);
            }
            postInvalidate();
        }
    }
    /**
     * setIndicatorColor(0xFF00FF00)
     * or
     * setIndicatorColor(Color.BLUE)
     * or
     * setIndicatorColor(Color.parseColor("#FF4081"))
     * or
     * setIndicatorColor(0xFF00FF00)
     * or
     * setIndicatorColor(getResources().getColor(android.R.color.black))
     * @param color
     */
    public void setIndicatorColor(int color){
        this.mIndicatorColor=color;
        mIndicator.setColor(color);
    }
    /**
     * You should pay attention to pass this parameter with two way:
     * for example:
     * 1. Only class Name,like "SimpleIndicator".(This way would use default package name with
     * "com.wang.avi.indicators")
     * 2. Class name with full package,like "com.my.android.indicators.SimpleIndicator".
     * @param indicatorName the class must be extend Indicator .
     */
    public void setIndicator(String indicatorName){
        if (TextUtils.isEmpty(indicatorName)){
            return;
        }
        StringBuilder drawableClassName=new StringBuilder();
        if (!indicatorName.contains(".")){
            String defaultPackageName=getClass().getPackage().getName();
            drawableClassName.append(defaultPackageName)
                    .append(".indicators")
                    .append(".");
        }
        drawableClassName.append(indicatorName);
        try {
            Class<?> drawableClass = Class.forName(drawableClassName.toString());
            Indicator indicator = (Indicator) drawableClass.newInstance();
            setIndicator(indicator);
        } catch (ClassNotFoundException e) {
            Log.e(TAG,"Didn't find your class , check the name again !");
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
    public void smoothToShow(){
        startAnimation(AnimationUtils.loadAnimation(getContext(),android.R.anim.fade_in));
        setVisibility(VISIBLE);
    }
    public void smoothToHide(){
        startAnimation(AnimationUtils.loadAnimation(getContext(),android.R.anim.fade_out));
        setVisibility(GONE);
    }
    public void hide() {
        mDismissed = true;
        removeCallbacks(mDelayedShow);
        long diff = System.currentTimeMillis() - mStartTime;
        if (diff >= MIN_SHOW_TIME || mStartTime == -1) {
            // The progress spinner has been shown long enough
            // OR was not shown yet. If it wasn't shown yet,
            // it will just never be shown.
            setVisibility(View.GONE);
        } else {
            // The progress spinner is shown, but not long enough,
            // so put a delayed message in to hide it when its been
            // shown long enough.
            if (!mPostedHide) {
                postDelayed(mDelayedHide, MIN_SHOW_TIME - diff);
                mPostedHide = true;
            }
        }
    }
    public void show() {
        // Reset the start time.
        mStartTime = -1;
        mDismissed = false;
        removeCallbacks(mDelayedHide);
        if (!mPostedShow) {
            postDelayed(mDelayedShow, MIN_DELAY);
            mPostedShow = true;
        }
    }
    @Override
    protected boolean verifyDrawable(Drawable who) {
        return who == mIndicator
                || super.verifyDrawable(who);
    }
    void startAnimation() {
        if (getVisibility() != VISIBLE) {
            return;
        }
        if (mIndicator instanceof Animatable) {
            mShouldStartAnimationDrawable = true;
        }
        postInvalidate();
    }
    void stopAnimation() {
        if (mIndicator instanceof Animatable) {
            mIndicator.stop();
            mShouldStartAnimationDrawable = false;
        }
        postInvalidate();
    }
    @Override
    public void setVisibility(int v) {
        if (getVisibility() != v) {
            super.setVisibility(v);
            if (v == GONE || v == INVISIBLE) {
                stopAnimation();
            } else {
                startAnimation();
            }
        }
    }
    @Override
    protected void onVisibilityChanged(View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);
        if (visibility == GONE || visibility == INVISIBLE) {
            stopAnimation();
        } else {
            startAnimation();
        }
    }
    @Override
    public void invalidateDrawable(Drawable dr) {
        if (verifyDrawable(dr)) {
            final Rect dirty = dr.getBounds();
            final int scrollX = getScrollX() + getPaddingLeft();
            final int scrollY = getScrollY() + getPaddingTop();
            invalidate(dirty.left + scrollX, dirty.top + scrollY,
                    dirty.right + scrollX, dirty.bottom + scrollY);
        } else {
            super.invalidateDrawable(dr);
        }
    }
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        updateDrawableBounds(w, h);
    }
    private void updateDrawableBounds(int w, int h) {
        // onDraw will translate the canvas so we draw starting at 0,0.
        // Subtract out padding for the purposes of the calculations below.
        w -= getPaddingRight() + getPaddingLeft();
        h -= getPaddingTop() + getPaddingBottom();
        int right = w;
        int bottom = h;
        int top = 0;
        int left = 0;
        if (mIndicator != null) {
            // Maintain aspect ratio. Certain kinds of animated drawables
            // get very confused otherwise.
            final int intrinsicWidth = mIndicator.getIntrinsicWidth();
            final int intrinsicHeight = mIndicator.getIntrinsicHeight();
            final float intrinsicAspect = (float) intrinsicWidth / intrinsicHeight;
            final float boundAspect = (float) w / h;
            if (intrinsicAspect != boundAspect) {
                if (boundAspect > intrinsicAspect) {
                    // New width is larger. Make it smaller to match height.
                    final int width = (int) (h * intrinsicAspect);
                    left = (w - width) / 2;
                    right = left + width;
                } else {
                    // New height is larger. Make it smaller to match width.
                    final int height = (int) (w * (1 / intrinsicAspect));
                    top = (h - height) / 2;
                    bottom = top + height;
                }
            }
            mIndicator.setBounds(left, top, right, bottom);
        }
    }
    @Override
    protected synchronized void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawTrack(canvas);
    }
    void drawTrack(Canvas canvas) {
        final Drawable d = mIndicator;
        if (d != null) {
            // Translate canvas so a indeterminate circular progress bar with padding
            // rotates properly in its animation
            final int saveCount = canvas.save();
            canvas.translate(getPaddingLeft(), getPaddingTop());
            d.draw(canvas);
            canvas.restoreToCount(saveCount);
            if (mShouldStartAnimationDrawable && d instanceof Animatable) {
                ((Animatable) d).start();
                mShouldStartAnimationDrawable = false;
            }
        }
    }
    @Override
    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int dw = 0;
        int dh = 0;
        final Drawable d = mIndicator;
        if (d != null) {
            dw = Math.max(mMinWidth, Math.min(mMaxWidth, d.getIntrinsicWidth()));
            dh = Math.max(mMinHeight, Math.min(mMaxHeight, d.getIntrinsicHeight()));
        }
        updateDrawableState();
        dw += getPaddingLeft() + getPaddingRight();
        dh += getPaddingTop() + getPaddingBottom();
        final int measuredWidth = resolveSizeAndState(dw, widthMeasureSpec, 0);
        final int measuredHeight = resolveSizeAndState(dh, heightMeasureSpec, 0);
        setMeasuredDimension(measuredWidth, measuredHeight);
    }
    @Override
    protected void drawableStateChanged() {
        super.drawableStateChanged();
        updateDrawableState();
    }
    private void updateDrawableState() {
        final int[] state = getDrawableState();
        if (mIndicator != null && mIndicator.isStateful()) {
            mIndicator.setState(state);
        }
    }
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    public void drawableHotspotChanged(float x, float y) {
        super.drawableHotspotChanged(x, y);
        if (mIndicator != null) {
            mIndicator.setHotspot(x, y);
        }
    }
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        startAnimation();
        removeCallbacks();
    }
    @Override
    protected void onDetachedFromWindow() {
        stopAnimation();
        // This should come after stopAnimation(), otherwise an invalidate message remains in the
        // queue, which can prevent the entire view hierarchy from being GC'ed during a rotation
        super.onDetachedFromWindow();
        removeCallbacks();
    }
    private void removeCallbacks() {
        removeCallbacks(mDelayedHide);
        removeCallbacks(mDelayedShow);
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/Indicator.java
New file
@@ -0,0 +1,201 @@
package com.wang.avi;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import java.util.ArrayList;
import java.util.HashMap;
/**
 * Created by Jack Wang on 2016/8/5.
 */
public abstract class Indicator extends Drawable implements Animatable {
    private HashMap<ValueAnimator,ValueAnimator.AnimatorUpdateListener> mUpdateListeners=new HashMap<>();
    private ArrayList<ValueAnimator> mAnimators;
    private int alpha = 255;
    private static final Rect ZERO_BOUNDS_RECT = new Rect();
    protected Rect drawBounds = ZERO_BOUNDS_RECT;
    private boolean mHasAnimators;
    private Paint mPaint=new Paint();
    public Indicator(){
        mPaint.setColor(Color.WHITE);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setAntiAlias(true);
    }
    public int getColor() {
        return mPaint.getColor();
    }
    public void setColor(int color) {
        mPaint.setColor(color);
    }
    @Override
    public void setAlpha(int alpha) {
        this.alpha = alpha;
    }
    @Override
    public int getAlpha() {
        return alpha;
    }
    @Override
    public int getOpacity() {
        return PixelFormat.OPAQUE;
    }
    @Override
    public void setColorFilter(ColorFilter colorFilter) {
    }
    @Override
    public void draw(Canvas canvas) {
        draw(canvas,mPaint);
    }
    public abstract void draw(Canvas canvas, Paint paint);
    public abstract ArrayList<ValueAnimator> onCreateAnimators();
    @Override
    public void start() {
        ensureAnimators();
        if (mAnimators == null) {
            return;
        }
        // If the animators has not ended, do nothing.
        if (isStarted()) {
            return;
        }
        startAnimators();
        invalidateSelf();
    }
    private void startAnimators() {
        for (int i = 0; i < mAnimators.size(); i++) {
            ValueAnimator animator = mAnimators.get(i);
            //when the animator restart , add the updateListener again because they
            // was removed by animator stop .
            ValueAnimator.AnimatorUpdateListener updateListener=mUpdateListeners.get(animator);
            if (updateListener!=null){
                animator.addUpdateListener(updateListener);
            }
            animator.start();
        }
    }
    private void stopAnimators() {
        if (mAnimators!=null){
            for (ValueAnimator animator : mAnimators) {
                if (animator != null && animator.isStarted()) {
                    animator.removeAllUpdateListeners();
                    animator.end();
                }
            }
        }
    }
    private void ensureAnimators() {
        if (!mHasAnimators) {
            mAnimators = onCreateAnimators();
            mHasAnimators = true;
        }
    }
    @Override
    public void stop() {
        stopAnimators();
    }
    private boolean isStarted() {
        for (ValueAnimator animator : mAnimators) {
            return animator.isStarted();
        }
        return false;
    }
    @Override
    public boolean isRunning() {
        for (ValueAnimator animator : mAnimators) {
            return animator.isRunning();
        }
        return false;
    }
    /**
     *  Your should use this to add AnimatorUpdateListener when
     *  create animator , otherwise , animator doesn't work when
     *  the animation restart .
     * @param updateListener
     */
    public void addUpdateListener(ValueAnimator animator, ValueAnimator.AnimatorUpdateListener updateListener){
        mUpdateListeners.put(animator,updateListener);
    }
    @Override
    protected void onBoundsChange(Rect bounds) {
        super.onBoundsChange(bounds);
        setDrawBounds(bounds);
    }
    public void setDrawBounds(Rect drawBounds) {
        setDrawBounds(drawBounds.left, drawBounds.top, drawBounds.right, drawBounds.bottom);
    }
    public void setDrawBounds(int left, int top, int right, int bottom) {
        this.drawBounds = new Rect(left, top, right, bottom);
    }
    public void postInvalidate(){
        invalidateSelf();
    }
    public Rect getDrawBounds() {
        return drawBounds;
    }
    public int getWidth(){
        return drawBounds.width();
    }
    public int getHeight(){
        return drawBounds.height();
    }
    public int centerX(){
        return drawBounds.centerX();
    }
    public int centerY(){
        return drawBounds.centerY();
    }
    public float exactCenterX(){
        return drawBounds.exactCenterX();
    }
    public float exactCenterY(){
        return drawBounds.exactCenterY();
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallBeatIndicator.java
New file
@@ -0,0 +1,81 @@
package com.wang.avi.indicators;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.animation.ValueAnimator;
import com.wang.avi.Indicator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/19.
 */
public class BallBeatIndicator extends Indicator {
    public static final float SCALE=1.0f;
    public static final int ALPHA=255;
    private float[] scaleFloats=new float[]{SCALE,
            SCALE,
            SCALE};
    int[] alphas=new int[]{ALPHA,
            ALPHA,
            ALPHA,};
    @Override
    public void draw(Canvas canvas, Paint paint) {
        float circleSpacing=4;
        float radius=(getWidth()-circleSpacing*2)/6;
        float x = getWidth()/ 2-(radius*2+circleSpacing);
        float y=getHeight() / 2;
        for (int i = 0; i < 3; i++) {
            canvas.save();
            float translateX=x+(radius*2)*i+circleSpacing*i;
            canvas.translate(translateX, y);
            canvas.scale(scaleFloats[i], scaleFloats[i]);
            paint.setAlpha(alphas[i]);
            canvas.drawCircle(0, 0, radius, paint);
            canvas.restore();
        }
    }
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        int[] delays=new int[]{350,0,350};
        for (int i = 0; i < 3; i++) {
            final int index=i;
            ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.75f,1);
            scaleAnim.setDuration(700);
            scaleAnim.setRepeatCount(-1);
            scaleAnim.setStartDelay(delays[i]);
            addUpdateListener(scaleAnim,new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    scaleFloats[index] = (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            ValueAnimator alphaAnim=ValueAnimator.ofInt(255,51,255);
            alphaAnim.setDuration(700);
            alphaAnim.setRepeatCount(-1);
            alphaAnim.setStartDelay(delays[i]);
            addUpdateListener(alphaAnim,new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    alphas[index] = (int) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            animators.add(scaleAnim);
            animators.add(alphaAnim);
        }
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallClipRotateIndicator.java
New file
@@ -0,0 +1,62 @@
package com.wang.avi.indicators;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.animation.ValueAnimator;
import com.wang.avi.Indicator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/16.
 */
public class BallClipRotateIndicator extends Indicator {
    float scaleFloat=1,degrees;
    @Override
    public void draw(Canvas canvas, Paint paint) {
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(3);
        float circleSpacing=12;
        float x = (getWidth()) / 2;
        float y=(getHeight()) / 2;
        canvas.translate(x, y);
        canvas.scale(scaleFloat, scaleFloat);
        canvas.rotate(degrees);
        RectF rectF=new RectF(-x+circleSpacing,-y+circleSpacing,0+x-circleSpacing,0+y-circleSpacing);
        canvas.drawArc(rectF, -45, 270, false, paint);
    }
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.6f,0.5f,1);
        scaleAnim.setDuration(750);
        scaleAnim.setRepeatCount(-1);
        addUpdateListener(scaleAnim,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                scaleFloat = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        ValueAnimator rotateAnim=ValueAnimator.ofFloat(0,180,360);
        rotateAnim.setDuration(750);
        rotateAnim.setRepeatCount(-1);
        addUpdateListener(rotateAnim,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                degrees = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animators.add(scaleAnim);
        animators.add(rotateAnim);
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallClipRotateMultipleIndicator.java
New file
@@ -0,0 +1,83 @@
package com.wang.avi.indicators;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.animation.ValueAnimator;
import com.wang.avi.Indicator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/17.
 */
public class BallClipRotateMultipleIndicator extends Indicator {
    float scaleFloat=1,degrees;
    @Override
    public void draw(Canvas canvas, Paint paint) {
        paint.setStrokeWidth(3);
        paint.setStyle(Paint.Style.STROKE);
        float circleSpacing=12;
        float x=getWidth()/2;
        float y=getHeight()/2;
        canvas.save();
        canvas.translate(x, y);
        canvas.scale(scaleFloat, scaleFloat);
        canvas.rotate(degrees);
        //draw two big arc
        float[] bStartAngles=new float[]{135,-45};
        for (int i = 0; i < 2; i++) {
            RectF rectF=new RectF(-x+circleSpacing,-y+circleSpacing,x-circleSpacing,y-circleSpacing);
            canvas.drawArc(rectF, bStartAngles[i], 90, false, paint);
        }
        canvas.restore();
        canvas.translate(x, y);
        canvas.scale(scaleFloat, scaleFloat);
        canvas.rotate(-degrees);
        //draw two small arc
        float[] sStartAngles=new float[]{225,45};
        for (int i = 0; i < 2; i++) {
            RectF rectF=new RectF(-x/1.8f+circleSpacing,-y/1.8f+circleSpacing,x/1.8f-circleSpacing,y/1.8f-circleSpacing);
            canvas.drawArc(rectF, sStartAngles[i], 90, false, paint);
        }
    }
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.6f,1);
        scaleAnim.setDuration(1000);
        scaleAnim.setRepeatCount(-1);
        addUpdateListener(scaleAnim,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                scaleFloat = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        ValueAnimator rotateAnim=ValueAnimator.ofFloat(0, 180,360);
        rotateAnim.setDuration(1000);
        rotateAnim.setRepeatCount(-1);
        addUpdateListener(rotateAnim,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                degrees = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animators.add(scaleAnim);
        animators.add(rotateAnim);
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallClipRotatePulseIndicator.java
New file
@@ -0,0 +1,92 @@
package com.wang.avi.indicators;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.animation.ValueAnimator;
import com.wang.avi.Indicator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/16.
 */
public class BallClipRotatePulseIndicator extends Indicator {
    float scaleFloat1,scaleFloat2,degrees;
    @Override
    public void draw(Canvas canvas, Paint paint) {
        float circleSpacing=12;
        float x=getWidth()/2;
        float y=getHeight()/2;
        //draw fill circle
        canvas.save();
        canvas.translate(x, y);
        canvas.scale(scaleFloat1, scaleFloat1);
        paint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(0, 0, x / 2.5f, paint);
        canvas.restore();
        canvas.translate(x, y);
        canvas.scale(scaleFloat2, scaleFloat2);
        canvas.rotate(degrees);
        paint.setStrokeWidth(3);
        paint.setStyle(Paint.Style.STROKE);
        //draw two arc
        float[] startAngles=new float[]{225,45};
        for (int i = 0; i < 2; i++) {
            RectF rectF=new RectF(-x+circleSpacing,-y+circleSpacing,x-circleSpacing,y-circleSpacing);
            canvas.drawArc(rectF, startAngles[i], 90, false, paint);
        }
    }
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.3f,1);
        scaleAnim.setDuration(1000);
        scaleAnim.setRepeatCount(-1);
        addUpdateListener(scaleAnim,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                scaleFloat1 = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        ValueAnimator scaleAnim2=ValueAnimator.ofFloat(1,0.6f,1);
        scaleAnim2.setDuration(1000);
        scaleAnim2.setRepeatCount(-1);
        addUpdateListener(scaleAnim2,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                scaleFloat2 = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        ValueAnimator rotateAnim=ValueAnimator.ofFloat(0, 180,360);
        rotateAnim.setDuration(1000);
        rotateAnim.setRepeatCount(-1);
        addUpdateListener(rotateAnim,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                degrees = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        animators.add(scaleAnim);
        animators.add(scaleAnim2);
        animators.add(rotateAnim);
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallGridBeatIndicator.java
New file
@@ -0,0 +1,76 @@
package com.wang.avi.indicators;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.animation.ValueAnimator;
import com.wang.avi.Indicator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/20.
 */
public class BallGridBeatIndicator extends Indicator {
    public static final int ALPHA=255;
    int[] alphas=new int[]{ALPHA,
            ALPHA,
            ALPHA,
            ALPHA,
            ALPHA,
            ALPHA,
            ALPHA,
            ALPHA,
            ALPHA};
    @Override
    public void draw(Canvas canvas, Paint paint) {
        float circleSpacing=4;
        float radius=(getWidth()-circleSpacing*4)/6;
        float x = getWidth()/ 2-(radius*2+circleSpacing);
        float y = getWidth()/ 2-(radius*2+circleSpacing);
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                canvas.save();
                float translateX=x+(radius*2)*j+circleSpacing*j;
                float translateY=y+(radius*2)*i+circleSpacing*i;
                canvas.translate(translateX, translateY);
                paint.setAlpha(alphas[3 * i + j]);
                canvas.drawCircle(0, 0, radius, paint);
                canvas.restore();
            }
        }
    }
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        int[] durations={960, 930, 1190, 1130, 1340, 940, 1200, 820, 1190};
        int[] delays= {360, 400, 680, 410, 710, -150, -120, 10, 320};
        for (int i = 0; i < 9; i++) {
            final int index=i;
            ValueAnimator alphaAnim=ValueAnimator.ofInt(255, 168,255);
            alphaAnim.setDuration(durations[i]);
            alphaAnim.setRepeatCount(-1);
            alphaAnim.setStartDelay(delays[i]);
            addUpdateListener(alphaAnim,new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    alphas[index] = (int) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            animators.add(alphaAnim);
        }
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallGridPulseIndicator.java
New file
@@ -0,0 +1,100 @@
package com.wang.avi.indicators;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.animation.ValueAnimator;
import com.wang.avi.Indicator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/16.
 */
public class BallGridPulseIndicator extends Indicator {
    public static final int ALPHA=255;
    public static final float SCALE=1.0f;
    int[] alphas=new int[]{ALPHA,
            ALPHA,
            ALPHA,
            ALPHA,
            ALPHA,
            ALPHA,
            ALPHA,
            ALPHA,
            ALPHA};
    float[] scaleFloats=new float[]{SCALE,
            SCALE,
            SCALE,
            SCALE,
            SCALE,
            SCALE,
            SCALE,
            SCALE,
            SCALE};
    @Override
    public void draw(Canvas canvas, Paint paint) {
        float circleSpacing=4;
        float radius=(getWidth()-circleSpacing*4)/6;
        float x = getWidth()/ 2-(radius*2+circleSpacing);
        float y = getWidth()/ 2-(radius*2+circleSpacing);
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                canvas.save();
                float translateX=x+(radius*2)*j+circleSpacing*j;
                float translateY=y+(radius*2)*i+circleSpacing*i;
                canvas.translate(translateX, translateY);
                canvas.scale(scaleFloats[3 * i + j], scaleFloats[3 * i + j]);
                paint.setAlpha(alphas[3 * i + j]);
                canvas.drawCircle(0, 0, radius, paint);
                canvas.restore();
            }
        }
    }
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        int[] durations={720, 1020, 1280, 1420, 1450, 1180, 870, 1450, 1060};
        int[] delays= {-60, 250, -170, 480, 310, 30, 460, 780, 450};
        for (int i = 0; i < 9; i++) {
            final int index=i;
            ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.5f,1);
            scaleAnim.setDuration(durations[i]);
            scaleAnim.setRepeatCount(-1);
            scaleAnim.setStartDelay(delays[i]);
            addUpdateListener(scaleAnim,new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    scaleFloats[index] = (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            ValueAnimator alphaAnim=ValueAnimator.ofInt(255, 210, 122, 255);
            alphaAnim.setDuration(durations[i]);
            alphaAnim.setRepeatCount(-1);
            alphaAnim.setStartDelay(delays[i]);
            addUpdateListener(alphaAnim,new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    alphas[index] = (int) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            animators.add(scaleAnim);
            animators.add(alphaAnim);
        }
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallPulseIndicator.java
New file
@@ -0,0 +1,67 @@
package com.wang.avi.indicators;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.animation.ValueAnimator;
import com.wang.avi.Indicator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/16.
 */
public class BallPulseIndicator extends Indicator {
    public static final float SCALE=1.0f;
    //scale x ,y
    private float[] scaleFloats=new float[]{SCALE,
            SCALE,
            SCALE};
    @Override
    public void draw(Canvas canvas, Paint paint) {
        float circleSpacing=4;
        float radius=(Math.min(getWidth(),getHeight())-circleSpacing*2)/6;
        float x = getWidth()/ 2-(radius*2+circleSpacing);
        float y=getHeight() / 2;
        for (int i = 0; i < 3; i++) {
            canvas.save();
            float translateX=x+(radius*2)*i+circleSpacing*i;
            canvas.translate(translateX, y);
            canvas.scale(scaleFloats[i], scaleFloats[i]);
            canvas.drawCircle(0, 0, radius, paint);
            canvas.restore();
        }
    }
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        int[] delays=new int[]{120,240,360};
        for (int i = 0; i < 3; i++) {
            final int index=i;
            ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.3f,1);
            scaleAnim.setDuration(750);
            scaleAnim.setRepeatCount(-1);
            scaleAnim.setStartDelay(delays[i]);
            addUpdateListener(scaleAnim,new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    scaleFloats[index] = (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            animators.add(scaleAnim);
        }
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallPulseRiseIndicator.java
New file
@@ -0,0 +1,69 @@
package com.wang.avi.indicators;
import android.animation.ValueAnimator;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.view.animation.LinearInterpolator;
import com.wang.avi.Indicator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/17.
 */
public class BallPulseRiseIndicator extends Indicator {
    private Camera mCamera;
    private Matrix mMatrix;
    private float degress;
    public BallPulseRiseIndicator(){
        mCamera=new Camera();
        mMatrix=new Matrix();
    }
    @Override
    public void draw(Canvas canvas, Paint paint) {
        mMatrix.reset();
        mCamera.save();
        mCamera.rotateX(degress);
        mCamera.getMatrix(mMatrix);
        mCamera.restore();
        mMatrix.preTranslate(-centerX(), -centerY());
        mMatrix.postTranslate(centerX(), centerY());
        canvas.concat(mMatrix);
        float radius=getWidth()/10;
        canvas.drawCircle(getWidth()/4,radius*2,radius,paint);
        canvas.drawCircle(getWidth()*3/4,radius*2,radius,paint);
        canvas.drawCircle(radius,getHeight()-2*radius,radius,paint);
        canvas.drawCircle(getWidth()/2,getHeight()-2*radius,radius,paint);
        canvas.drawCircle(getWidth()-radius,getHeight()-2*radius,radius,paint);
    }
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        ValueAnimator animator=ValueAnimator.ofFloat(0,360);
        addUpdateListener(animator,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                degress = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animator.setInterpolator(new LinearInterpolator());
        animator.setRepeatCount(-1);
        animator.setDuration(1500);
        animators.add(animator);
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallPulseSyncIndicator.java
New file
@@ -0,0 +1,57 @@
package com.wang.avi.indicators;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.animation.ValueAnimator;
import com.wang.avi.Indicator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/19.
 */
public class BallPulseSyncIndicator extends Indicator {
    float[] translateYFloats=new float[3];
    @Override
    public void draw(Canvas canvas, Paint paint) {
        float circleSpacing=4;
        float radius=(getWidth()-circleSpacing*2)/6;
        float x = getWidth()/ 2-(radius*2+circleSpacing);
        for (int i = 0; i < 3; i++) {
            canvas.save();
            float translateX=x+(radius*2)*i+circleSpacing*i;
            canvas.translate(translateX, translateYFloats[i]);
            canvas.drawCircle(0, 0, radius, paint);
            canvas.restore();
        }
    }
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        float circleSpacing=4;
        float radius=(getWidth()-circleSpacing*2)/6;
        int[] delays=new int[]{70,140,210};
        for (int i = 0; i < 3; i++) {
            final int index=i;
            ValueAnimator scaleAnim=ValueAnimator.ofFloat(getHeight()/2,getHeight()/2-radius*2,getHeight()/2);
            scaleAnim.setDuration(600);
            scaleAnim.setRepeatCount(-1);
            scaleAnim.setStartDelay(delays[i]);
            addUpdateListener(scaleAnim,new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    translateYFloats[index] = (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            animators.add(scaleAnim);
        }
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallRotateIndicator.java
New file
@@ -0,0 +1,89 @@
package com.wang.avi.indicators;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import com.wang.avi.Indicator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/17.
 */
public class BallRotateIndicator extends Indicator {
    float scaleFloat=0.5f;
    float degress;
    private Matrix mMatrix;
    public BallRotateIndicator(){
        mMatrix=new Matrix();
    }
    @Override
    public void draw(Canvas canvas, Paint paint) {
        float radius=getWidth()/10;
        float x = getWidth()/ 2;
        float y=getHeight()/2;
        /*mMatrix.preTranslate(-centerX(), -centerY());
        mMatrix.preRotate(degress,centerX(),centerY());
        mMatrix.postTranslate(centerX(), centerY());
        canvas.concat(mMatrix);*/
        canvas.rotate(degress,centerX(),centerY());
        canvas.save();
        canvas.translate(x - radius * 2 - radius, y);
        canvas.scale(scaleFloat, scaleFloat);
        canvas.drawCircle(0, 0, radius, paint);
        canvas.restore();
        canvas.save();
        canvas.translate(x, y);
        canvas.scale(scaleFloat, scaleFloat);
        canvas.drawCircle(0, 0, radius, paint);
        canvas.restore();
        canvas.save();
        canvas.translate(x + radius * 2 + radius, y);
        canvas.scale(scaleFloat, scaleFloat);
        canvas.drawCircle(0,0,radius, paint);
        canvas.restore();
    }
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        ValueAnimator scaleAnim=ValueAnimator.ofFloat(0.5f,1,0.5f);
        scaleAnim.setDuration(1000);
        scaleAnim.setRepeatCount(-1);
        addUpdateListener(scaleAnim,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                scaleFloat = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        ValueAnimator rotateAnim=ValueAnimator.ofFloat(0,180,360);
        addUpdateListener(rotateAnim,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                degress = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        rotateAnim.setDuration(1000);
        rotateAnim.setRepeatCount(-1);
        animators.add(scaleAnim);
        animators.add(rotateAnim);
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallScaleIndicator.java
New file
@@ -0,0 +1,60 @@
package com.wang.avi.indicators;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.animation.LinearInterpolator;
import android.animation.ValueAnimator;
import com.wang.avi.Indicator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/19.
 */
public class BallScaleIndicator extends Indicator {
    float scale=1;
    int alpha=255;
    @Override
    public void draw(Canvas canvas, Paint paint) {
        float circleSpacing=4;
        paint.setAlpha(alpha);
        canvas.scale(scale,scale,getWidth()/2,getHeight()/2);
        paint.setAlpha(alpha);
        canvas.drawCircle(getWidth()/2,getHeight()/2,getWidth()/2-circleSpacing,paint);
    }
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        ValueAnimator scaleAnim=ValueAnimator.ofFloat(0,1);
        scaleAnim.setInterpolator(new LinearInterpolator());
        scaleAnim.setDuration(1000);
        scaleAnim.setRepeatCount(-1);
        addUpdateListener(scaleAnim,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                scale = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        ValueAnimator alphaAnim=ValueAnimator.ofInt(255, 0);
        alphaAnim.setInterpolator(new LinearInterpolator());
        alphaAnim.setDuration(1000);
        alphaAnim.setRepeatCount(-1);
        addUpdateListener(alphaAnim,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                alpha = (int) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animators.add(scaleAnim);
        animators.add(alphaAnim);
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallScaleMultipleIndicator.java
New file
@@ -0,0 +1,68 @@
package com.wang.avi.indicators;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.animation.LinearInterpolator;
import android.animation.ValueAnimator;
import com.wang.avi.Indicator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/19.
 */
public class BallScaleMultipleIndicator extends Indicator {
    float[] scaleFloats=new float[]{1,1,1};
    int[] alphaInts=new int[]{255,255,255};
    @Override
    public void draw(Canvas canvas, Paint paint) {
        float circleSpacing=4;
        for (int i = 0; i < 3; i++) {
            paint.setAlpha(alphaInts[i]);
            canvas.scale(scaleFloats[i],scaleFloats[i],getWidth()/2,getHeight()/2);
            canvas.drawCircle(getWidth()/2,getHeight()/2,getWidth()/2-circleSpacing,paint);
        }
    }
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        long[] delays=new long[]{0, 200, 400};
        for (int i = 0; i < 3; i++) {
            final int index=i;
            ValueAnimator scaleAnim=ValueAnimator.ofFloat(0,1);
            scaleAnim.setInterpolator(new LinearInterpolator());
            scaleAnim.setDuration(1000);
            scaleAnim.setRepeatCount(-1);
            addUpdateListener(scaleAnim,new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    scaleFloats[index] = (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            scaleAnim.setStartDelay(delays[i]);
            ValueAnimator alphaAnim=ValueAnimator.ofInt(255,0);
            alphaAnim.setInterpolator(new LinearInterpolator());
            alphaAnim.setDuration(1000);
            alphaAnim.setRepeatCount(-1);
            addUpdateListener(alphaAnim,new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    alphaInts[index] = (int) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            scaleAnim.setStartDelay(delays[i]);
            animators.add(scaleAnim);
            animators.add(alphaAnim);
        }
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallScaleRippleIndicator.java
New file
@@ -0,0 +1,56 @@
package com.wang.avi.indicators;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.animation.LinearInterpolator;
import android.animation.ValueAnimator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/19.
 */
public class BallScaleRippleIndicator extends BallScaleIndicator {
    @Override
    public void draw(Canvas canvas, Paint paint) {
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(3);
        super.draw(canvas, paint);
    }
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        ValueAnimator scaleAnim=ValueAnimator.ofFloat(0,1);
        scaleAnim.setInterpolator(new LinearInterpolator());
        scaleAnim.setDuration(1000);
        scaleAnim.setRepeatCount(-1);
        addUpdateListener(scaleAnim,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                scale = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        ValueAnimator alphaAnim=ValueAnimator.ofInt(0, 255);
        alphaAnim.setInterpolator(new LinearInterpolator());
        alphaAnim.setDuration(1000);
        alphaAnim.setRepeatCount(-1);
        addUpdateListener(alphaAnim,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                alpha = (int) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animators.add(scaleAnim);
        animators.add(alphaAnim);
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallScaleRippleMultipleIndicator.java
New file
@@ -0,0 +1,62 @@
package com.wang.avi.indicators;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.animation.LinearInterpolator;
import android.animation.ValueAnimator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/19.
 */
public class BallScaleRippleMultipleIndicator extends BallScaleMultipleIndicator {
    @Override
    public void draw(Canvas canvas, Paint paint) {
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(3);
        super.draw(canvas, paint);
    }
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        long[] delays=new long[]{0, 200, 400};
        for (int i = 0; i < 3; i++) {
            final int index=i;
            ValueAnimator scaleAnim=ValueAnimator.ofFloat(0,1);
            scaleAnim.setInterpolator(new LinearInterpolator());
            scaleAnim.setDuration(1000);
            scaleAnim.setRepeatCount(-1);
            addUpdateListener(scaleAnim,new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    scaleFloats[index] = (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            scaleAnim.setStartDelay(delays[i]);
            ValueAnimator alphaAnim=ValueAnimator.ofInt(0,255);
            scaleAnim.setInterpolator(new LinearInterpolator());
            alphaAnim.setDuration(1000);
            alphaAnim.setRepeatCount(-1);
            addUpdateListener(alphaAnim,new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    alphaInts[index] = (int) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            scaleAnim.setStartDelay(delays[i]);
            animators.add(scaleAnim);
            animators.add(alphaAnim);
        }
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallSpinFadeLoaderIndicator.java
New file
@@ -0,0 +1,114 @@
package com.wang.avi.indicators;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.animation.ValueAnimator;
import com.wang.avi.Indicator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/20.
 */
public class BallSpinFadeLoaderIndicator extends Indicator {
    public static final float SCALE=1.0f;
    public static final int ALPHA=255;
    float[] scaleFloats=new float[]{SCALE,
            SCALE,
            SCALE,
            SCALE,
            SCALE,
            SCALE,
            SCALE,
            SCALE};
    int[] alphas=new int[]{ALPHA,
            ALPHA,
            ALPHA,
            ALPHA,
            ALPHA,
            ALPHA,
            ALPHA,
            ALPHA};
    @Override
    public void draw(Canvas canvas, Paint paint) {
        float radius=getWidth()/10;
        for (int i = 0; i < 8; i++) {
            canvas.save();
            Point point=circleAt(getWidth(),getHeight(),getWidth()/2-radius,i*(Math.PI/4));
            canvas.translate(point.x,point.y);
            canvas.scale(scaleFloats[i],scaleFloats[i]);
            paint.setAlpha(alphas[i]);
            canvas.drawCircle(0,0,radius,paint);
            canvas.restore();
        }
    }
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        int[] delays= {0, 120, 240, 360, 480, 600, 720, 780, 840};
        for (int i = 0; i < 8; i++) {
            final int index=i;
            ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.4f,1);
            scaleAnim.setDuration(1000);
            scaleAnim.setRepeatCount(-1);
            scaleAnim.setStartDelay(delays[i]);
            addUpdateListener(scaleAnim,new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    scaleFloats[index] = (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            ValueAnimator alphaAnim=ValueAnimator.ofInt(255, 77, 255);
            alphaAnim.setDuration(1000);
            alphaAnim.setRepeatCount(-1);
            alphaAnim.setStartDelay(delays[i]);
            addUpdateListener(alphaAnim,new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    alphas[index] = (int) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            animators.add(scaleAnim);
            animators.add(alphaAnim);
        }
        return animators;
    }
    /**
     * 圆O的圆心为(a,b),半径为R,点A与到X轴的为角α.
     *则点A的坐标为(a+R*cosα,b+R*sinα)
     * @param width
     * @param height
     * @param radius
     * @param angle
     * @return
     */
    Point circleAt(int width,int height,float radius,double angle){
        float x= (float) (width/2+radius*(Math.cos(angle)));
        float y= (float) (height/2+radius*(Math.sin(angle)));
        return new Point(x,y);
    }
    final class Point{
        public float x;
        public float y;
        public Point(float x, float y){
            this.x=x;
            this.y=y;
        }
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallTrianglePathIndicator.java
New file
@@ -0,0 +1,80 @@
package com.wang.avi.indicators;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.animation.LinearInterpolator;
import android.animation.ValueAnimator;
import com.wang.avi.Indicator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/19.
 */
public class BallTrianglePathIndicator extends Indicator {
    float[] translateX=new float[3],translateY=new float[3];
    @Override
    public void draw(Canvas canvas, Paint paint) {
        paint.setStrokeWidth(3);
        paint.setStyle(Paint.Style.STROKE);
        for (int i = 0; i < 3; i++) {
            canvas.save();
            canvas.translate(translateX[i], translateY[i]);
            canvas.drawCircle(0, 0, getWidth() / 10, paint);
            canvas.restore();
        }
    }
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        float startX=getWidth()/5;
        float startY=getWidth()/5;
        for (int i = 0; i < 3; i++) {
            final int index=i;
            ValueAnimator translateXAnim=ValueAnimator.ofFloat(getWidth()/2,getWidth()-startX,startX,getWidth()/2);
            if (i==1){
                translateXAnim=ValueAnimator.ofFloat(getWidth()-startX,startX,getWidth()/2,getWidth()-startX);
            }else if (i==2){
                translateXAnim=ValueAnimator.ofFloat(startX,getWidth()/2,getWidth()-startX,startX);
            }
            ValueAnimator translateYAnim=ValueAnimator.ofFloat(startY,getHeight()-startY,getHeight()-startY,startY);
            if (i==1){
                translateYAnim=ValueAnimator.ofFloat(getHeight()-startY,getHeight()-startY,startY,getHeight()-startY);
            }else if (i==2){
                translateYAnim=ValueAnimator.ofFloat(getHeight()-startY,startY,getHeight()-startY,getHeight()-startY);
            }
            translateXAnim.setDuration(2000);
            translateXAnim.setInterpolator(new LinearInterpolator());
                translateXAnim.setRepeatCount(-1);
            addUpdateListener(translateXAnim,new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    translateX [index]= (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            translateYAnim.setDuration(2000);
            translateYAnim.setInterpolator(new LinearInterpolator());
            translateYAnim.setRepeatCount(-1);
            addUpdateListener(translateYAnim,new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    translateY [index]= (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            animators.add(translateXAnim);
            animators.add(translateYAnim);
        }
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallZigZagDeflectIndicator.java
New file
@@ -0,0 +1,60 @@
package com.wang.avi.indicators;
import android.view.animation.LinearInterpolator;
import android.animation.ValueAnimator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/19.
 */
public class BallZigZagDeflectIndicator extends BallZigZagIndicator {
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        float startX=getWidth()/6;
        float startY=getWidth()/6;
        for (int i = 0; i < 2; i++) {
            final int index=i;
            ValueAnimator translateXAnim=ValueAnimator.ofFloat(startX,getWidth()-startX,startX,getWidth()-startX,startX);
            if (i==1){
                translateXAnim=ValueAnimator.ofFloat(getWidth()-startX,startX,getWidth()-startX,startX,getWidth()-startX);
            }
            ValueAnimator translateYAnim=ValueAnimator.ofFloat(startY,startY,getHeight()-startY,getHeight()-startY,startY);
            if (i==1){
                translateYAnim=ValueAnimator.ofFloat(getHeight()-startY,getHeight()-startY,startY,startY,getHeight()-startY);
            }
            translateXAnim.setDuration(2000);
            translateXAnim.setInterpolator(new LinearInterpolator());
            translateXAnim.setRepeatCount(-1);
            addUpdateListener(translateXAnim,new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    translateX [index]= (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            translateYAnim.setDuration(2000);
            translateYAnim.setInterpolator(new LinearInterpolator());
            translateYAnim.setRepeatCount(-1);
            addUpdateListener(translateYAnim,new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    translateY [index]= (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            animators.add(translateXAnim);
            animators.add(translateYAnim);
        }
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/BallZigZagIndicator.java
New file
@@ -0,0 +1,73 @@
package com.wang.avi.indicators;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.animation.LinearInterpolator;
import android.animation.ValueAnimator;
import com.wang.avi.Indicator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/19.
 */
public class BallZigZagIndicator extends Indicator {
    float[] translateX=new float[2],translateY=new float[2];
    @Override
    public void draw(Canvas canvas, Paint paint) {
        for (int i = 0; i < 2; i++) {
            canvas.save();
            canvas.translate(translateX[i], translateY[i]);
            canvas.drawCircle(0, 0, getWidth() / 10, paint);
            canvas.restore();
        }
    }
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        float startX=getWidth()/6;
        float startY=getWidth()/6;
        for (int i = 0; i < 2; i++) {
            final int index=i;
            ValueAnimator translateXAnim=ValueAnimator.ofFloat(startX,getWidth()-startX,getWidth()/2,startX);
            if (i==1){
                translateXAnim=ValueAnimator.ofFloat(getWidth()-startX,startX,getWidth()/2,getWidth()-startX);
            }
            ValueAnimator translateYAnim=ValueAnimator.ofFloat(startY,startY,getHeight()/2,startY);
            if (i==1){
                translateYAnim=ValueAnimator.ofFloat(getHeight()-startY,getHeight()-startY,getHeight()/2,getHeight()-startY);
            }
            translateXAnim.setDuration(1000);
            translateXAnim.setInterpolator(new LinearInterpolator());
            translateXAnim.setRepeatCount(-1);
            addUpdateListener(translateXAnim,new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    translateX[index] = (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            translateYAnim.setDuration(1000);
            translateYAnim.setInterpolator(new LinearInterpolator());
            translateYAnim.setRepeatCount(-1);
            addUpdateListener(translateYAnim,new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    translateY[index] = (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            animators.add(translateXAnim);
            animators.add(translateYAnim);
        }
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/CubeTransitionIndicator.java
New file
@@ -0,0 +1,106 @@
package com.wang.avi.indicators;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.view.animation.LinearInterpolator;
import android.animation.ValueAnimator;
import com.wang.avi.Indicator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/18.
 */
public class CubeTransitionIndicator extends Indicator {
    float[] translateX=new float[2],translateY=new float[2];
    float degrees,scaleFloat=1.0f;
    @Override
    public void draw(Canvas canvas, Paint paint) {
        float rWidth=getWidth()/5;
        float rHeight=getHeight()/5;
        for (int i = 0; i < 2; i++) {
            canvas.save();
            canvas.translate(translateX[i], translateY[i]);
            canvas.rotate(degrees);
            canvas.scale(scaleFloat,scaleFloat);
            RectF rectF=new RectF(-rWidth/2,-rHeight/2,rWidth/2,rHeight/2);
            canvas.drawRect(rectF,paint);
            canvas.restore();
        }
    }
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        float startX=getWidth()/5;
        float startY=getHeight()/5;
        for (int i = 0; i < 2; i++) {
            final int index=i;
            translateX[index]=startX;
            ValueAnimator translationXAnim=ValueAnimator.ofFloat(startX,getWidth()-startX,getWidth()-startX, startX,startX);
            if (i==1){
                translationXAnim=ValueAnimator.ofFloat(getWidth()-startX,startX,startX, getWidth()-startX,getWidth()-startX);
            }
            translationXAnim.setInterpolator(new LinearInterpolator());
            translationXAnim.setDuration(1600);
            translationXAnim.setRepeatCount(-1);
            translationXAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    translateX[index] = (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            translateY[index]=startY;
            ValueAnimator translationYAnim=ValueAnimator.ofFloat(startY,startY,getHeight()-startY,getHeight()- startY,startY);
            if (i==1){
                translationYAnim=ValueAnimator.ofFloat(getHeight()-startY,getHeight()-startY,startY,startY,getHeight()-startY);
            }
            translationYAnim.setDuration(1600);
            translationYAnim.setInterpolator(new LinearInterpolator());
            translationYAnim.setRepeatCount(-1);
            addUpdateListener(translationYAnim,new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    translateY[index] = (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            animators.add(translationXAnim);
            animators.add(translationYAnim);
        }
        ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.5f,1,0.5f,1);
        scaleAnim.setDuration(1600);
        scaleAnim.setInterpolator(new LinearInterpolator());
        scaleAnim.setRepeatCount(-1);
        addUpdateListener(scaleAnim,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                scaleFloat = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        ValueAnimator rotateAnim=ValueAnimator.ofFloat(0,180,360,1.5f*360,2*360);
        rotateAnim.setDuration(1600);
        rotateAnim.setInterpolator(new LinearInterpolator());
        rotateAnim.setRepeatCount(-1);
        addUpdateListener(rotateAnim,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                degrees = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animators.add(scaleAnim);
        animators.add(rotateAnim);
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/LineScaleIndicator.java
New file
@@ -0,0 +1,61 @@
package com.wang.avi.indicators;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.animation.ValueAnimator;
import com.wang.avi.Indicator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/19.
 */
public class LineScaleIndicator extends Indicator {
    public static final float SCALE=1.0f;
    float[] scaleYFloats=new float[]{SCALE,
            SCALE,
            SCALE,
            SCALE,
            SCALE,};
    @Override
    public void draw(Canvas canvas, Paint paint) {
        float translateX=getWidth()/11;
        float translateY=getHeight()/2;
        for (int i = 0; i < 5; i++) {
            canvas.save();
            canvas.translate((2 + i * 2) * translateX - translateX / 2, translateY);
            canvas.scale(SCALE, scaleYFloats[i]);
            RectF rectF=new RectF(-translateX/2,-getHeight()/2.5f,translateX/2,getHeight()/2.5f);
            canvas.drawRoundRect(rectF, 5, 5, paint);
            canvas.restore();
        }
    }
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        long[] delays=new long[]{100,200,300,400,500};
        for (int i = 0; i < 5; i++) {
            final int index=i;
            ValueAnimator scaleAnim=ValueAnimator.ofFloat(1, 0.4f, 1);
            scaleAnim.setDuration(1000);
            scaleAnim.setRepeatCount(-1);
            scaleAnim.setStartDelay(delays[i]);
            addUpdateListener(scaleAnim,new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    scaleYFloats[index] = (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            animators.add(scaleAnim);
        }
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/LineScalePartyIndicator.java
New file
@@ -0,0 +1,64 @@
package com.wang.avi.indicators;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.animation.ValueAnimator;
import com.wang.avi.Indicator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/19.
 */
public class LineScalePartyIndicator extends Indicator {
    public static final float SCALE=1.0f;
    float[] scaleFloats=new float[]{SCALE,
            SCALE,
            SCALE,
            SCALE,
            SCALE,};
    @Override
    public void draw(Canvas canvas, Paint paint) {
        float translateX=getWidth()/9;
        float translateY=getHeight()/2;
        for (int i = 0; i < 4; i++) {
            canvas.save();
            canvas.translate((2 + i * 2) * translateX - translateX / 2, translateY);
            canvas.scale(scaleFloats[i], scaleFloats[i]);
            RectF rectF=new RectF(-translateX/2,-getHeight()/2.5f,translateX/2,getHeight()/2.5f);
            canvas.drawRoundRect(rectF,5,5,paint);
            canvas.restore();
        }
    }
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        long[] durations=new long[]{1260, 430, 1010, 730};
        long[] delays=new long[]{770, 290, 280, 740};
        for (int i = 0; i < 4; i++) {
            final int index=i;
            ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.4f,1);
            scaleAnim.setDuration(durations[i]);
            scaleAnim.setRepeatCount(-1);
            scaleAnim.setStartDelay(delays[i]);
            addUpdateListener(scaleAnim,new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    scaleFloats[index] = (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            animators.add(scaleAnim);
        }
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/LineScalePulseOutIndicator.java
New file
@@ -0,0 +1,35 @@
package com.wang.avi.indicators;
import android.animation.ValueAnimator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/19.
 */
public class LineScalePulseOutIndicator extends LineScaleIndicator {
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        long[] delays=new long[]{500,250,0,250,500};
        for (int i = 0; i < 5; i++) {
            final int index=i;
            ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.3f,1);
            scaleAnim.setDuration(900);
            scaleAnim.setRepeatCount(-1);
            scaleAnim.setStartDelay(delays[i]);
            addUpdateListener(scaleAnim,new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    scaleYFloats[index] = (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            animators.add(scaleAnim);
        }
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/LineScalePulseOutRapidIndicator.java
New file
@@ -0,0 +1,35 @@
package com.wang.avi.indicators;
import android.animation.ValueAnimator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/19.
 */
public class LineScalePulseOutRapidIndicator extends LineScaleIndicator {
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        long[] delays=new long[]{400,200,0,200,400};
        for (int i = 0; i < 5; i++) {
            final int index=i;
            ValueAnimator scaleAnim=ValueAnimator.ofFloat(1,0.4f,1);
            scaleAnim.setDuration(1000);
            scaleAnim.setRepeatCount(-1);
            scaleAnim.setStartDelay(delays[i]);
            addUpdateListener(scaleAnim,new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    scaleYFloats[index] = (float) animation.getAnimatedValue();
                    postInvalidate();
                }
            });
            animators.add(scaleAnim);
        }
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/LineSpinFadeLoaderIndicator.java
New file
@@ -0,0 +1,30 @@
package com.wang.avi.indicators;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
/**
 * Created by Jack on 2015/10/24.
 * Email:81813780@qq.com
 */
public class LineSpinFadeLoaderIndicator extends BallSpinFadeLoaderIndicator {
    @Override
    public void draw(Canvas canvas, Paint paint) {
        float radius=getWidth()/10;
        for (int i = 0; i < 8; i++) {
            canvas.save();
            Point point=circleAt(getWidth(),getHeight(),getWidth()/2.5f-radius,i*(Math.PI/4));
            canvas.translate(point.x, point.y);
            canvas.scale(scaleFloats[i], scaleFloats[i]);
            canvas.rotate(i*45);
            paint.setAlpha(alphas[i]);
            RectF rectF=new RectF(-radius,-radius/1.5f,1.5f*radius,radius/1.5f);
            canvas.drawRoundRect(rectF,5,5,paint);
            canvas.restore();
        }
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/PacmanIndicator.java
New file
@@ -0,0 +1,115 @@
package com.wang.avi.indicators;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.view.animation.LinearInterpolator;
import android.animation.ValueAnimator;
import com.wang.avi.Indicator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/16.
 */
public class PacmanIndicator extends Indicator {
    private float translateX;
    private int alpha;
    private float degrees1,degrees2;
    @Override
    public void draw(Canvas canvas, Paint paint) {
        drawPacman(canvas,paint);
        drawCircle(canvas,paint);
    }
    private void drawPacman(Canvas canvas,Paint paint){
        float x=getWidth()/2;
        float y=getHeight()/2;
        canvas.save();
        canvas.translate(x, y);
        canvas.rotate(degrees1);
        paint.setAlpha(255);
        RectF rectF1=new RectF(-x/1.7f,-y/1.7f,x/1.7f,y/1.7f);
        canvas.drawArc(rectF1, 0, 270, true, paint);
        canvas.restore();
        canvas.save();
        canvas.translate(x, y);
        canvas.rotate(degrees2);
        paint.setAlpha(255);
        RectF rectF2=new RectF(-x/1.7f,-y/1.7f,x/1.7f,y/1.7f);
        canvas.drawArc(rectF2,90,270,true,paint);
        canvas.restore();
    }
    private void drawCircle(Canvas canvas, Paint paint) {
        float radius=getWidth()/11;
        paint.setAlpha(alpha);
        canvas.drawCircle(translateX, getHeight() / 2, radius, paint);
    }
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        float startT=getWidth()/11;
        ValueAnimator translationAnim=ValueAnimator.ofFloat(getWidth()-startT,getWidth()/2);
        translationAnim.setDuration(650);
        translationAnim.setInterpolator(new LinearInterpolator());
        translationAnim.setRepeatCount(-1);
        addUpdateListener(translationAnim,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                translateX = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        ValueAnimator alphaAnim=ValueAnimator.ofInt(255,122);
        alphaAnim.setDuration(650);
        alphaAnim.setRepeatCount(-1);
        addUpdateListener(alphaAnim,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                alpha = (int) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        ValueAnimator rotateAnim1=ValueAnimator.ofFloat(0, 45, 0);
        rotateAnim1.setDuration(650);
        rotateAnim1.setRepeatCount(-1);
        addUpdateListener(rotateAnim1,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                degrees1 = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        ValueAnimator rotateAnim2=ValueAnimator.ofFloat(0,-45,0);
        rotateAnim2.setDuration(650);
        rotateAnim2.setRepeatCount(-1);
        addUpdateListener(rotateAnim2,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                degrees2 = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animators.add(translationAnim);
        animators.add(alphaAnim);
        animators.add(rotateAnim1);
        animators.add(rotateAnim2);
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/SemiCircleSpinIndicator.java
New file
@@ -0,0 +1,43 @@
package com.wang.avi.indicators;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import com.wang.avi.Indicator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/20.
 */
public class SemiCircleSpinIndicator extends Indicator {
    private float degress;
    @Override
    public void draw(Canvas canvas, Paint paint) {
        canvas.rotate(degress,centerX(),centerY());
        RectF rectF=new RectF(0,0,getWidth(),getHeight());
        canvas.drawArc(rectF,-60,120,false,paint);
    }
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        ValueAnimator rotateAnim=ValueAnimator.ofFloat(0,180,360);
        addUpdateListener(rotateAnim,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                degress= (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        rotateAnim.setDuration(600);
        rotateAnim.setRepeatCount(-1);
        animators.add(rotateAnim);
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/SquareSpinIndicator.java
New file
@@ -0,0 +1,80 @@
package com.wang.avi.indicators;
import android.animation.ValueAnimator;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.RectF;
import android.view.animation.LinearInterpolator;
import com.wang.avi.Indicator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/16.
 */
public class SquareSpinIndicator extends Indicator {
    private float rotateX;
    private float rotateY;
    private Camera mCamera;
    private Matrix mMatrix;
    public SquareSpinIndicator(){
        mCamera=new Camera();
        mMatrix=new Matrix();
    }
    @Override
    public void draw(Canvas canvas, Paint paint) {
        mMatrix.reset();
        mCamera.save();
        mCamera.rotateX(rotateX);
        mCamera.rotateY(rotateY);
        mCamera.getMatrix(mMatrix);
        mCamera.restore();
        mMatrix.preTranslate(-centerX(), -centerY());
        mMatrix.postTranslate(centerX(), centerY());
        canvas.concat(mMatrix);
        canvas.drawRect(new RectF(getWidth()/5,getHeight()/5,getWidth()*4/5,getHeight()*4/5),paint);
    }
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        ValueAnimator animator=ValueAnimator.ofFloat(0,180,180,0,0);
        addUpdateListener(animator,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                rotateX= (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animator.setInterpolator(new LinearInterpolator());
        animator.setRepeatCount(-1);
        animator.setDuration(2500);
        ValueAnimator animator1=ValueAnimator.ofFloat(0,0,180,180,0);
        addUpdateListener(animator1,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                rotateY= (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animator1.setInterpolator(new LinearInterpolator());
        animator1.setRepeatCount(-1);
        animator1.setDuration(2500);
        animators.add(animator);
        animators.add(animator1);
        return animators;
    }
}
pickerviewlibrary/src/main/java/com/wang/avi/indicators/TriangleSkewSpinIndicator.java
New file
@@ -0,0 +1,86 @@
package com.wang.avi.indicators;
import android.animation.ValueAnimator;
import android.graphics.Camera;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.view.animation.LinearInterpolator;
import com.wang.avi.Indicator;
import java.util.ArrayList;
/**
 * Created by Jack on 2015/10/20.
 */
public class TriangleSkewSpinIndicator extends Indicator {
    private float rotateX;
    private float rotateY;
    private Camera mCamera;
    private Matrix mMatrix;
    public TriangleSkewSpinIndicator(){
        mCamera=new Camera();
        mMatrix=new Matrix();
    }
    @Override
    public void draw(Canvas canvas, Paint paint) {
        mMatrix.reset();
        mCamera.save();
        mCamera.rotateX(rotateX);
        mCamera.rotateY(rotateY);
        mCamera.getMatrix(mMatrix);
        mCamera.restore();
        mMatrix.preTranslate(-centerX(), -centerY());
        mMatrix.postTranslate(centerX(), centerY());
        canvas.concat(mMatrix);
        Path path=new Path();
        path.moveTo(getWidth()/5,getHeight()*4/5);
        path.lineTo(getWidth()*4/5, getHeight()*4/5);
        path.lineTo(getWidth()/2,getHeight()/5);
        path.close();
        canvas.drawPath(path, paint);
    }
    @Override
    public ArrayList<ValueAnimator> onCreateAnimators() {
        ArrayList<ValueAnimator> animators=new ArrayList<>();
        ValueAnimator animator=ValueAnimator.ofFloat(0,180,180,0,0);
        addUpdateListener(animator,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                rotateX= (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animator.setInterpolator(new LinearInterpolator());
        animator.setRepeatCount(-1);
        animator.setDuration(2500);
        ValueAnimator animator1=ValueAnimator.ofFloat(0,0,180,180,0);
        addUpdateListener(animator1,new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                rotateY= (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animator1.setInterpolator(new LinearInterpolator());
        animator1.setRepeatCount(-1);
        animator1.setDuration(2500);
        animators.add(animator);
        animators.add(animator1);
        return animators;
    }
}
pickerviewlibrary/src/main/res/values/attrs.xml
@@ -19,4 +19,13 @@
        <attr name="wheelview_dividerWidth" format="dimension"/>
        <attr name="wheelview_lineSpacingMultiplier" format="float"/>
    </declare-styleable>
    <declare-styleable name="AVLoadingIndicatorView">
        <attr name="minWidth" format="dimension" />
        <attr name="maxWidth" format="dimension"/>
        <attr name="minHeight" format="dimension" />
        <attr name="maxHeight" format="dimension"/>
        <attr name="indicatorName" format="string"/>
        <attr name="indicatorColor" format="color"/>
    </declare-styleable>
</resources>
pickerviewlibrary/src/main/res/values/styles.xml
@@ -40,4 +40,28 @@
        <item name="android:windowEnterAnimation">@anim/pickerview_slide_in_bottom</item>
        <item name="android:windowExitAnimation">@anim/pickerview_slide_out_bottom</item>
    </style>
    <style name="AVLoadingIndicatorView">
        <item name="minWidth">48dip</item>
        <item name="maxWidth">48dip</item>
        <item name="minHeight">48dip</item>
        <item name="maxHeight">48dip</item>
        <item name="indicatorName">BallPulseIndicator</item>
    </style>
    <style name="AVLoadingIndicatorView.Large">
        <item name="minWidth">76dip</item>
        <item name="maxWidth">76dip</item>
        <item name="minHeight">76dip</item>
        <item name="maxHeight">76dip</item>
        <item name="indicatorName">BallPulseIndicator</item>
    </style>
    <style name="AVLoadingIndicatorView.Small">
        <item name="minWidth">24dip</item>
        <item name="maxWidth">24dip</item>
        <item name="minHeight">24dip</item>
        <item name="maxHeight">24dip</item>
        <item name="indicatorName">BallPulseIndicator</item>
    </style>
</resources>
qihealonelibrary/build.gradle
@@ -64,7 +64,7 @@
    compileOnly 'com.github.getActivity:XXPermissions:18.5'
    //滚动选择框
//    compileOnly 'com.contrarywind:Android-PickerView:4.1.9'
    implementation files('../baselibrary/libs/avi.library-2.1.3.aar')
    //列表
    compileOnly 'io.github.scwang90:refresh-layout-kernel:2.0.5'
    compileOnly 'io.github.scwang90:refresh-header-classics:2.0.5'
qiheonlinelibrary/build.gradle
@@ -81,8 +81,7 @@
    compileOnly 'io.github.scwang90:refresh-header-classics:2.0.5'
    compileOnly 'androidx.recyclerview:recyclerview:1.2.0'//经典刷新头
    //将注释掉的远程依赖改为本地aar引用
    compileOnly files('../baselibrary/libs/avi.library-2.1.3.aar')
    compileOnly group: 'net.sourceforge.jexcelapi', name: 'jxl', version: '2.6.12'
}