diff --git a/.idea/gradle.xml b/.idea/gradle.xml index a2d7c21..0d498f0 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -11,6 +11,7 @@ diff --git a/.idea/misc.xml b/.idea/misc.xml index 5593996..1fce2ca 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -25,6 +25,12 @@ + + + + + + diff --git a/app/build.gradle b/app/build.gradle index 3b9ad01..e023237 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -83,40 +83,20 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'com.google.android.material:material:1.2.1' implementation 'androidx.constraintlayout:constraintlayout:2.0.1' - implementation 'org.jetbrains:annotations:15.0' - //implementation files('libs\\AMap2DMap_6.0.0_AMapSearch_7.9.0_20210331.jar') -// implementation files('libs\\AMap_Location_V5.3.1_20210331.jar') - //implementation files('libs\\Android_Lite3DMap_SDK_V1.2.0_20210412.jar') -// implementation files('libs\\AMap2DMap_6.0.0_AMapSearch_7.9.0_20210331.jar') - //implementation files('libs\\android-support-v4.jar') - testImplementation 'junit:junit:4.+' - androidTestImplementation 'androidx.test.ext:junit:1.1.2' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' - //图片 - implementation 'com.github.bumptech.glide:glide:4.11.0' +// implementation 'org.jetbrains:annotations:15.0' implementation 'top.zibin:Luban:1.1.3' - //okhttp - implementation 'com.squareup.okhttp3:okhttp:3.2.0' - //gson - implementation 'com.google.code.gson:gson:2.8.5' //角标文字 implementation 'com.haozhang.libary:android-slanted-textview:1.2' //加载 implementation 'com.scwang.smart:refresh-layout-kernel:2.0.1' implementation 'com.scwang.smart:refresh-header-material:2.0.1' - implementation 'com.scwang.smart:refresh-footer-ball:2.0.1' //球脉冲加载 - implementation 'com.scwang.smart:refresh-footer-classics:2.0.1' //经典加载 implementation 'com.alibaba:fastjson:1.2.61' - //弹框 - // - implementation 'com.lxj:xpopup:2.2.8' //更新版本 implementation 'com.github.jenly1314.AppUpdater:app-updater:1.1.0' implementation 'com.github.jenly1314.AppUpdater:app-dialog:1.1.0' //轮播插件 implementation 'com.github.zhpanvip:BannerViewPager:3.5.4' //选择器 - //implementation 'com.github.gzu-liyujiang:AndroidPicker:Tag' implementation 'com.github.gzu-liyujiang.AndroidPicker:WheelPicker:3.1.1' implementation 'com.github.gzu-liyujiang.AndroidPicker:AddressPicker:3.1.1' //EventBus @@ -125,13 +105,6 @@ dependencies { //工具类 implementation 'cn.hutool:hutool-all:5.7.11' //UI库 - implementation 'com.github.tamsiree.RxTool:RxUI:2.6.2' - //相机库 - implementation 'com.github.tamsiree.RxTool:RxCamera:2.6.2' - //功能库(Zxing扫描与生成二维码条形码) - implementation 'com.github.tamsiree.RxTool:RxFeature:2.6.2' - //ArcGis For Android工具库(API:100.1以上版本) - implementation 'com.github.tamsiree.RxTool:RxArcGisKit:2.6.2' //友盟 // 下面各SDK根据宿主App是否使用相关业务按需引入。 // 友盟统计SDK @@ -142,21 +115,10 @@ dependencies { //xui implementation 'com.github.xuexiangjys:XUI:1.1.8' - implementation "io.reactivex.rxjava3:rxjava:3.1.4" - implementation "io.reactivex.rxjava3:rxandroid:3.0.0" -// implementation "com.squareup.retrofit2:adapter-rxjava3:2.9.0" - - implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.2.9' - -// implementation 'io.github.lucksiege:pictureselector:v3.0.9' - implementation 'com.github.getActivity:XToast:8.2' - implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.6' implementation 'com.github.tbruyelle:rxpermissions:0.12' - implementation 'com.amap.api:3dmap:8.0.0' - implementation 'com.amap.api:location:5.4.0' - implementation 'com.amap.api:search:7.9.0' + implementation project(path: ':mylibrary') } \ No newline at end of file diff --git a/app/release/dhhy-cargo-0718_16-12-3.0.7.apk b/app/release/dhhy-cargo-0830_17-18-3.0.7.apk similarity index 85% rename from app/release/dhhy-cargo-0718_16-12-3.0.7.apk rename to app/release/dhhy-cargo-0830_17-18-3.0.7.apk index ac67230..d6dbd92 100644 Binary files a/app/release/dhhy-cargo-0718_16-12-3.0.7.apk and b/app/release/dhhy-cargo-0830_17-18-3.0.7.apk differ diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json index f131b02..767cfc5 100644 --- a/app/release/output-metadata.json +++ b/app/release/output-metadata.json @@ -12,7 +12,7 @@ "filters": [], "versionCode": 27, "versionName": "3.0.7", - "outputFile": "dhhy-cargo-0718_16-12-3.0.7.apk" + "outputFile": "dhhy-cargo-0830_17-18-3.0.7.apk" } ] } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_choice_address.xml b/app/src/main/res/layout/activity_choice_address.xml index 5e62508..26a3082 100644 --- a/app/src/main/res/layout/activity_choice_address.xml +++ b/app/src/main/res/layout/activity_choice_address.xml @@ -211,7 +211,7 @@ android:layout_width="@dimen/dp_22" android:layout_height="@dimen/dp_22" android:layout_marginLeft="@dimen/dp_4" - android:background="@drawable/selector_location"> + > @color/color_theme #C9C9C9 #999999 + #FF0000 \ No newline at end of file diff --git a/build.gradle b/build.gradle index a7ed02b..19c6166 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,8 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. +apply from: "compile.gradle" + buildscript { + ext.kotlin_version = "1.5.0" repositories { google() // jcenter() // 这个 @@ -18,6 +21,7 @@ buildscript { } dependencies { classpath "com.android.tools.build:gradle:4.2.0" + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } diff --git a/compile.gradle b/compile.gradle new file mode 100644 index 0000000..047a488 --- /dev/null +++ b/compile.gradle @@ -0,0 +1,92 @@ +def SupportVersion = '28.0.0' +def ButterKnifeVersion = '10.0.0' +def CrashActivityVersion = '2.2.0' +def StatusBarVersion = '2.3.3' +def GsonVersion = '2.8.6' +def PhotoPickerVersion = 'v2.6.1' +//def PhotoPickerVersion = 'v2.7.2' +def GlideVersion = '4.12.0' +def AgentWebVersion = 'v4.1.9-androidx' +def NiceDialogVersion = '1.1.9' +def AndPermissionVersion = '2.0.3' +def BannerVersion = '1.4.10' +def SmartRefreshLayoutVersion = '1.1.0-alpha-12' +def MultideXVersion = '2.0.1' +def RXJavaVersion = '3.0.12' +def RXAndroidVersion = '3.0.0' +def RetrofitVersion = '2.9.0' +def OkHttpVersion = '4.9.1' +def AutoSizeVersion = '1.1.2' +def FlycoTabLayoutVersion = '2.1.2@aar' +def ZxingVersion = '1.3.8' +def BaseRecyclerViewAdapterHelper = '3.0.6' +def MagicIndicator = '1.7.0' +def PickerView = '4.1.9' +def NiceSpinner = '1.4.4' +def Countdownview = '2.1.6' +def Xpopup = '2.2.8' +def CheckVersionLib = '2.4.1_androidx' +def GooglePlayVersion = '15.0.1' +def Streamsupport = '1.7.3' +def NewbieGuideVersion = 'v2.4.0' +def CountdownviewVersion = '2.1.6' +def JpushVersion = '3.1.8' +def JcoreVersion = '1.2.7' +def BuglyVersion = 'latest.release' +project.ext { + android = [ + compileSdkVersion: 30, + buildToolsVersion: "30.0.3", + applicationId : "com.dahe.examine", + minSdkVersion : 21, + targetSdkVersion : 30, + versionCode : 5, + versionName : "1.0.5", + ] + dependencies = [ + "appcompat-v7" : "com.android.support:appcompat-v7:${SupportVersion}", + "support-v4" : "com.android.support:support-v4:${SupportVersion}", + "support-design" : "com.android.support:design:${SupportVersion}", + "recyclerview" : "com.android.support:recyclerview-v7:${SupportVersion}", + "butterknife" : "com.jakewharton:butterknife:${ButterKnifeVersion}", + "butterknife-compiler" : "com.jakewharton:butterknife-compiler:${ButterKnifeVersion}", + "customactivityoncrash": "cat.ereza:customactivityoncrash:${CrashActivityVersion}", + "gson" : "com.google.code.gson:gson:${GsonVersion}", + "PhotoPicker" : "com.github.LuckSiege.PictureSelector:picture_library:${PhotoPickerVersion}", + "PhotoPicker" : "io.github.lucksiege:pictureselector:${PhotoPickerVersion}", + "agentweb" : "com.github.Justson.AgentWeb:agentweb-core:${AgentWebVersion}", + "statusbaruitl" : "com.github.niorgai:StatusBarCompat:${StatusBarVersion}", + "glide" : "com.github.bumptech.glide:glide:${GlideVersion}", + "glide-compiler" : "com.github.bumptech.glide:compiler:${GlideVersion}", + "glide-okhttps" : "com.github.bumptech.glide:okhttp3-integration:${GlideVersion}", + "NiceDialog" : "com.github.Othershe:NiceDialog:${NiceDialogVersion}", + "Banner" : "com.youth.banner:banner:${BannerVersion}", + "RefreshLayout" : "com.scwang.smartrefresh:SmartRefreshLayout:${SmartRefreshLayoutVersion}", + "Multidex" : "androidx.multidex:multidex:${MultideXVersion}", + "rxjava" : "io.reactivex.rxjava3:rxjava:${RXJavaVersion}", + "rxandroid" : "io.reactivex.rxjava3:rxandroid:${RXAndroidVersion}", + "retrofit" : "com.squareup.retrofit2:retrofit:${RetrofitVersion}", + "converter-gson" : "com.squareup.retrofit2:converter-gson:${RetrofitVersion}", + "adapter-rxjava2" : "com.squareup.retrofit2:adapter-rxjava3:${RetrofitVersion}", + "okhttp" : "com.squareup.okhttp3:okhttp:${OkHttpVersion}", + "logging-interceptor" : "com.squareup.okhttp3:logging-interceptor:${OkHttpVersion}", + "AutoSize" : "me.jessyan:autosize:${AutoSizeVersion}", + "FlycoTabLayout" : "com.flyco.tablayout:FlycoTabLayout_Lib:${FlycoTabLayoutVersion}", + "AndPermission" : "com.yanzhenjie:permission:${AndPermissionVersion}", +// "Zxing" : "cn.bingoogolapple:bga-qrcode-zxing:${ZxingVersion}", + "Zxing" : "com.github.bingoogolapple.BGAQRCode-Android:zxing:${ZxingVersion}", + "BaseRecyclerViewAdapterHelper" :"com.github.CymChad:BaseRecyclerViewAdapterHelper:${BaseRecyclerViewAdapterHelper}", + "MagicIndicator" :"com.github.hackware1993:MagicIndicator:${MagicIndicator}", + "NiceSpinner" :"com.github.arcadefire:nice-spinner:${NiceSpinner}", + "Countdownview" :"com.github.iwgang:countdownview:${Countdownview}", + "Xpopup" :"com.lxj:xpopup:${Xpopup}", + "CheckVersionLib" :"com.github.AlexLiuSheng:CheckVersionLib:${CheckVersionLib}", + "Bugly" :"com.tencent.bugly:crashreport:${BuglyVersion}", + "Streamsupport" :"net.sourceforge.streamsupport:streamsupport:${Streamsupport}", + "PickerView" :"com.contrarywind:Android-PickerView:${PickerView}", + "Permissionx" :'com.guolindev.permissionx:permissionx:1.6.4', + "3Dmap" :'com.amap.api:3dmap:8.0.0', + "Location" :'com.amap.api:location:5.4.0', + "Search" :'com.amap.api:search:7.9.0' + ] +} diff --git a/mylibrary/.gitignore b/mylibrary/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/mylibrary/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/mylibrary/build.gradle b/mylibrary/build.gradle new file mode 100644 index 0000000..10706c3 --- /dev/null +++ b/mylibrary/build.gradle @@ -0,0 +1,78 @@ +plugins { + id 'com.android.library' + id 'kotlin-android' +// id 'com.jakewharton.butterknife' +} + +android { + compileSdkVersion 30 + buildToolsVersion "30.0.3" + + defaultConfig { + minSdkVersion 21 + targetSdkVersion 30 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles "consumer-rules.pro" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } +} + +dependencies { + + implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" + implementation 'androidx.core:core-ktx:1.3.1' + implementation 'androidx.appcompat:appcompat:1.2.0' + implementation 'com.google.android.material:material:1.2.1' + implementation 'androidx.constraintlayout:constraintlayout:2.0.1' + testImplementation 'junit:junit:4.+' + androidTestImplementation 'androidx.test.ext:junit:1.1.2' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' + + api rootProject.ext.dependencies["gson"] + api rootProject.ext.dependencies["glide"] + annotationProcessor rootProject.ext.dependencies["glide-compiler"] + api rootProject.ext.dependencies["agentweb"] +// api rootProject.ext.dependencies["Banner"] + api rootProject.ext.dependencies["RefreshLayout"] + api rootProject.ext.dependencies["rxjava"] + api rootProject.ext.dependencies["rxandroid"] + api rootProject.ext.dependencies["retrofit"] + api rootProject.ext.dependencies["converter-gson"] + api rootProject.ext.dependencies["adapter-rxjava2"] + api rootProject.ext.dependencies["okhttp"] + api rootProject.ext.dependencies["logging-interceptor"] + api rootProject.ext.dependencies["recyclerview"] +// api rootProject.ext.dependencies["AutoSize"] + api rootProject.ext.dependencies["statusbaruitl"] + api rootProject.ext.dependencies["BaseRecyclerViewAdapterHelper"] + api rootProject.ext.dependencies["PhotoPicker"] +// api rootProject.ext.dependencies["PickerView"] + api rootProject.ext.dependencies["Xpopup"] +// api rootProject.ext.dependencies["Countdownview"] + api rootProject.ext.dependencies["Multidex"] + api rootProject.ext.dependencies["NiceDialog"] + api rootProject.ext.dependencies["glide-okhttps"] +// api rootProject.ext.dependencies["Permissionx"] + api rootProject.ext.dependencies["3Dmap"] + api rootProject.ext.dependencies["Location"] + api rootProject.ext.dependencies["Search"] + + + +} diff --git a/mylibrary/consumer-rules.pro b/mylibrary/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/mylibrary/proguard-rules.pro b/mylibrary/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/mylibrary/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/mylibrary/src/androidTest/java/com/dahe/mylibrary/ExampleInstrumentedTest.kt b/mylibrary/src/androidTest/java/com/dahe/mylibrary/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..c51c36c --- /dev/null +++ b/mylibrary/src/androidTest/java/com/dahe/mylibrary/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package com.dahe.mylibrary + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.dahe.mylibrary.test", appContext.packageName) + } +} \ No newline at end of file diff --git a/mylibrary/src/main/AndroidManifest.xml b/mylibrary/src/main/AndroidManifest.xml new file mode 100644 index 0000000..2f43892 --- /dev/null +++ b/mylibrary/src/main/AndroidManifest.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/CommonBaseLibrary.java b/mylibrary/src/main/java/com/dahe/mylibrary/CommonBaseLibrary.java new file mode 100644 index 0000000..8354e02 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/CommonBaseLibrary.java @@ -0,0 +1,137 @@ +package com.dahe.mylibrary; + +import android.app.Activity; +import android.app.Application; +import android.content.Context; +import android.os.Bundle; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.scwang.smartrefresh.layout.SmartRefreshLayout; +import com.scwang.smartrefresh.layout.api.DefaultRefreshFooterCreator; +import com.scwang.smartrefresh.layout.api.DefaultRefreshHeaderCreator; +import com.scwang.smartrefresh.layout.api.RefreshFooter; +import com.scwang.smartrefresh.layout.api.RefreshHeader; +import com.scwang.smartrefresh.layout.api.RefreshLayout; +import com.scwang.smartrefresh.layout.footer.ClassicsFooter; +import com.scwang.smartrefresh.layout.header.ClassicsHeader; + +import java.lang.ref.WeakReference; +import java.util.LinkedList; +import java.util.List; + +import retrofit2.Retrofit; +import retrofit2.adapter.rxjava3.RxJava3CallAdapterFactory; +import retrofit2.converter.gson.GsonConverterFactory; + +/** + * Created by Administrator on 2018/7/15 0015. + */ + +public class CommonBaseLibrary { + public volatile static CommonBaseLibrary mInstance = null; + private static Application mApplication = null; + public static WeakReference topActivity; + public static List activityList = new LinkedList<>(); + private static Retrofit mRetrofit; + + static { + SmartRefreshLayout.setDefaultRefreshHeaderCreator(new DefaultRefreshHeaderCreator() { + @Override + public RefreshHeader createRefreshHeader(Context context, RefreshLayout layout) { + return new ClassicsHeader(context); + } + }); + SmartRefreshLayout.setDefaultRefreshFooterCreator(new DefaultRefreshFooterCreator() { + @Override + public RefreshFooter createRefreshFooter(Context context, RefreshLayout layout) { + return new ClassicsFooter(context); + } + }); + } + + public CommonBaseLibrary() { + } + + public static CommonBaseLibrary getInstance() { + if (null == mInstance) { + synchronized (CommonBaseLibrary.class) { + if (null == mInstance) { + mInstance = new CommonBaseLibrary(); + } + } + } + return mInstance; + } + + public CommonBaseLibrary init(Application application, String baseUrl) { + mApplication = application; + application.registerActivityLifecycleCallbacks(mCallbacks); + Gson gson = new GsonBuilder().setDateFormat("yyy-MM-dd HH:mm:ss").create(); + mRetrofit = new Retrofit.Builder() + .baseUrl(baseUrl) + .addConverterFactory(GsonConverterFactory.create(gson)) + .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) + .build(); + +// .addConverterFactory(GsonConverterFactory.create(gson)) + return this; + } + + + + public static Application getApplication() { + return mApplication; + } + + public static Retrofit getRetrofit() { + if (null == mRetrofit) + throw new NullPointerException("please call CommonBaseLibrary.getInstance().init() first in application!"); + return mRetrofit; + + } + + private static Application.ActivityLifecycleCallbacks mCallbacks = new Application.ActivityLifecycleCallbacks() { + @Override + public void onActivityCreated(Activity activity, Bundle bundle) { + activityList.add(activity); + setTopActivityWeakRef(activity); + } + + @Override + public void onActivityStarted(Activity activity) { + setTopActivityWeakRef(activity); + } + + @Override + public void onActivityResumed(Activity activity) { + setTopActivityWeakRef(activity); + } + + @Override + public void onActivityPaused(Activity activity) { + + } + + @Override + public void onActivityStopped(Activity activity) { + + } + + @Override + public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { + + } + + @Override + public void onActivityDestroyed(Activity activity) { + activityList.remove(activity); + } + }; + + private static void setTopActivityWeakRef(Activity activity) { + if (topActivity == null || !activity.equals(topActivity.get())) { + topActivity = new WeakReference<>(activity); + } + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/adapter/CarAdapter.java b/mylibrary/src/main/java/com/dahe/mylibrary/adapter/CarAdapter.java new file mode 100644 index 0000000..0d2df13 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/adapter/CarAdapter.java @@ -0,0 +1,31 @@ +package com.dahe.mylibrary.adapter; + +import android.widget.CheckBox; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.viewholder.BaseViewHolder; +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.bean.CarBean; +import com.dahe.mylibrary.bean.NodeBean; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class CarAdapter extends BaseQuickAdapter { + + public CarAdapter(int layoutResId, @Nullable List data) { + super(R.layout.item_car_select, data); + } + + @Override + protected void convert(@NotNull BaseViewHolder helper, CarBean item) { + helper.setText(R.id.tv_title, item.getVehicle()) + .setText(R.id.tv_lxr, "司机信息:"+item.getDriverName() + " " + item.getDriverPhone()) + .setText(R.id.tv_zz, "载重(Kg):"+item.getApprovedLoad()) + .setText(R.id.tv_ckg, "长宽高(毫米):"+item.getOutlineLong()+"*"+item.getOutlineWide()+"*"+item.getOutlineHigh()); + CheckBox cb = helper.getView(R.id.cb); + cb.setChecked(item.isSelect()); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/adapter/CenterSimAdapter.java b/mylibrary/src/main/java/com/dahe/mylibrary/adapter/CenterSimAdapter.java new file mode 100644 index 0000000..27f52e7 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/adapter/CenterSimAdapter.java @@ -0,0 +1,41 @@ +package com.dahe.mylibrary.adapter; + +import android.widget.TextView; + +import androidx.annotation.Nullable; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.viewholder.BaseViewHolder; +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.bean.StateBean; + +import java.util.List; + +public class CenterSimAdapter extends BaseQuickAdapter { + private StateBean selectString=null; + + + public CenterSimAdapter(int layoutResId, @Nullable List data, StateBean selectString) { + super(R.layout.item_select, data); + this.selectString = selectString; + } + + @Override + protected void convert(BaseViewHolder helper, StateBean item) { + helper.setText(R.id.tv_content,item.getDictLabel()); + TextView tv = helper.getView(R.id.tv_content); + if (selectString!=null&&item.getDictValue()!=null){ + if (item.getDictValue().equals(selectString.getDictValue())){ + tv.setSelected(true); + }else{ + tv.setSelected(false); + } + } + + + } + + public void setSelect(StateBean selectString){ + this.selectString = selectString; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/adapter/GridImageAdapter.java b/mylibrary/src/main/java/com/dahe/mylibrary/adapter/GridImageAdapter.java new file mode 100644 index 0000000..d0fdb18 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/adapter/GridImageAdapter.java @@ -0,0 +1,272 @@ +package com.dahe.mylibrary.adapter; + +import android.content.Context; +import android.net.Uri; +import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; + +import androidx.recyclerview.widget.RecyclerView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.load.resource.bitmap.CenterCrop; +import com.bumptech.glide.load.resource.bitmap.RoundedCorners; +import com.bumptech.glide.request.RequestOptions; +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.callback.OnItemLongClickListener; +import com.luck.picture.lib.config.PictureMimeType; +import com.luck.picture.lib.entity.LocalMedia; +import com.luck.picture.lib.listener.OnItemClickListener; +import com.luck.picture.lib.tools.DateUtils; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + + +/** + * @author:luck + * @date:2016-7-27 23:02 + * @describe:GridImageAdapter + */ +public class GridImageAdapter extends + RecyclerView.Adapter { + public static final String TAG = "PictureSelector"; + public static final int TYPE_CAMERA = 1; + public static final int TYPE_PICTURE = 2; + public boolean IS_ONLY_SHOW = false; + private final Context ctx; + private LayoutInflater mInflater; + private List list = new ArrayList<>(); + private int selectMax = 9; + /** + * 点击添加图片跳转 + */ + private onAddPicClickListener mOnAddPicClickListener; + + public interface onAddPicClickListener { + void onAddPicClick(); + void onDelPicClick(int postion,LocalMedia localMedia); + } + + /** + * 删除 + */ + public void delete(int position) { + try { + + if (position != RecyclerView.NO_POSITION && list.size() > position) { + list.remove(position); + notifyItemRemoved(position); + notifyItemRangeChanged(position, list.size()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public GridImageAdapter(Context context, onAddPicClickListener mOnAddPicClickListener) { + this.ctx = context; + this.mInflater = LayoutInflater.from(context); + this.mOnAddPicClickListener = mOnAddPicClickListener; + } + + public void setSelectMax(int selectMax) { + this.selectMax = selectMax; + } + + public void setList(List list) { + this.list = list; + } + + public void setListNotif(List list) { + if (null!=list&&list.size()>0){ + this.list = list; + notifyDataSetChanged(); + } + } + + public List getData() { + return list == null ? new ArrayList<>() : list; + } + + public void remove(int position) { + if (list != null && position < list.size()) { + list.remove(position); + } + } + + public static class ViewHolder extends RecyclerView.ViewHolder { + + ImageView mImg; + ImageView mIvDel; + TextView tvDuration; + + public ViewHolder(View view) { + super(view); + mImg = view.findViewById(R.id.fiv); + mIvDel = view.findViewById(R.id.iv_del); + tvDuration = view.findViewById(R.id.tv_duration); + } + } + + @Override + public int getItemCount() { + if (list.size() < selectMax&&!IS_ONLY_SHOW) { + return list.size() + 1; + } else { + return list.size(); + } + } + + @Override + public int getItemViewType(int position) { + if (isShowAddItem(position)) { + return TYPE_CAMERA; + } else { + return TYPE_PICTURE; + } + } + + /** + * 创建ViewHolder + */ + @Override + public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { + View view = mInflater.inflate(R.layout.gv_filter_image, viewGroup, false); + return new ViewHolder(view); + } + + private boolean isShowAddItem(int position) { + if (IS_ONLY_SHOW){ + return false; + } + int size = list.size(); + return position == size; + } + + public void setIsOnlyShow(boolean b){ + this.IS_ONLY_SHOW = b; + } + + /** + * 设置值 + */ + @Override + public void onBindViewHolder(final ViewHolder viewHolder, final int position) { + //少于8张,显示继续添加的图标 + if (getItemViewType(position) == TYPE_CAMERA) { + viewHolder.mImg.setImageResource(R.drawable.id_select_z); +// viewHolder.mImg.setImageResource(R.drawable.ic_add_image); + viewHolder.mImg.setOnClickListener(v -> mOnAddPicClickListener.onAddPicClick()); + viewHolder.mIvDel.setVisibility(View.INVISIBLE); + } else { + viewHolder.mIvDel.setVisibility(IS_ONLY_SHOW?View.GONE:View.VISIBLE); + viewHolder.mIvDel.setOnClickListener(view -> { + int index = viewHolder.getAbsoluteAdapterPosition(); + + // 这里有时会返回-1造成数据下标越界,具体可参考getAdapterPosition()源码, + // 通过源码分析应该是bindViewHolder()暂未绘制完成导致,知道原因的也可联系我~感谢 + if (index != RecyclerView.NO_POSITION && list.size() > index) { + mOnAddPicClickListener.onDelPicClick(index, list.get(index)); +// list.remove(index); +// notifyItemRemoved(index); +// notifyItemRangeChanged(index, list.size()); + } + }); + LocalMedia media = list.get(position); + if (media == null + || TextUtils.isEmpty(media.getPath())) { + return; + } + int chooseModel = media.getChooseModel(); + String path; + if (media.isCut() && !media.isCompressed()) { + // 裁剪过 + path = media.getCutPath(); + } else if (media.isCompressed() || (media.isCut() && media.isCompressed())) { + // 压缩过,或者裁剪同时压缩过,以最终压缩过图片为准 + path = media.getCompressPath(); + } else { + // 原图 + path = media.getPath(); + } + + Log.i(TAG, "原图地址::" + media.getPath()); + + if (media.isCut()) { + Log.i(TAG, "裁剪地址::" + media.getCutPath()); + } + if (media.isCompressed()) { + Log.i(TAG, "压缩地址::" + media.getCompressPath()); + Log.i(TAG, "压缩后文件大小::" + new File(media.getCompressPath()).length() / 1024 + "k"); + } + if (!TextUtils.isEmpty(media.getAndroidQToPath())) { + Log.i(TAG, "Android Q特有地址::" + media.getAndroidQToPath()); + } + if (media.isOriginal()) { + Log.i(TAG, "是否开启原图功能::" + true); + Log.i(TAG, "开启原图功能后地址::" + media.getOriginalPath()); + } + + long duration = media.getDuration(); + viewHolder.tvDuration.setVisibility(PictureMimeType.isHasVideo(media.getMimeType()) + ? View.VISIBLE : View.GONE); + if (chooseModel == PictureMimeType.ofAudio()) { + viewHolder.tvDuration.setVisibility(View.VISIBLE); + viewHolder.tvDuration.setCompoundDrawablesRelativeWithIntrinsicBounds + (R.drawable.picture_icon_audio, 0, 0, 0); + + } else { + viewHolder.tvDuration.setCompoundDrawablesRelativeWithIntrinsicBounds + (R.drawable.picture_icon_video, 0, 0, 0); + } + viewHolder.tvDuration.setText(DateUtils.formatDurationTime(duration)); + if (chooseModel == PictureMimeType.ofAudio()) { + viewHolder.mImg.setImageResource(R.drawable.picture_audio_placeholder); + } else { + RequestOptions requestOptions = RequestOptions.fitCenterTransform().transform(new CenterCrop(), new RoundedCorners(5)); + Glide.with(ctx) + .load(PictureMimeType.isContent(path) && !media.isCut() && !media.isCompressed() ? Uri.parse(path) + : path) + .centerCrop() + .apply(requestOptions)//圆角半径 + .placeholder(R.drawable.id_select_loading) + .diskCacheStrategy(DiskCacheStrategy.ALL) + .into(viewHolder.mImg); + } + //itemView 的点击事件 + if (mItemClickListener != null) { + viewHolder.itemView.setOnClickListener(v -> { + int adapterPosition = viewHolder.getAdapterPosition(); + mItemClickListener.onItemClick(v, adapterPosition); + }); + } + + if (mItemLongClickListener != null) { + viewHolder.itemView.setOnLongClickListener(v -> { + int adapterPosition = viewHolder.getAdapterPosition(); + mItemLongClickListener.onItemLongClick(viewHolder, adapterPosition, v); + return true; + }); + } + } + } + + private OnItemClickListener mItemClickListener; + + public void setOnItemClickListener(OnItemClickListener l) { + this.mItemClickListener = l; + } + + private OnItemLongClickListener mItemLongClickListener; + + public void setItemLongClickListener(OnItemLongClickListener l) { + this.mItemLongClickListener = l; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/adapter/NodeAdapter.java b/mylibrary/src/main/java/com/dahe/mylibrary/adapter/NodeAdapter.java new file mode 100644 index 0000000..b4da2e0 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/adapter/NodeAdapter.java @@ -0,0 +1,30 @@ +package com.dahe.mylibrary.adapter; + +import android.widget.CheckBox; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.viewholder.BaseViewHolder; +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.bean.NodeBean; +import com.dahe.mylibrary.utils.StringUtils; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class NodeAdapter extends BaseQuickAdapter { + + public NodeAdapter(int layoutResId, @Nullable List data) { + super(R.layout.item_node_select, data); + } + + @Override + protected void convert(@NotNull BaseViewHolder helper, NodeBean item) { + helper.setText(R.id.tv_title, item.getNode()) + .setText(R.id.tv_lxr, StringUtils.isEmpty(item.getDocking())?"":item.getDocking() + " " + (StringUtils.isEmpty(item.getDockingPhone())?"":item.getDockingPhone())) + .setText(R.id.tv_addres, item.getFreighter()); + CheckBox cb = helper.getView(R.id.cb); + cb.setChecked("1".equals(item.isSelect())?true:false); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/adapter/SelectDicAdapter.java b/mylibrary/src/main/java/com/dahe/mylibrary/adapter/SelectDicAdapter.java new file mode 100644 index 0000000..06159d9 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/adapter/SelectDicAdapter.java @@ -0,0 +1,38 @@ +package com.dahe.mylibrary.adapter; + +import androidx.annotation.Nullable; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.viewholder.BaseViewHolder; +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.bean.DictBean; +import com.dahe.mylibrary.bean.StateBean; + +import java.util.List; + + +public class SelectDicAdapter extends BaseQuickAdapter { + private int selectPos = -1; + + + public SelectDicAdapter(int layoutResId, @Nullable List data, int selectPos) { + super(R.layout.item_dic_select, data); + this.selectPos = selectPos; + } + + @Override + protected void convert(BaseViewHolder helper, StateBean item) { + helper.setText(R.id.tv_content,item.getDictLabel()); +// TextView tv = helper.getView(R.id.tv_content); +// if (item.equals(selectString)){ +// tv.setSelected(true); +// }else{ +// tv.setSelected(false); +// } + + } + + public void setSelect(int selectString){ + this.selectPos = selectString; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/base/BaseActivity.java b/mylibrary/src/main/java/com/dahe/mylibrary/base/BaseActivity.java new file mode 100644 index 0000000..65a2fc1 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/base/BaseActivity.java @@ -0,0 +1,250 @@ +package com.dahe.mylibrary.base; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.os.Bundle; +import android.text.TextUtils; +import android.view.View; +import android.view.ViewGroup; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.annotation.ColorRes; +import androidx.annotation.DrawableRes; +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import androidx.core.content.ContextCompat; + +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.callback.RefreshCallBack; +import com.dahe.mylibrary.utils.BarUtils; +import com.dahe.mylibrary.utils.ConvertUtils; +import com.dahe.mylibrary.utils.StatusBar; +import com.dahe.mylibrary.utils.ToastUtils; +import com.scwang.smartrefresh.layout.SmartRefreshLayout; +import com.scwang.smartrefresh.layout.api.RefreshLayout; +import com.scwang.smartrefresh.layout.constant.RefreshState; +import com.scwang.smartrefresh.layout.listener.OnRefreshLoadMoreListener; + +import qiu.niorgai.StatusBarCompat; + + +public abstract class BaseActivity extends AppCompatActivity { + protected Context mContext; + protected final int DEFAULT_STATUS_BAR_ALPHA = 0; + private static final String TAG = "BaseActivity"; + protected Toolbar mToolbar; + protected int mRefreshPage = 1; + protected int mRefreshCount = 15; + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(getLayout()); + mContext = this; + setStatusBarColor(R.color.colorPrimaryDark); + initView(savedInstanceState); + initDate(); + } + + /** + * 标题栏的颜色 文字白色 + */ + public void setStatusBarCancelLightColor() { + StatusBar.cancelLightStatusBar(this); + } + + + /** + * 设置沉浸式标题栏 标题栏的颜色 + */ + public void setStatusBarColor(int color) { + StatusBarCompat.setStatusBarColor(this, ContextCompat.getColor(mContext, color), DEFAULT_STATUS_BAR_ALPHA); + StatusBar.changeToLightStatusBar(this); //黑色 下边白色 +// StatusBar.cancelLightStatusBar(this); + } + + /** + * 设置沉浸式标题栏 标题栏的颜色 + */ + public void setStatusBarColor() { +// StatusBarCompat.setStatusBarColor(this, ContextCompat.getColor(mContext, color), DEFAULT_STATUS_BAR_ALPHA); +// StatusBar.changeToLightStatusBar(this); //黑色 下边白色 + StatusBar.cancelLightStatusBar(this); + } + + /** + * 设置沉浸式标题栏 里面是Fragment + */ + public void setStatusBarColorInFragment() { + StatusBarCompat.translucentStatusBar(this); + } + + /** + * 设置透明沉浸式标题栏 + */ + public void setStatusBarColorToLight() { + StatusBar.translucentStatusBar(this, false); + StatusBar.changeToLightStatusBar(this); + } + + /** + * 设置标题 + */ + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + protected void setTitleBar(String title, View.OnClickListener listener) { + mToolbar = (Toolbar) findViewById(R.id.common_toolbar); + if (!TextUtils.isEmpty(title)) + ((TextView) findViewById(R.id.common_toolBar_title)).setText(title); + mToolbar.setNavigationIcon(R.drawable.left); + mToolbar.setNavigationOnClickListener(listener); + } + + /** + * 设置标题 + */ + + protected void setTitleBar(String title) { + mToolbar = (Toolbar) findViewById(R.id.common_toolbar); + if (!TextUtils.isEmpty(title)) + ((TextView) findViewById(R.id.common_toolBar_title)).setText(title); + } + + /** + * 显示右边标题 + * + * @param title + * @param listener + * @param isVisible + * @param right + */ + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + protected void setTitleBar(String title, View.OnClickListener listener, boolean isVisible, String right, View.OnClickListener rightListener) { + mToolbar = (Toolbar) findViewById(R.id.common_toolbar); + if (!TextUtils.isEmpty(title)) + ((TextView) findViewById(R.id.common_toolBar_title)).setText(title); + TextView mTextRight = (TextView) findViewById(R.id.common_toolBar_text_right); + if (isVisible) { + mTextRight.setVisibility(View.VISIBLE); + mTextRight.setText(right); + mTextRight.setOnClickListener(rightListener); + } + mToolbar.setNavigationIcon(R.drawable.left); + mToolbar.setNavigationOnClickListener(listener); + } + + /** + * 设置距离顶部距离 + */ + protected void setStatusHeightParams(View llContent) { + RelativeLayout.LayoutParams closeLayoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); + closeLayoutParams.topMargin = ConvertUtils.dp2px(8) + BarUtils.getStatusBarHeight(); +// closeLayoutParams.topMargin = BarUtils.getStatusBarHeight(); + llContent.setLayoutParams(closeLayoutParams); + } + + protected abstract int getLayout(); + + protected abstract void initView(Bundle savedInstanceState); + + protected abstract void initDate(); + + protected void showToast(Object message) { + ToastUtils.showToast(this, message instanceof String ? message + "" : getResources().getString((int) message)); + } + + protected void canCelToast(){ + ToastUtils.cancelToast(); + } + + +// protected void showToast(Object message,int time) { +// ToastUtils.showToast(this, message instanceof String ? message + "" : getResources().getString((int) message),time); +// } + + @Override + protected void onDestroy() { + super.onDestroy(); + } + + + /** + * 设置刷新控件 + * + * @param refreshLayout + * @param callBack 访问网络回调 + */ + protected void setRefresh(final SmartRefreshLayout refreshLayout, final RefreshCallBack callBack) { + refreshLayout.setEnableOverScrollDrag(true) + .setOnRefreshLoadMoreListener(new OnRefreshLoadMoreListener() { + @Override + public void onLoadMore(@NonNull RefreshLayout refreshLayout) { + mRefreshPage++; + callBack.getRefreshDate(2, mRefreshPage, mRefreshCount); + } + + @Override + public void onRefresh(@NonNull RefreshLayout refreshLayout) { + mRefreshPage = 1; + callBack.getRefreshDate(1, mRefreshPage, mRefreshCount); + } + }); + } + + /** + * 网络访问完成 刷新控件 + * + * @param refreshLayout + * @param isLoadMore false禁用下拉加载更多 + */ + protected void setFinishRefresh(final SmartRefreshLayout refreshLayout, boolean isLoadMore) { + if (refreshLayout != null && refreshLayout.getState() == RefreshState.Refreshing) + refreshLayout.finishRefresh(); + else if (refreshLayout != null && refreshLayout.getState() == RefreshState.Loading) + refreshLayout.finishLoadMore(); + if (!isLoadMore){ + refreshLayout.finishLoadMore(); //加载完成 + refreshLayout.finishLoadMoreWithNoMoreData(); //全部加载完成,没有数据了调用此方法 + } +// refreshLayout.setEnableLoadMore(isLoadMore); + } + + public void onClick(View view){ + + } + + + /** + * 获取Drawable + * + * @param id + * @return + */ + protected Drawable getDrawableV4(@DrawableRes int id) { + return ContextCompat.getDrawable(this, id); + } + + /** + * 获取Color + * + * @param id + * @return + */ + protected int getColorV4(@ColorRes int id) { + return ContextCompat.getColor(this, id); + } + + @Override + public void onResume() { + super.onResume(); + } + + @Override + public void onPause() { + super.onPause(); + } + + +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/base/BaseFragment.java b/mylibrary/src/main/java/com/dahe/mylibrary/base/BaseFragment.java new file mode 100644 index 0000000..0e67b39 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/base/BaseFragment.java @@ -0,0 +1,321 @@ +package com.dahe.mylibrary.base; + + +import android.content.Context; +import android.os.Bundle; +import android.text.TextUtils; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageButton; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.widget.Toolbar; +import androidx.core.content.ContextCompat; +import androidx.fragment.app.Fragment; + +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.callback.RefreshCallBack; +import com.dahe.mylibrary.utils.StatusBar; +import com.dahe.mylibrary.utils.ToastUtils; +import com.scwang.smartrefresh.layout.SmartRefreshLayout; +import com.scwang.smartrefresh.layout.api.RefreshLayout; +import com.scwang.smartrefresh.layout.constant.RefreshState; +import com.scwang.smartrefresh.layout.listener.OnRefreshLoadMoreListener; + +import qiu.niorgai.StatusBarCompat; + +/** + *

+ * Fragment基类,封装了懒加载的实现 + *

+ * 1、Viewpager + Fragment情况下,fragment的生命周期因Viewpager的缓存机制而失去了具体意义 + * 该抽象类自定义一个新的回调方法,当fragment可见状态改变时会触发的回调方法 + * + * @see #onFragmentVisibleChange(boolean) + * @see #onFragmentFirstVisible() + */ +public abstract class BaseFragment extends Fragment { + private boolean isFragmentVisible; + private boolean isReuseView; + private boolean isFirstVisible; + private boolean isPause; + private View rootView; + private static final String TAG = "BaseFragment"; + protected Context mContext; + protected int mRefreshPage = 1; + protected int mRefreshCount = 20; + protected Toolbar mToolbar; + protected final int DEFAULT_STATUS_BAR_ALPHA = 0; + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + Log.i(TAG, "onViewCreated: " + (rootView == null) + "---getUserVisibleHint()" + getUserVisibleHint() + "---isFirstVisible" + isFirstVisible); + //如果setUserVisibleHint()在rootView创建前调用时,那么 + //就等到rootView创建完后才回调onFragmentVisibleChange(true) + //保证onFragmentVisibleChange()的回调发生在rootView创建完成之后,以便支持ui操作 + if (rootView == null) { + rootView = view; + if (getUserVisibleHint()) { + if (isFirstVisible) { + onFragmentFirstVisible(); + isFirstVisible = false; + } + + onFragmentVisibleChange(isFirstVisible); + isFragmentVisible = true; + } + } + super.onViewCreated(isReuseView && rootView != null ? rootView : view, savedInstanceState); + } + + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + if (getContentViewLayoutID() != 0) { + mContext = getActivity(); + return inflater.inflate(getContentViewLayoutID(), container, false); + } else { + return super.onCreateView(inflater, container, savedInstanceState); + } + } + + + protected abstract int getContentViewLayoutID(); + + + /** + * 标题栏的颜色 文字白色 + */ + public void setStatusBarCancelLightColor() { + StatusBar.cancelLightStatusBar(getActivity()); + } + + /** + * 设置沉浸式标题栏 标题栏的颜色 + */ + public void setStatusBarColor(int color) { + StatusBarCompat.setStatusBarColor(getActivity(), ContextCompat.getColor(mContext, color), DEFAULT_STATUS_BAR_ALPHA); + StatusBar.changeToLightStatusBar(getActivity()); + } + + /** + * 设置沉浸式标题栏 里面是Fragment + */ + public void setStatusBarColorInFragment() { + StatusBarCompat.translucentStatusBar(getActivity()); + } + + public void setStatusBarColorToLight() { + StatusBar.translucentStatusBar(getActivity(), true); + StatusBar.changeToLightStatusBar(getActivity()); + } + + @Override + public void onDestroy() { + initVariable(); + super.onDestroy(); + } + + + protected void showToast(Object message) { + ToastUtils.showToast(mContext, message instanceof String ? message + "" : getResources().getString((int) message)); + } + + /** + * 设置刷新控件 + * + * @param refreshLayout + * @param callBack 访问网络回调 + */ + protected void setRefresh(final SmartRefreshLayout refreshLayout, final RefreshCallBack callBack) { + refreshLayout.setEnableOverScrollDrag(true) + .setOnRefreshLoadMoreListener(new OnRefreshLoadMoreListener() { + @Override + public void onLoadMore(@NonNull RefreshLayout refreshLayout) { + mRefreshPage++; + callBack.getRefreshDate(2, mRefreshPage, mRefreshCount); + } + + @Override + public void onRefresh(@NonNull RefreshLayout refreshLayout) { + mRefreshPage = 1; + callBack.getRefreshDate(1, mRefreshPage, mRefreshCount); + } + }); + } + + /** + * 网络访问完成 刷新控件 + * + * @param refreshLayout + * @param isLoadMore false禁用下拉加载更多 + */ + protected void setFinishRefresh(final SmartRefreshLayout refreshLayout, boolean isLoadMore) { + if (refreshLayout.getState() == RefreshState.Refreshing) + refreshLayout.finishRefresh(); + else if (refreshLayout.getState() == RefreshState.Loading) + refreshLayout.finishLoadMore(); + if (!isLoadMore){ + refreshLayout.finishLoadMore(); //加载完成 + refreshLayout.finishLoadMoreWithNoMoreData(); //全部加载完成,没有数据了调用此方法 + } +// refreshLayout.setEnableLoadMore(isLoadMore); + } + + /** + * 设置标题 + */ + + protected void setTitleBar(String title, View.OnClickListener listener) { + mToolbar = (Toolbar) rootView.findViewById(R.id.common_toolbar); + if (!TextUtils.isEmpty(title)) + ((TextView) rootView.findViewById(R.id.common_toolBar_title)).setText(title); + mToolbar.setNavigationIcon(R.drawable.black_back); + mToolbar.setNavigationOnClickListener(listener); + } + + /** + * 设置标题 + */ + + protected void setTitleBar(String title) { + mToolbar = (Toolbar) rootView.findViewById(R.id.common_toolbar); + if (!TextUtils.isEmpty(title)) + ((TextView) rootView.findViewById(R.id.common_toolBar_title)).setText(title); + } + + /** + * 设置标题 + */ + + protected void setTitleBar(String title, boolean isRight, View.OnClickListener listener) { + mToolbar = (Toolbar) rootView.findViewById(R.id.common_toolbar); + if (!TextUtils.isEmpty(title)) { + ((TextView) rootView.findViewById(R.id.common_toolBar_title)).setText(title); + ((RelativeLayout) rootView.findViewById(R.id.rlMessage)).setVisibility(isRight ? View.VISIBLE : View.GONE); + (rootView.findViewById(R.id.rlMessage)).setOnClickListener(listener); + } + } + + /** + * 设置标题 + */ + + protected void setTitleBar(String title, boolean isRight,String message, View.OnClickListener listener) { + mToolbar = (Toolbar) rootView.findViewById(R.id.common_toolbar); + if (!TextUtils.isEmpty(title)) { + ((TextView) rootView.findViewById(R.id.common_toolBar_title)).setText(title); + ((RelativeLayout) rootView.findViewById(R.id.rlMessage)).setVisibility(isRight ? View.VISIBLE : View.GONE); + ((TextView) rootView.findViewById(R.id.tvMessage)).setText(message); + (rootView.findViewById(R.id.rlMessage)).setOnClickListener(listener); + } + } + + /** + * 设置标题 + */ + + protected void setBadView(boolean isRight) { + if (null != ((TextView) rootView.findViewById(R.id.tvCount))) { + ((TextView) rootView.findViewById(R.id.tvCount)).setVisibility(isRight ? View.VISIBLE : View.GONE); + } + } + + protected void setCount(int count) { + if (count > 100) { + ((TextView) rootView.findViewById(R.id.tvCount)).setText("99··"); + } else { + ((TextView) rootView.findViewById(R.id.tvCount)).setText(count + ""); + } + + } + + + //setUserVisibleHint()在Fragment创建时会先被调用一次,传入isVisibleToUser = false + //如果当前Fragment可见,那么setUserVisibleHint()会再次被调用一次,传入isVisibleToUser = true + //如果Fragment从可见->不可见,那么setUserVisibleHint()也会被调用,传入isVisibleToUser = false + //总结:setUserVisibleHint()除了Fragment的可见状态发生变化时会被回调外,在new Fragment()时也会被回调 + @Override + public void setUserVisibleHint(boolean isVisibleToUser) { + Log.i(TAG, "isFirstVisible: " + isFirstVisible + "--isVisibleToUser" + isVisibleToUser + "--rootView == null" + (rootView == null)); + super.setUserVisibleHint(isVisibleToUser); + //setUserVisibleHint()有可能在fragment的生命周期外被调用 + if (rootView == null) { + return; + } + if (isFirstVisible && isVisibleToUser) { + onFragmentFirstVisible(); + isFirstVisible = false; + isFragmentVisible = true; + return; + } + if (isVisibleToUser) { + onFragmentVisibleChange(true); + isFragmentVisible = true; + return; + } + if (isFragmentVisible) { + isFragmentVisible = false; + onFragmentVisibleChange(false); + } + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + initVariable(); + } + + + private void initVariable() { + isFirstVisible = true; + isFragmentVisible = false; + isPause = false; + rootView = null; + isReuseView = true; + } + + @Override + public void onPause() { + isPause = true; + super.onPause(); + } + + @Override + public void onResume() { + if (isPause && getUserVisibleHint()) + onFragmentVisibleChange(true); + super.onResume(); + } + + /** + * @param isReuse + */ + protected void reuseView(boolean isReuse) { + isReuseView = isReuse; + } + + /** + * 去除setUserVisibleHint()多余的回调场景,保证只有当fragment可见状态发生变化时才回调 + * 回调时机在view创建完后,所以支持ui操作,解决在setUserVisibleHint()里进行ui操作有可能报null异常的问题 + *

+ * 可在该回调方法里进行一些ui显示与隐藏 + * + * @param isVisible true 不可见 -> 可见 + * false 可见 -> 不可见 + */ + protected abstract void onFragmentVisibleChange(boolean isVisible); + + /** + * 在fragment首次可见时回调,可用于加载数据,防止每次进入都重复加载数据 + */ + protected abstract void onFragmentFirstVisible(); + + protected boolean isFragmentVisible() { + return isFragmentVisible; + } +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/bean/CarBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/bean/CarBean.java new file mode 100644 index 0000000..1691809 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/bean/CarBean.java @@ -0,0 +1,100 @@ +package com.dahe.mylibrary.bean; + +import java.io.Serializable; + +public class CarBean implements Serializable { + + +// private String approved_load; +// private String driver_name; +// private String current_load; +// private String car_number; +// private String outline_wide; +// private String outline_long; +// private String driver_phone; +// private Integer car_id; +// private String outline_high; + private boolean isSelect; + + private String vehicle; + private String carId; + private String outlineWide; + private String outlineHigh; + private String outlineLong; + private String approvedLoad; + private String driverName; + private String driverPhone; + + public String getVehicle() { + return vehicle; + } + + public void setVehicle(String vehicle) { + this.vehicle = vehicle; + } + + public String getCarId() { + return carId; + } + + public void setCarId(String carId) { + this.carId = carId; + } + + public String getOutlineWide() { + return outlineWide; + } + + public void setOutlineWide(String outlineWide) { + this.outlineWide = outlineWide; + } + + public String getOutlineHigh() { + return outlineHigh; + } + + public void setOutlineHigh(String outlineHigh) { + this.outlineHigh = outlineHigh; + } + + public String getOutlineLong() { + return outlineLong; + } + + public void setOutlineLong(String outlineLong) { + this.outlineLong = outlineLong; + } + + public String getApprovedLoad() { + return approvedLoad; + } + + public void setApprovedLoad(String approvedLoad) { + this.approvedLoad = approvedLoad; + } + + public String getDriverName() { + return driverName; + } + + public void setDriverName(String driverName) { + this.driverName = driverName; + } + + public String getDriverPhone() { + return driverPhone; + } + + public void setDriverPhone(String driverPhone) { + this.driverPhone = driverPhone; + } + + public boolean isSelect() { + return isSelect; + } + + public void setSelect(boolean select) { + isSelect = select; + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/bean/DictBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/bean/DictBean.java new file mode 100644 index 0000000..f8e9983 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/bean/DictBean.java @@ -0,0 +1,154 @@ +package com.dahe.mylibrary.bean; + +import java.io.Serializable; + +public class DictBean implements Serializable { + + + private String searchValue; + private String createBy; + private String createTime; + private String updateBy; + private String updateTime; + private String remark; + private String dictCode; + private String dictSort; + private String dictLabel; + private String dictValue; + private String dictType; + private String cssClass; + private String listClass; + private String isDefault; + private String status; + + public DictBean() { + + } + + public DictBean(String dictValue, String dictLabel) { + this.dictValue = dictValue; + this.dictLabel = dictLabel; + } + + public String getSearchValue() { + return searchValue; + } + + public void setSearchValue(String searchValue) { + this.searchValue = searchValue; + } + + public String getCreateBy() { + return createBy; + } + + public void setCreateBy(String createBy) { + this.createBy = createBy; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getUpdateBy() { + return updateBy; + } + + public void setUpdateBy(String updateBy) { + this.updateBy = updateBy; + } + + public String getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(String updateTime) { + this.updateTime = updateTime; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + + public String getDictCode() { + return dictCode; + } + + public void setDictCode(String dictCode) { + this.dictCode = dictCode; + } + + public String getDictSort() { + return dictSort; + } + + public void setDictSort(String dictSort) { + this.dictSort = dictSort; + } + + public String getDictLabel() { + return dictLabel; + } + + public void setDictLabel(String dictLabel) { + this.dictLabel = dictLabel; + } + + public String getDictValue() { + return dictValue; + } + + public void setDictValue(String dictValue) { + this.dictValue = dictValue; + } + + public String getDictType() { + return dictType; + } + + public void setDictType(String dictType) { + this.dictType = dictType; + } + + public String getCssClass() { + return cssClass; + } + + public void setCssClass(String cssClass) { + this.cssClass = cssClass; + } + + public String getListClass() { + return listClass; + } + + public void setListClass(String listClass) { + this.listClass = listClass; + } + + public String getIsDefault() { + return isDefault; + } + + public void setIsDefault(String isDefault) { + this.isDefault = isDefault; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/bean/NodeBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/bean/NodeBean.java new file mode 100644 index 0000000..7da5641 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/bean/NodeBean.java @@ -0,0 +1,354 @@ +package com.dahe.mylibrary.bean; + +import java.io.Serializable; + +public class NodeBean implements Serializable { + + + private String searchValue; + private String createBy; + private String createTime; + private String updateBy; + private String updateTime; + private String remark; + private String planId; + private String nodeId; + private String nodeType; + private String orderId; + private String nodeName; + private String address; + private String contacts; + private String contactsPhone; + private String contacts_phone; + private String provinceId; + private String provinceName; + private String cityId; + private String cityName; + private String countyId; + private String countyName; + private String planIndex; + private String remarks; + private String node_name; + private String warehouseId; + private String warehouseName; + private String isSelect; + private String w_child_id; + private String firstNameCode; + + + private String wChildId; + private String waybillId; + private String freighter; + private String freighterId; + private String node; + private String state; + private String isSelectOld; + private String dockingPhone; + private String docking; + + public String getwChildId() { + return wChildId; + } + + public void setwChildId(String wChildId) { + this.wChildId = wChildId; + } + + public String getWaybillId() { + return waybillId; + } + + public void setWaybillId(String waybillId) { + this.waybillId = waybillId; + } + + public String getFreighter() { + return freighter; + } + + public void setFreighter(String freighter) { + this.freighter = freighter; + } + + public String getFreighterId() { + return freighterId; + } + + public void setFreighterId(String freighterId) { + this.freighterId = freighterId; + } + + public String getNode() { + return node; + } + + public void setNode(String node) { + this.node = node; + } + + public String getState() { + return state; + } + + public void setState(String state) { + this.state = state; + } + + public String getIsSelectOld() { + return isSelectOld; + } + + public void setIsSelectOld(String isSelectOld) { + this.isSelectOld = isSelectOld; + } + + public String getDockingPhone() { + return dockingPhone; + } + + public void setDockingPhone(String dockingPhone) { + this.dockingPhone = dockingPhone; + } + + public String getDocking() { + return docking; + } + + public void setDocking(String docking) { + this.docking = docking; + } + + public String getWarehouseId() { + return warehouseId; + } + + public void setWarehouseId(String warehouseId) { + this.warehouseId = warehouseId; + } + + public String getWarehouseName() { + return warehouseName; + } + + public void setWarehouseName(String warehouseName) { + this.warehouseName = warehouseName; + } + + public String getFirstNameCode() { + return firstNameCode; + } + + public void setFirstNameCode(String firstNameCode) { + this.firstNameCode = firstNameCode; + } + + public String getW_child_id() { + return w_child_id; + } + + public void setW_child_id(String w_child_id) { + this.w_child_id = w_child_id; + } + + public String isSelect() { + return isSelect; + } + + public void setSelect(String select) { + isSelect = select; + } + + public String getNode_name() { + return node_name; + } + + public void setNode_name(String node_name) { + this.node_name = node_name; + } + + public String getContacts_phone() { + return contacts_phone; + } + + public void setContacts_phone(String contacts_phone) { + this.contacts_phone = contacts_phone; + } + + public String getSearchValue() { + return searchValue; + } + + public void setSearchValue(String searchValue) { + this.searchValue = searchValue; + } + + public String getCreateBy() { + return createBy; + } + + public void setCreateBy(String createBy) { + this.createBy = createBy; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getUpdateBy() { + return updateBy; + } + + public void setUpdateBy(String updateBy) { + this.updateBy = updateBy; + } + + public String getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(String updateTime) { + this.updateTime = updateTime; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + + public String getPlanId() { + return planId; + } + + public void setPlanId(String planId) { + this.planId = planId; + } + + public String getNodeId() { + return nodeId; + } + + public void setNodeId(String nodeId) { + this.nodeId = nodeId; + } + + public String getNodeType() { + return nodeType; + } + + public void setNodeType(String nodeType) { + this.nodeType = nodeType; + } + + public String getOrderId() { + return orderId; + } + + public void setOrderId(String orderId) { + this.orderId = orderId; + } + + public String getNodeName() { + return nodeName; + } + + public void setNodeName(String nodeName) { + this.nodeName = nodeName; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getContacts() { + return contacts; + } + + public void setContacts(String contacts) { + this.contacts = contacts; + } + + public String getContactsPhone() { + return contactsPhone; + } + + public void setContactsPhone(String contactsPhone) { + this.contactsPhone = contactsPhone; + } + + public String getProvinceId() { + return provinceId; + } + + public void setProvinceId(String provinceId) { + this.provinceId = provinceId; + } + + public String getProvinceName() { + return provinceName; + } + + public void setProvinceName(String provinceName) { + this.provinceName = provinceName; + } + + public String getCityId() { + return cityId; + } + + public void setCityId(String cityId) { + this.cityId = cityId; + } + + public String getCityName() { + return cityName; + } + + public void setCityName(String cityName) { + this.cityName = cityName; + } + + public String getCountyId() { + return countyId; + } + + public void setCountyId(String countyId) { + this.countyId = countyId; + } + + public String getCountyName() { + return countyName; + } + + public void setCountyName(String countyName) { + this.countyName = countyName; + } + + public String getPlanIndex() { + return planIndex; + } + + public void setPlanIndex(String planIndex) { + this.planIndex = planIndex; + } + + public String getRemarks() { + return remarks; + } + + public void setRemarks(String remarks) { + this.remarks = remarks; + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/bean/StateBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/bean/StateBean.java new file mode 100644 index 0000000..83f9b59 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/bean/StateBean.java @@ -0,0 +1,151 @@ +package com.dahe.mylibrary.bean; + +import java.io.Serializable; + +public class StateBean implements Serializable { + + + private String searchValue; + private String createBy; + private String createTime; + private String updateBy; + private String updateTime; + private String remark; + private String dictCode; + private String dictSort; + private String dictLabel; + private String dictValue; + private String dictType; + private String cssClass; + private String listClass; + private String isDefault; + private String status; + + public StateBean(String dictLabel, String dictValue) { + this.dictLabel = dictLabel; + this.dictValue = dictValue; + } + + public String getSearchValue() { + return searchValue; + } + + public void setSearchValue(String searchValue) { + this.searchValue = searchValue; + } + + public String getCreateBy() { + return createBy; + } + + public void setCreateBy(String createBy) { + this.createBy = createBy; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getUpdateBy() { + return updateBy; + } + + public void setUpdateBy(String updateBy) { + this.updateBy = updateBy; + } + + public String getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(String updateTime) { + this.updateTime = updateTime; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public String getDictCode() { + return dictCode; + } + + public void setDictCode(String dictCode) { + this.dictCode = dictCode; + } + + public String getDictSort() { + return dictSort; + } + + public void setDictSort(String dictSort) { + this.dictSort = dictSort; + } + + public String getDictLabel() { + return dictLabel; + } + + public void setDictLabel(String dictLabel) { + this.dictLabel = dictLabel; + } + + public String getDictValue() { + return dictValue; + } + + public void setDictValue(String dictValue) { + this.dictValue = dictValue; + } + + public String getDictType() { + return dictType; + } + + public void setDictType(String dictType) { + this.dictType = dictType; + } + + public String getCssClass() { + return cssClass; + } + + public void setCssClass(String cssClass) { + this.cssClass = cssClass; + } + + public String getListClass() { + return listClass; + } + + public void setListClass(String listClass) { + this.listClass = listClass; + } + + public String getIsDefault() { + return isDefault; + } + + public void setIsDefault(String isDefault) { + this.isDefault = isDefault; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public static class ParamsDTO { + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/bean/TipsBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/bean/TipsBean.java new file mode 100644 index 0000000..1b989cc --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/bean/TipsBean.java @@ -0,0 +1,29 @@ +package com.dahe.mylibrary.bean; + +import java.io.Serializable; + +public class TipsBean implements Serializable { + private String title; + private String content; + + public TipsBean(String title, String content) { + this.title = title; + this.content = content; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/bean/VersionBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/bean/VersionBean.java new file mode 100644 index 0000000..55f51f7 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/bean/VersionBean.java @@ -0,0 +1,93 @@ +package com.dahe.mylibrary.bean; + +import java.io.Serializable; + +public class VersionBean implements Serializable { + + + + private ParamsDao data; + + public ParamsDao getData() { + return data; + } + + public void setData(ParamsDao data) { + this.data = data; + } + + public static class ParamsDao implements Serializable{ + private int versionId; + private int version; + private String versionName; + private String introduce; + private String updateType; + private String createTime; + private String remark; + private String apkUrl; + + public String getApkUrl() { + return apkUrl; + } + + public void setApkUrl(String apkUrl) { + this.apkUrl = apkUrl; + } + + public int getVersionId() { + return versionId; + } + + public void setVersionId(int versionId) { + this.versionId = versionId; + } + + public int getVersion() { + return version; + } + + public void setVersion(int version) { + this.version = version; + } + + public String getVersionName() { + return versionName; + } + + public void setVersionName(String versionName) { + this.versionName = versionName; + } + + public String getIntroduce() { + return introduce; + } + + public void setIntroduce(String introduce) { + this.introduce = introduce; + } + + public String getUpdateType() { + return updateType; + } + + public void setUpdateType(String updateType) { + this.updateType = updateType; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/callback/OnItemLongClickListener.java b/mylibrary/src/main/java/com/dahe/mylibrary/callback/OnItemLongClickListener.java new file mode 100644 index 0000000..9e949df --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/callback/OnItemLongClickListener.java @@ -0,0 +1,14 @@ +package com.dahe.mylibrary.callback; + +import android.view.View; + +import androidx.recyclerview.widget.RecyclerView; + +/** + * @author:luck + * @date:2020-01-13 17:58 + * @describe:长按事件 + */ +public interface OnItemLongClickListener { + void onItemLongClick(RecyclerView.ViewHolder holder, int position, View v); +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/callback/RefreshCallBack.java b/mylibrary/src/main/java/com/dahe/mylibrary/callback/RefreshCallBack.java new file mode 100644 index 0000000..adc89c3 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/callback/RefreshCallBack.java @@ -0,0 +1,14 @@ +package com.dahe.mylibrary.callback; + +/** + * 刷新的回调 + */ + +public interface RefreshCallBack { + /** + * @param stat 1刷新 2加载更多 + * @param page 当前页数 + * @param count 当前count + */ + void getRefreshDate(int stat, int page, int count); +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/CarSelPopupView.java b/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/CarSelPopupView.java new file mode 100644 index 0000000..26850dc --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/CarSelPopupView.java @@ -0,0 +1,102 @@ +package com.dahe.mylibrary.cuspop; + +import android.content.Context; +import android.view.View; +import android.widget.Button; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.listener.OnItemClickListener; +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.adapter.CarAdapter; +import com.dahe.mylibrary.bean.CarBean; +import com.dahe.mylibrary.net.JsonUtils; +import com.lxj.xpopup.core.CenterPopupView; + +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +public class CarSelPopupView extends CenterPopupView { + + + private Context context; + private List data; + public CarSelPopupView(Context context, String data) { + super(context); + this.context = context; + ArrayList nodeBeans = JsonUtils.getInstance().jsonToList(data, CarBean.class); + this.data = nodeBeans; + } + + @Override + protected int getImplLayoutId() { + return R.layout.view_node; + } + + @Override + protected void onCreate() { + super.onCreate(); + TextView tvTitle = (TextView) findViewById(R.id.tvTitle); + ImageView ivCha = (ImageView) findViewById(R.id.ivCha); + LinearLayout llCha = (LinearLayout) findViewById(R.id.llCha); + Button btnOK = (Button) findViewById(R.id.btnOK); + RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView); + recyclerView.setLayoutManager(new LinearLayoutManager(context,RecyclerView.VERTICAL,false)); + recyclerView.setHasFixedSize(true); + CarAdapter nodeAdapter = new CarAdapter(-1,data); + recyclerView.setAdapter(nodeAdapter); + + tvTitle.setText("关联司机"); + nodeAdapter.setOnItemClickListener(new OnItemClickListener() { + @Override + public void onItemClick(@NonNull @NotNull BaseQuickAdapter adapter, @NonNull @NotNull View view, int position) { + CarBean nodeSelectBean = data.get(position); + nodeSelectBean.setSelect(!nodeSelectBean.isSelect()); + nodeAdapter.notifyItemChanged(position); + } + }); + + btnOK.setOnClickListener(v -> { + if (listener!=null){ +// ArrayList temp = new ArrayList<>(); +// for (int i = 0; i < data.size(); i++) { +// CarBean nodeSelectBean = data.get(i); +// if ("1".equals(nodeSelectBean.isSelect())){ +// temp.add(nodeSelectBean); +// } +// +// } +// if (temp.size()<=0){ +// ToastUtils.showToast(context,"至少存在一个节点"); +// return; +// } + listener.okClick(JsonUtils.getInstance().toJson(nodeAdapter.getData())); +// temp = null; + dismiss(); + } + }); + llCha.setOnClickListener(v -> { + dismiss(); + }); + } + + + private OnOkListener listener; + + public CarSelPopupView setOnOkListener(OnOkListener listener) { + this.listener = listener; + return this; + } + + public interface OnOkListener { + void okClick(String data); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/CenterPopupView.java b/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/CenterPopupView.java new file mode 100644 index 0000000..14a7542 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/CenterPopupView.java @@ -0,0 +1,90 @@ +package com.dahe.mylibrary.cuspop; + +import android.app.Activity; +import android.content.Context; +import android.util.Log; +import android.view.View; + +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.listener.OnItemClickListener; +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.adapter.CenterSimAdapter; +import com.dahe.mylibrary.bean.StateBean; +import com.luck.picture.lib.decoration.GridSpacingItemDecoration; +import com.lxj.xpopup.impl.PartShadowPopupView; + +import java.util.List; + +/** + * Description: 自定义局部阴影弹窗 + * Create by dance, at 2018/12/21 + */ +public class CenterPopupView extends PartShadowPopupView { + private Context ctx; + private RecyclerView recyclerView; + private List wordList; + private CenterSimAdapter adapter; + private StateBean selectString; + + public CenterPopupView(@NonNull Activity context, List wordList, StateBean selectString) { + super(context); + this.wordList= wordList; + this.selectString = selectString; + } + + @Override + protected int getImplLayoutId() { + return R.layout.custom_part_shadow_popup; + } + + + @Override + protected void onCreate() { + super.onCreate(); + recyclerView = findViewById(R.id.recyclerView); + GridLayoutManager gridLayoutManager = new GridLayoutManager(ctx, 4); + recyclerView.addItemDecoration(new GridSpacingItemDecoration(4, 20, false)); + recyclerView.setLayoutManager(gridLayoutManager); + adapter = new CenterSimAdapter(-1, wordList,selectString); + recyclerView.setAdapter(adapter); + + adapter.setOnItemClickListener(new OnItemClickListener() { + @Override + public void onItemClick(@NonNull BaseQuickAdapter adapter, @NonNull View view, int position) { + if (listener!=null){ + listener.selectChange(wordList.get(position),position); + } + ((CenterSimAdapter)adapter).setSelect(wordList.get(position)); + adapter.notifyDataSetChanged(); + dismiss(); + } + }); + + } + + @Override + protected void onShow() { + super.onShow(); + Log.e("tag", "CustomPartShadowPopupView onShow"); + } + + @Override + protected void onDismiss() { + super.onDismiss(); + Log.e("tag", "CustomPartShadowPopupView onDismiss"); + } + + + private OnSelectChangeListener listener; + public CenterPopupView setOnSelectChangeListener(OnSelectChangeListener listener){ + this.listener = listener; + return this; + } + public interface OnSelectChangeListener{ + void selectChange(StateBean item ,int postion); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/dialog/DialogPhotoSelect.java b/mylibrary/src/main/java/com/dahe/mylibrary/dialog/DialogPhotoSelect.java new file mode 100644 index 0000000..e06f0e3 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/dialog/DialogPhotoSelect.java @@ -0,0 +1,108 @@ +package com.dahe.mylibrary.dialog; + +import android.content.Context; +import android.os.Bundle; +import android.view.Gravity; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.widget.TextView; + +import androidx.annotation.NonNull; + +import com.dahe.mylibrary.R; + + +/** + * 头像选择 dialog + * + * @Description: + * @Author: tao + * @CreateDate: 2018/7/26 10:34 + */ +public class DialogPhotoSelect extends MyBaseDialog { + + private TextView take_photo; + private TextView select_photo; + private TextView do_cancel; + + private onSelectClickListener onSelectClickListener; + + public void setOnSelectClickListener(onSelectClickListener onSelectClickListener) { + this.onSelectClickListener = onSelectClickListener; + } + + public DialogPhotoSelect(@NonNull Context context) { + super(context); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.dialog_photo_select); + + initView(); + initListener(); + } + + private void initView() { + take_photo = findViewById( R.id.take_photo); + select_photo = findViewById(R.id.select_photo); + do_cancel = findViewById(R.id.do_cancel); + } + + private void initListener() { + + //拍照 + take_photo.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + dismiss(); + onSelectClickListener.onTakePhoto(); + } + }); + + //相册选择 + select_photo.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + dismiss(); + onSelectClickListener.onSelectPhoto(); + } + }); + + do_cancel.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + dismiss(); + } + }); + + + } + + @Override + public void init(@NonNull Context context) { + Window window = getWindow(); + window.setWindowAnimations(R.style.BottomAnim); + window.setGravity( Gravity.BOTTOM); + //默认的Dialog只有5/6左右的宽度,改为全屏宽度,由dialog的布局自己来决定实际显示宽度 + window.getDecorView().setPadding(0, 0, 0, 0); + WindowManager.LayoutParams lp = window.getAttributes(); + lp.width = WindowManager.LayoutParams.MATCH_PARENT; + lp.height = WindowManager.LayoutParams.WRAP_CONTENT; + window.setAttributes(lp); + } + + @Override + public boolean isCancelAble() { + return true; + } + + public interface onSelectClickListener { + + void onTakePhoto(); + + void onSelectPhoto(); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/dialog/MyBaseDialog.java b/mylibrary/src/main/java/com/dahe/mylibrary/dialog/MyBaseDialog.java new file mode 100644 index 0000000..74b915f --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/dialog/MyBaseDialog.java @@ -0,0 +1,55 @@ +package com.dahe.mylibrary.dialog; + +import android.app.Dialog; +import android.content.Context; +import android.os.Bundle; +import android.view.Gravity; +import android.view.Window; +import android.view.WindowManager; + +import androidx.annotation.NonNull; + +import com.dahe.mylibrary.R; + + +/** + * Dialog 基类 基类 基类 + *

+ * 以后再写Dialog,都要继承这个 + * + * @Description: + * @Author: tao + * @CreateDate: 2018/7/26 10:29 + */ +public class MyBaseDialog extends Dialog { + + + public MyBaseDialog(@NonNull Context context) { + super(context, R.style.MyBaseDialog); + init(context); + } + + public void init(@NonNull Context context) { + Window window = getWindow(); + window.setWindowAnimations(R.style.BottomAnim); + window.setGravity(Gravity.CENTER); + //默认的Dialog只有5/6左右的宽度,改为全屏宽度,由dialog的布局自己来决定实际显示宽度 + window.getDecorView().setPadding(0, 0, 0, 0); + WindowManager.LayoutParams lp = window.getAttributes(); + lp.width = WindowManager.LayoutParams.MATCH_PARENT; + lp.height = WindowManager.LayoutParams.WRAP_CONTENT; + window.setAttributes(lp); + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setCancelable(isCancelAble()); + setCanceledOnTouchOutside(isCancelAble()); + } + + public boolean isCancelAble() { + return false; + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/dialog/VersionDialog.java b/mylibrary/src/main/java/com/dahe/mylibrary/dialog/VersionDialog.java new file mode 100644 index 0000000..383c55f --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/dialog/VersionDialog.java @@ -0,0 +1,21 @@ +package com.dahe.mylibrary.dialog; + +import android.app.Dialog; +import android.content.Context; + +/** + * Created by Allen Liu on 2017/2/23. + */ +public class VersionDialog extends Dialog { + private int res; + + public VersionDialog(Context context, int theme, int res) { + super(context, theme); + getWindow().setBackgroundDrawableResource(android.R.color.transparent); + // TODO 自动生成的构造函数存根 + setContentView(res); + this.res = res; + setCanceledOnTouchOutside(false); + } + +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/glide/AppGlideModule.java b/mylibrary/src/main/java/com/dahe/mylibrary/glide/AppGlideModule.java new file mode 100644 index 0000000..2387881 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/glide/AppGlideModule.java @@ -0,0 +1,35 @@ +package com.dahe.mylibrary.glide; + +import android.content.Context; + +import androidx.annotation.NonNull; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.Registry; +import com.bumptech.glide.annotation.GlideModule; +import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader; +import com.bumptech.glide.load.model.GlideUrl; + +import org.jetbrains.annotations.NotNull; + +import java.io.InputStream; + +import okhttp3.OkHttpClient; + +/** + * @ClassName AppGlideModule + * @Author 用户 + * @Date 2021/10/11 10:13 + * @Description TODO + */ + +@GlideModule +public class AppGlideModule extends com.bumptech.glide.module.AppGlideModule { + + @Override + public void registerComponents(@NonNull @NotNull Context context, @NonNull @NotNull Glide glide, @NonNull @NotNull Registry registry) { + super.registerComponents(context, glide, registry); + OkHttpClient client = UnsafeOkHttpClient.getUnsafeOkHttpClient(); + registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(client)); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/glide/UnsafeOkHttpClient.java b/mylibrary/src/main/java/com/dahe/mylibrary/glide/UnsafeOkHttpClient.java new file mode 100644 index 0000000..da9e54e --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/glide/UnsafeOkHttpClient.java @@ -0,0 +1,67 @@ +package com.dahe.mylibrary.glide; + +import java.security.cert.CertificateException; +import java.util.concurrent.TimeUnit; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import okhttp3.OkHttpClient; + +/** + * @ClassName UnsafeOkHttpClient + * @Author 用户 + * @Date 2021/10/11 10:16 + * @Description TODO + */ +public class UnsafeOkHttpClient { + public static OkHttpClient getUnsafeOkHttpClient() { + try { + // Create a trust manager that does not validate certificate chains + final TrustManager[] trustAllCerts = new TrustManager[]{ + new X509TrustManager() { + @Override + public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { + } + + @Override + public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { + } + + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return new java.security.cert.X509Certificate[]{}; + } + } + }; + + // Install the all-trusting trust manager + final SSLContext sslContext = SSLContext.getInstance("SSL"); + sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); + + // Create an ssl socket factory with our all-trusting manager + final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); + + OkHttpClient.Builder builder = new OkHttpClient.Builder(); + builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]); + builder.hostnameVerifier(new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }); + + builder.connectTimeout(20, TimeUnit.SECONDS); + builder.readTimeout(20,TimeUnit.SECONDS); + + OkHttpClient okHttpClient = builder.build(); + return okHttpClient; + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/CommonResponseBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/CommonResponseBean.java new file mode 100644 index 0000000..d6ac17a --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/CommonResponseBean.java @@ -0,0 +1,73 @@ +package com.dahe.mylibrary.net; + +import java.io.Serializable; + +/** + * 返回通用的实体类 + */ + +public class CommonResponseBean implements Serializable { + private T data; + private int code; + private String info; + private String msg; + private String url; + private String fileName; + private boolean success; + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getInfo() { + return info; + } + + public void setInfo(String info) { + this.info = info; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public boolean isSuccess() { + return success; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/ErrorResponse.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/ErrorResponse.java new file mode 100644 index 0000000..d2998e9 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/ErrorResponse.java @@ -0,0 +1,22 @@ +package com.dahe.mylibrary.net; + +public class ErrorResponse { + private int code; + private String msg; + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/FileInterceptor.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/FileInterceptor.java new file mode 100644 index 0000000..d373b7c --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/FileInterceptor.java @@ -0,0 +1,60 @@ +package com.dahe.mylibrary.net; + +import android.util.Log; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; + +import okhttp3.Interceptor; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import okhttp3.ResponseBody; +import okio.Buffer; +import okio.BufferedSource; + +/** + * 文件上传Interceptor + */ + +public class FileInterceptor implements Interceptor { + private static final String TAG = "FileInterceptor"; + private File mFile; + + public FileInterceptor(File mFile) { + this.mFile = mFile; + } + + @Override + public Response intercept(Chain chain) throws IOException { + Request request = chain.request(); + request = request.newBuilder() + .post(RequestBody.create(MediaType.parse("application/file; charset=utf-8"), mFile)) + .build(); + Response response = chain.proceed(request); + Log.i(TAG, "url= " + request.body()); + Log.i(TAG, "method= " + request.method()); + ResponseBody responseBody = response.body(); + //为了不消耗buffer,我们这里使用source先获得buffer对象,然后clone()后使用 + BufferedSource source = responseBody.source(); + source.request(Long.MAX_VALUE); // Buffer the entire body. + //获得返回的数据 + Buffer buffer = source.buffer(); + //使用前clone()下,避免直接消耗 + String responseBodyStr = buffer.clone().readString(Charset.forName("UTF-8")); + Log.i(TAG, "result-body= " + responseBodyStr); + try { + JSONObject jsonObject = new JSONObject(responseBodyStr); + responseBody = ResponseBody.create(MediaType.parse("application/json; charset=utf-8"), jsonObject.getString("response")); + } catch (JSONException e) { + e.printStackTrace(); + } + response = response.newBuilder().body(responseBody).build(); + return response; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/GsonResponseBodyConverter.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/GsonResponseBodyConverter.java new file mode 100644 index 0000000..5ce33b2 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/GsonResponseBodyConverter.java @@ -0,0 +1,74 @@ +package com.dahe.mylibrary.net; + +import com.google.gson.Gson; + +import org.json.JSONObject; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.nio.charset.Charset; + +import okhttp3.ResponseBody; +import okio.Buffer; +import okio.BufferedSource; +import retrofit2.Converter; + + +public class GsonResponseBodyConverter implements Converter { + private final Gson gson; + private final Type type; + + + public GsonResponseBodyConverter(Gson gson, Type type) { + this.gson = gson; + this.type = type; + } + + @Override + public T convert(ResponseBody value) throws IOException { + + //为了不消耗buffer,我们这里使用source先获得buffer对象,然后clone()后使用 + BufferedSource source = value.source(); + source.request(Long.MAX_VALUE); // Buffer the entire body. + //获得返回的数据 + Buffer buffer = source.buffer(); + //使用前clone()下,避免直接消耗 + String responseBodyStr = buffer.clone().readString(Charset.forName("UTF-8")); + try { + + JSONObject jsonObject = new JSONObject(responseBodyStr); + int code = jsonObject.optInt("code"); + if (-1 == code) { + jsonObject.put("data", new JSONObject()); +// ErrorResponse errorResponse = gson.fromJson(response, ErrorResponse.class); + //抛一个自定义ResultException 传入失败时候的状态码,和信息 + + throw new ResultException(-1, "errorResponse.getMsg()"); + +// return gson.fromJson(responseBodyStr,type); + } + } catch (Exception e) { + e.printStackTrace(); + } + return gson.fromJson(responseBodyStr, type); + + +// String response = value.string(); +// //先将返回的json数据解析到Response中,如果code==200,则解析到我们的实体基类中,否则抛异常 +// Response httpResult = gson.fromJson(response, Response.class); +// if (httpResult.code()==200){ +// //200的时候就直接解析,不可能出现解析异常。因为我们实体基类中传入的泛型,就是数据成功时候的格式 +// return gson.fromJson(response,type); +// }else { +// ErrorResponse errorResponse = gson.fromJson(response,ErrorResponse.class); +// //抛一个自定义ResultException 传入失败时候的状态码,和信息 +// try { +// throw new ResultException(errorResponse.getCode(),errorResponse.getMsg()); +// } catch (ResultException e) { +// e.printStackTrace(); +// } +// return null; +// } + } +} + diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/JsonInterceptor.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/JsonInterceptor.java new file mode 100644 index 0000000..694a18e --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/JsonInterceptor.java @@ -0,0 +1,62 @@ +package com.dahe.mylibrary.net; + +import android.text.TextUtils; +import android.util.Log; +import org.json.JSONObject; + +import java.io.IOException; +import java.nio.charset.Charset; + +import okhttp3.Interceptor; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; +import okio.Buffer; +import okio.BufferedSource; + +/** + * json的Interceptor + */ + +public class JsonInterceptor implements Interceptor { + private static final String TAG = "JsonInterceptor"; + + public JsonInterceptor() { + } + + @Override + public Response intercept(Chain chain) throws IOException { + Request request = chain.request(); + Response response = chain.proceed(request); + ResponseBody responseBody = response.body(); + //为了不消耗buffer,我们这里使用source先获得buffer对象,然后clone()后使用 + BufferedSource source = responseBody.source(); + source.request(Long.MAX_VALUE); // Buffer the entire body. + //获得返回的数据 + Buffer buffer = source.buffer(); + //使用前clone()下,避免直接消耗 + String responseBodyStr = buffer.clone().readString(Charset.forName("UTF-8")); + Log.i(TAG, "result-body= " + responseBodyStr); + try { + JSONObject jsonObject = new JSONObject(responseBodyStr); + String str = jsonObject.optString("data"); + int code = jsonObject.optInt("code"); + if (-1 == code) { + jsonObject.put("data", new JSONObject()); + throw new ResultException(); + } else { + if (TextUtils.isEmpty(str)) { + jsonObject.put("data", new JSONObject()); + } + } + + String data = jsonObject.toString(); + responseBody = ResponseBody.create(MediaType.parse("application/json; charset=utf-8"), data); + } catch (Exception e) { + e.printStackTrace(); + } + response = response.newBuilder().body(responseBody).build(); + return response; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/JsonUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/JsonUtils.java new file mode 100644 index 0000000..37d91af --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/JsonUtils.java @@ -0,0 +1,91 @@ +package com.dahe.mylibrary.net; + +import android.util.Log; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonIOException; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; +import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.lang.reflect.Type; +import java.util.ArrayList; + +/** + * 利用Gson反射对象类型,将json转化为对象 + */ +public class JsonUtils { + private Gson mGson = null; + private static JsonUtils mUtils; + + public static JsonUtils getInstance() { + if (mUtils == null) { + return new JsonUtils(); + } else { + return mUtils; + } + } + + public Gson getGson() { + if (null == mGson) { + mGson = new GsonBuilder().serializeNulls().create(); + } + return mGson; + } + + public String toJson(Object o){ + return getGson().toJson(o); + } + + /** + * 将json数组转化为List + * + * @param json json字符串 + * @param classOfT 对应实体类型 + * @return 实体列表 + */ + public ArrayList jsonToList(String json, Class classOfT) { + try { + if (mGson == null) { + // 不要直接new Gson是为了避免放回结果为null的这种情况 + mGson = new GsonBuilder().serializeNulls().create(); + } + Type type = new TypeToken>() { + }.getType(); + ArrayList jsonObjs = mGson.fromJson(json, type); + + ArrayList listOfT = new ArrayList(); + for (JsonObject jsonObj : jsonObjs) { + listOfT.add(mGson.fromJson(jsonObj, classOfT)); + } + return listOfT; + } catch (Exception e) { + return null; + } + } + + public T fromJson(String json, Class type) throws JsonIOException, JsonSyntaxException { + try { + JSONObject object = new JSONObject(json); + json = object.getString("response"); + Log.i("fromJson: ", json); + } catch (JSONException e) { + e.printStackTrace(); + } + return getGson().fromJson(json, type); + } + + public T fromJson(String json, Type type) { + return getGson().fromJson(json, type); + } + + public T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException { + return getGson().fromJson(reader, typeOfT); + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/PagerBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/PagerBean.java new file mode 100644 index 0000000..5ce514d --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/PagerBean.java @@ -0,0 +1,47 @@ +package com.dahe.mylibrary.net; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by Administrator on 2018\8\26 0026. + */ +public class PagerBean { + private int total; + private int count; + private int more; + + private ArrayList rows; + + public ArrayList getRows() { + return rows; + } + + public void setRows(ArrayList rows) { + this.rows = rows; + } + + public int getTotal() { + return total; + } + + public void setTotal(int total) { + this.total = total; + } + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } + + public int getMore() { + return more; + } + + public void setMore(int more) { + this.more = more; + } +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/PagingBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/PagingBean.java new file mode 100644 index 0000000..7aa11f5 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/PagingBean.java @@ -0,0 +1,46 @@ +package com.dahe.mylibrary.net; + +import java.io.Serializable; + +/** + * 返回通用的实体类 + */ + +public class PagingBean implements Serializable { + private T data; + private int code; + private String count; + private String msg; + + public T getData() { + return data; + } + + public void setData(T data) { + this.data = data; + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getCount() { + return count; + } + + public void setCount(String count) { + this.count = count; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/ResponseConverterFactory.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/ResponseConverterFactory.java new file mode 100644 index 0000000..7d040ed --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/ResponseConverterFactory.java @@ -0,0 +1,44 @@ +package com.dahe.mylibrary.net; + +import com.google.gson.Gson; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; + +import okhttp3.RequestBody; +import okhttp3.ResponseBody; +import retrofit2.Converter; +import retrofit2.Retrofit; + +public class ResponseConverterFactory extends Converter.Factory { + + public static ResponseConverterFactory create() { + return create(new Gson()); + } + + + public static ResponseConverterFactory create(Gson gson) { + return new ResponseConverterFactory(gson); + } + + private final Gson gson; + + private ResponseConverterFactory(Gson gson) { + if (gson == null) throw new NullPointerException("gson == null"); + this.gson = gson; + } + + @Override + public Converter responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { + //返回我们自定义的Gson响应体变换器 + return new GsonResponseBodyConverter<>(gson, type); + } + + @Override + public Converter requestBodyConverter(Type type, + Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) { + //返回我们自定义的Gson响应体变换器 + return new GsonResponseBodyConverter<>(gson,type); + } +} + diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/ResultException.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/ResultException.java new file mode 100644 index 0000000..31ffeed --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/ResultException.java @@ -0,0 +1,12 @@ +package com.dahe.mylibrary.net; + +public class ResultException extends Exception { + + public ResultException() { + super(); + // TODO Auto-generated constructor stub + } + + public ResultException(int code, String msg) { + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/recycleviewswipe/GridSpacingItemDecoration.java b/mylibrary/src/main/java/com/dahe/mylibrary/recycleviewswipe/GridSpacingItemDecoration.java new file mode 100644 index 0000000..017eb0f --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/recycleviewswipe/GridSpacingItemDecoration.java @@ -0,0 +1,43 @@ +package com.dahe.mylibrary.recycleviewswipe; + +import android.graphics.Rect; +import android.view.View; + +import androidx.recyclerview.widget.RecyclerView; + +public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration { + + private int spanCount; //列数 + private int spacing; //间隔 + private boolean includeEdge; //是否包含边缘 + + public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) { + this.spanCount = spanCount; + this.spacing = spacing; + this.includeEdge = includeEdge; + } + + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + + //这里是关键,需要根据你有几列来判断 + int position = parent.getChildAdapterPosition(view); // item position + int column = position % spanCount; // item column + + if (includeEdge) { + outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing) + outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing) + + if (position < spanCount) { // top edge + outRect.top = spacing; + } + outRect.bottom = spacing; // item bottom + } else { + outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing) + outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f / spanCount) * spacing) + if (position >= spanCount) { + outRect.top = spacing; // item top + } + } + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/recycleviewswipe/MyDecoration.java b/mylibrary/src/main/java/com/dahe/mylibrary/recycleviewswipe/MyDecoration.java new file mode 100644 index 0000000..faf06a3 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/recycleviewswipe/MyDecoration.java @@ -0,0 +1,110 @@ +package com.dahe.mylibrary.recycleviewswipe; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.view.View; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.dahe.mylibrary.R; + + +public class MyDecoration extends RecyclerView.ItemDecoration{ + + public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; + + public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; + + private Drawable mDivider; + + private int mOrientation; + + /** + * 分割线缩进值 + */ + private int inset; + + private Paint paint; + + /** + * @param context + * @param orientation layout的方向 + * @param drawable 引入的drawable的ID + * @param inset 分割线缩进值 + */ + public MyDecoration(Context context, int orientation, int drawable, int inset) { + mDivider = context.getResources().getDrawable(drawable); + this.inset = inset; + paint = new Paint(); + paint.setColor(context.getResources().getColor(R.color.white)); + paint.setStyle(Paint.Style.FILL); + paint.setAntiAlias(true); + setOrientation(orientation); + } + + public void setOrientation(int orientation) { + if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) { + throw new IllegalArgumentException("invalid orientation"); + } + mOrientation = orientation; + } + + @Override + public void onDraw(Canvas c, RecyclerView parent) { + if (mOrientation == VERTICAL_LIST) { + drawVertical(c, parent); + } else { + drawHorizontal(c, parent); + } + } + + private void drawVertical(Canvas c, RecyclerView parent) { + final int left = parent.getPaddingLeft(); + final int right = parent.getWidth() - parent.getPaddingRight(); + + final int childCount = parent.getChildCount(); + //最后一个item不画分割线 + for (int i = 0; i < childCount - 1; i++) { + final View child = parent.getChildAt(i); + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); + final int top = child.getBottom() + params.bottomMargin; + final int bottom = top + mDivider.getIntrinsicHeight(); + if (inset > 0) { + c.drawRect(left, top, right, bottom, paint); + mDivider.setBounds(left + inset, top, right - inset, bottom); + } else { + mDivider.setBounds(left, top, right, bottom); + } + mDivider.draw(c); + } + } + + private void drawHorizontal(Canvas c, RecyclerView parent) { + final int top = parent.getPaddingTop(); + final int bottom = parent.getHeight() - parent.getPaddingBottom(); + + final int childCount = parent.getChildCount(); + for (int i = 0; i < childCount - 1; i++) { + final View child = parent.getChildAt(i); + final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); + final int left = child.getRight() + params.rightMargin; + final int right = left + mDivider.getIntrinsicHeight(); + mDivider.setBounds(left, top, right, bottom); + mDivider.draw(c); + } + } + + //由于Divider也有宽高,每一个Item需要向下或者向右偏移 + @Override + public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { + if (mOrientation == VERTICAL_LIST) { + outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); + } else { + outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); + } + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/recycleviewswipe/RecycleViewDivider.java b/mylibrary/src/main/java/com/dahe/mylibrary/recycleviewswipe/RecycleViewDivider.java new file mode 100644 index 0000000..77bb594 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/recycleviewswipe/RecycleViewDivider.java @@ -0,0 +1,156 @@ +package com.dahe.mylibrary.recycleviewswipe; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.view.View; + +import androidx.core.content.ContextCompat; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +public class RecycleViewDivider extends RecyclerView.ItemDecoration { + + private Paint mPaint; + //分割线 + private Drawable mDivider; + //分割线高度,默认是1px + private int mDividerHeight = 1; + //列表的方向:LinearLayoutManager.VERTICAL或LinearLayoutManager.HORIZONTAL + private int mOrientation; + + private static final int[] ATTRS = new int[]{android.R.attr.listDivider}; + + /** + * + * 默认分割线:高度为2px,颜色为灰色 + * 获取属性值, + * + * @param context + * @param orientation 列表方向 + */ + + public RecycleViewDivider(Context context, int orientation){ + if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) { + throw new IllegalArgumentException("请输入正确的参数!"); + } + mOrientation = orientation; + final TypedArray array = context.obtainStyledAttributes(ATTRS); + mDivider = array.getDrawable(0); + array.recycle(); + mDividerHeight = mDivider.getIntrinsicHeight(); + } + + /** + * 自定义分割线 + * + * @param context + * @param orientation 列表方向 + * @param drawableId 分割线图片 + */ + public RecycleViewDivider(Context context, int orientation, int drawableId) { + if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) { + throw new IllegalArgumentException("请输入正确的参数!"); + } + mOrientation = orientation; + + mDivider = ContextCompat.getDrawable(context, drawableId); + mDividerHeight = mDivider.getIntrinsicHeight(); + } + + /** + * 自定义分割线 + * + * @param orientation 列表方向 + * @param dividerHeight 分割线高度 + * @param dividerColor 分割线颜色 + */ + public RecycleViewDivider(int orientation, int dividerHeight, int dividerColor) { + + if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) { + throw new IllegalArgumentException("请输入正确的参数!"); + } + mOrientation = orientation; + + mDividerHeight = dividerHeight; + + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mPaint.setColor(dividerColor); + mPaint.setStyle(Paint.Style.FILL); + + } + + //获取分割线尺寸 + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + + if (mOrientation == LinearLayoutManager.VERTICAL) { + outRect.set(0, 0, 0, mDividerHeight); + } else { + outRect.set(0, 0, mDividerHeight, 0); + } + } + + @Override + public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { + super.onDraw(c, parent, state); + if(mOrientation==LinearLayoutManager.VERTICAL){ + drawVerticalLine(c,parent); + }else{ + drawHorizontalLine(c,parent); + } + } + + //为横方向item, 画分割线 + private void drawHorizontalLine(Canvas canvas, RecyclerView parent) { + + final int top = parent.getPaddingTop(); + final int bottom = parent.getMeasuredHeight() - parent.getPaddingBottom(); + final int childSize = parent.getChildCount(); + for (int i = 0; i < childSize - 1; i++) { + if ((i+1) % 3 != 0) { + final View child = parent.getChildAt(i); + RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams(); + final int left = child.getRight() + layoutParams.rightMargin; + final int right = left + mDividerHeight; + if (mDivider != null) { + mDivider.setBounds(left, top, right, bottom); + mDivider.draw(canvas); + } + if (mPaint != null) { + canvas.drawRect(left, top, right, bottom, mPaint); + } + } + } + } + + //为竖方向item, 画分割线 + private void drawVerticalLine(Canvas canvas, RecyclerView parent) { + + final int left = parent.getPaddingLeft(); + final int right = parent.getMeasuredWidth() - parent.getPaddingRight(); + final int childSize = parent.getChildCount(); + for (int i = 0; i < childSize; i++) { + if (i < childSize -1) { + final View child = parent.getChildAt(i); + RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams(); + final int top = child.getBottom() + layoutParams.bottomMargin; + final int bottom = top + mDividerHeight; + + if (mDivider != null) { + mDivider.setBounds(left, top, right, bottom); + mDivider.draw(canvas); + } + + if (mPaint != null) { + canvas.drawRect(left, top, right, bottom, mPaint); + } + + } + } + } +} + diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/ActivityUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ActivityUtils.java new file mode 100644 index 0000000..af47200 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ActivityUtils.java @@ -0,0 +1,330 @@ +package com.dahe.mylibrary.utils; + + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.Bundle; + +import androidx.annotation.NonNull; + + +import com.dahe.mylibrary.CommonBaseLibrary; + +import java.util.List; + +/** + *

+ *     author: Blankj
+ *     blog  : http://blankj.com
+ *     time  : 2016/09/23
+ *     desc  : Activity相关工具类
+ * 
+ */ +public class ActivityUtils { + + public ActivityUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + /** + * 启动Activity + * + * @param context + * @param clz + * @param bundle + */ + public static void startActivity(@NonNull Context context, @NonNull Class clz, Bundle bundle) { + Intent intent = new Intent(context, clz); + if (null != bundle) intent.putExtras(bundle); + context.startActivity(intent); + } + + /** + * 启动Activity + * + * @param context + * @param clz + * @param bundle + */ + public static void startPushActivity(@NonNull Context context, @NonNull Class clz, Bundle bundle) { + Intent intent = new Intent(context, clz); + if (null != bundle){ + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + intent.putExtras(bundle); + } + context.startActivity(intent); + } + + /** + * 启动Activity + * + * @param context + * @param clz + */ + public static void startActivity(@NonNull Context context, @NonNull Class clz) { + startActivity(context, clz, null); + } + + /** + * 启动Activity + * + * @param activity + * @param clz + * @param bundle + */ + public static void startActivityForResult(@NonNull Activity activity, @NonNull Class clz, Bundle bundle, int requestCode) { + Intent intent = new Intent(activity, clz); + if (null != bundle) intent.putExtras(bundle); + activity.startActivityForResult(intent, requestCode); + } + + /** + * 启动Activity + * + * @param activity + * @param clz + */ + public static void startActivityForResult(@NonNull Activity activity, @NonNull Class clz, int requestCode) { + startActivityForResult(activity, clz, null, requestCode); + } + + +// /** +// * 跳转登录界面 +// * +// * @param context +// * @param finishOthers 是否结束其他的activity true结束 false 不结束 +// */ +// public static void openLoginActivity(@NonNull Context context, boolean finishOthers) { +// Intent intent = new Intent(context, LoginMainActivity.class); +// Bundle bundle = new Bundle(); +// bundle.putBoolean("finishOthers", finishOthers); +// intent.putExtras(bundle); +// context.startActivity(intent); +// } + +// /** +// * 启动前必须登录Activity +// * +// * @param context +// * @param clz +// */ +// public static void startActivityByLogin(@NonNull Context context, @NonNull Class clz) { +// startActivityByLogin(context, clz, null); +// } + + + /** + * 回到桌面 + */ + public static void startHomeActivity(Context context) { + Intent homeIntent = new Intent(Intent.ACTION_MAIN); + homeIntent.addCategory(Intent.CATEGORY_HOME); + context.startActivity(homeIntent); + } + + /** + * 获取Activity栈链表 + * + * @return Activity栈链表 + */ + public static List getActivityList() { + return CommonBaseLibrary.activityList; + } + + /** + * 获取启动项Activity + * + * @param packageName 包名 + * @return 启动项Activity + */ + public static String getLauncherActivity(@NonNull final String packageName) { + Intent intent = new Intent(Intent.ACTION_MAIN, null); + intent.addCategory(Intent.CATEGORY_LAUNCHER); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + List info = pm.queryIntentActivities(intent, 0); + for (ResolveInfo aInfo : info) { + if (aInfo.activityInfo.packageName.equals(packageName)) { + return aInfo.activityInfo.name; + } + } + return "no " + packageName; + } + + /** + * 获取栈顶Activity + * + * @return 栈顶Activity + */ + public static Activity getTopActivity() { + if (CommonBaseLibrary.topActivity != null) { + Activity activity = CommonBaseLibrary.topActivity.get(); + if (activity != null) { + return activity; + } + } + List activities = CommonBaseLibrary.activityList; + int size = activities.size(); + return size > 0 ? activities.get(size - 1) : null; + } + + /** + * 判断Activity是否存在栈中 + * + * @param activity activity + * @return {@code true}: 存在
{@code false}: 不存在 + */ + public static boolean isActivityExistsInStack(@NonNull final Activity activity) { + List activities = CommonBaseLibrary.activityList; + for (Activity aActivity : activities) { + if (aActivity.equals(activity)) { + return true; + } + } + return false; + } + + /** + * 判断Activity是否存在栈中 + * + * @param clz activity类 + * @return {@code true}: 存在
{@code false}: 不存在 + */ + public static boolean isActivityExistsInStack(@NonNull final Class clz) { + List activities = CommonBaseLibrary.activityList; + for (Activity aActivity : activities) { + if (aActivity.getClass().equals(clz)) { + return true; + } + } + return false; + } + + /** + * 结束Activity + * + * @param activity activity + */ + public static void finishActivity(@NonNull final Activity activity) { + activity.finish(); + } + + + /** + * 结束Activity + * + * @param clz activity类 + */ + public static void finishActivity(@NonNull final Class clz) { + List activities = CommonBaseLibrary.activityList; + for (Activity activity : activities) { + if (activity.getClass().equals(clz)) { + activity.finish(); + } + } + } + + /** + * 结束到指定Activity + * + * @param activity activity + * @param isIncludeSelf 是否结束该activity自己 + */ + public static boolean finishToActivity(@NonNull final Activity activity, + final boolean isIncludeSelf) { + List activities = CommonBaseLibrary.activityList; + for (int i = activities.size() - 1; i >= 0; --i) { + Activity aActivity = activities.get(i); + if (aActivity.equals(activity)) { + if (isIncludeSelf) { + finishActivity(aActivity); + } + return true; + } + finishActivity(aActivity); + } + return false; + } + + /** + * 结束到指定Activity + * + * @param isIncludeSelf 是否结束该activity自己 + */ + public static boolean finishToActivity(@NonNull final Class clz, + final boolean isIncludeSelf) { + List activities = CommonBaseLibrary.activityList; + for (int i = activities.size() - 1; i >= 0; --i) { + Activity aActivity = activities.get(i); + if (aActivity.getClass().equals(clz)) { + if (isIncludeSelf) { + finishActivity(aActivity); + } + return true; + }else{ + finishActivity(aActivity); + } +// finishActivity(aActivity); + } + return false; + } + + /** + * 结束除最新之外的同类型Activity + *

也就是让栈中最多只剩下一种类型的Activity

+ * + * @param clz activity类 + */ + public static void finishOtherActivitiesExceptNewest(@NonNull final Class clz) { + List activities = CommonBaseLibrary.activityList; + boolean flag = false; + for (int i = activities.size() - 1; i >= 0; i--) { + Activity activity = activities.get(i); + if (activity.getClass().equals(clz)) { + if (flag) { + finishActivity(activity); + } else { + flag = true; + } + } else { + finishActivity(activity); + } + } + } + + /** + * 清除除本activity之外所有的activity + * + * @param clz 本activity的类名 + */ + public static void finishOtherActivities(@NonNull final Class clz) { + List activities = CommonBaseLibrary.activityList; + for (Activity activity : activities) { + if (!activity.getClass().equals(clz)) { + finishActivity(activity); + } + } + } + + /** + * 结束所有activity + */ + public static void finishAllActivities() { + List activityList = CommonBaseLibrary.activityList; + for (int i = activityList.size() - 1; i >= 0; --i) {// 从栈顶开始移除 + Activity activity = activityList.get(i); + activity.finish();// 在onActivityDestroyed发生remove + } + } + + private static Context getActivityOrApp() { + Activity topActivity = getTopActivity(); + return topActivity == null ? CommonBaseLibrary.getApplication() : topActivity; + } + + +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/AppUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/AppUtils.java new file mode 100644 index 0000000..e556926 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/AppUtils.java @@ -0,0 +1,1062 @@ +package com.dahe.mylibrary.utils; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.app.ActivityManager; +import android.app.AppOpsManager; +import android.app.usage.UsageStats; +import android.app.usage.UsageStatsManager; +import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.content.pm.Signature; +import android.graphics.drawable.Drawable; +import android.net.Uri; +import android.os.Build; +import android.provider.Settings; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.core.content.FileProvider; + + +import com.dahe.mylibrary.CommonBaseLibrary; + +import java.io.File; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.List; + +/** + *
+ *     author: Blankj
+ *     blog  : http://blankj.com
+ *     time  : 2016/08/02
+ *     desc  : utils about app
+ * 
+ * registerAppStatusChangedListener : 注册 App 前后台切换监听器 + * unregisterAppStatusChangedListener: 注销 App 前后台切换监听器 + * installApp : 安装 App(支持 8.0) + * installAppSilent : 静默安装 App + * uninstallApp : 卸载 App + * uninstallAppSilent : 静默卸载 App + * isAppInstalled : 判断 App 是否安装 + * isAppRoot : 判断 App 是否有 root 权限 + * isAppDebug : 判断 App 是否是 Debug 版本 + * isAppSystem : 判断 App 是否是系统应用 + * isAppForeground : 判断 App 是否处于前台 + * launchApp : 打开 App + * relaunchApp : 重启 App + * launchAppDetailsSettings : 打开 App 具体设置 + * exitApp : 关闭应用 + * getAppIcon : 获取 App 图标 + * getAppPackageName : 获取 App 包名 + * getAppName : 获取 App 名称 + * getAppPath : 获取 App 路径 + * getAppVersionName : 获取 App 版本号 + * getAppVersionCode : 获取 App 版本码 + * getAppSignature : 获取 App 签名 + * getAppSignatureSHA1 : 获取应用签名的的 SHA1 值 + * getAppSignatureSHA256 : 获取应用签名的的 SHA256 值 + * getAppSignatureMD5 : 获取应用签名的的 MD5 值 + * getAppInfo : 获取 App 信息 + * getAppsInfo : 获取所有已安装 App 信息 + * getApkInfo : 获取 Apk 信息 + */ +public final class AppUtils { + + private AppUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + /** + * Install the app. + *

Target APIs greater than 25 must hold + * {@code }

+ * + * @param filePath The path of file. + */ + public static void installApp(final String filePath) { + installApp(getFileByPath(filePath)); + } + + /** + * Install the app. + *

Target APIs greater than 25 must hold + * {@code }

+ * + * @param file The file. + */ + public static void installApp(final File file) { + if (!isFileExists(file)) return; + CommonBaseLibrary.getApplication().startActivity(getInstallAppIntent(file, true)); + } + + /** + * Install the app. + *

Target APIs greater than 25 must hold + * {@code }

+ * + * @param activity The activity. + * @param filePath The path of file. + * @param requestCode If >= 0, this code will be returned in + * onActivityResult() when the activity exits. + */ + public static void installApp(final Activity activity, + final String filePath, + final int requestCode) { + installApp(activity, getFileByPath(filePath), requestCode); + } + + /** + * Install the app. + *

Target APIs greater than 25 must hold + * {@code }

+ * + * @param activity The activity. + * @param file The file. + * @param requestCode If >= 0, this code will be returned in + * onActivityResult() when the activity exits. + */ + public static void installApp(final Activity activity, + final File file, + final int requestCode) { + if (!isFileExists(file)) return; + activity.startActivityForResult(getInstallAppIntent(file), requestCode); + } + + /** + * Install the app silently. + *

Without root permission must hold + * {@code android:sharedUserId="android.uid.shell"} and + * {@code }

+ * + * @param filePath The path of file. + * @return {@code true}: success
{@code false}: fail + */ + public static boolean installAppSilent(final String filePath) { + return installAppSilent(getFileByPath(filePath), null); + } + + /** + * Install the app silently. + *

Without root permission must hold + * {@code android:sharedUserId="android.uid.shell"} and + * {@code }

+ * + * @param file The file. + * @return {@code true}: success
{@code false}: fail + */ + public static boolean installAppSilent(final File file) { + return installAppSilent(file, null); + } + + + /** + * Install the app silently. + *

Without root permission must hold + * {@code android:sharedUserId="android.uid.shell"} and + * {@code }

+ * + * @param filePath The path of file. + * @param params The params of installation(e.g.,-r, -s). + * @return {@code true}: success
{@code false}: fail + */ + public static boolean installAppSilent(final String filePath, final String params) { + return installAppSilent(getFileByPath(filePath), params); + } + + /** + * Install the app silently. + *

Without root permission must hold + * {@code android:sharedUserId="android.uid.shell"} and + * {@code }

+ * + * @param file The file. + * @param params The params of installation(e.g.,-r, -s). + * @return {@code true}: success
{@code false}: fail + */ + public static boolean installAppSilent(final File file, final String params) { + return installAppSilent(file, params, isDeviceRooted()); + } + + /** + * Install the app silently. + *

Without root permission must hold + * {@code android:sharedUserId="android.uid.shell"} and + * {@code }

+ * + * @param file The file. + * @param params The params of installation(e.g.,-r, -s). + * @param isRooted True to use root, false otherwise. + * @return {@code true}: success
{@code false}: fail + */ + public static boolean installAppSilent(final File file, + final String params, + final boolean isRooted) { + if (!isFileExists(file)) return false; + String filePath = '"' + file.getAbsolutePath() + '"'; + String command = "LD_LIBRARY_PATH=/vendor/lib*:/system/lib* pm install " + + (params == null ? "" : params + " ") + + filePath; + ShellUtils.CommandResult commandResult = ShellUtils.execCmd(command, isRooted); + if (commandResult.successMsg != null + && commandResult.successMsg.toLowerCase().contains("success")) { + return true; + } else { + Log.e("AppUtils", "installAppSilent successMsg: " + commandResult.successMsg + + ", errorMsg: " + commandResult.errorMsg); + return false; + } + } + + /** + * Uninstall the app. + * + * @param packageName The name of the package. + */ + public static void uninstallApp(final String packageName) { + if (isSpace(packageName)) return; + CommonBaseLibrary.getApplication().startActivity(getUninstallAppIntent(packageName, true)); + } + + /** + * Uninstall the app. + * + * @param activity The activity. + * @param packageName The name of the package. + * @param requestCode If >= 0, this code will be returned in + * onActivityResult() when the activity exits. + */ + public static void uninstallApp(final Activity activity, + final String packageName, + final int requestCode) { + if (isSpace(packageName)) return; + activity.startActivityForResult(getUninstallAppIntent(packageName), requestCode); + } + + /** + * Uninstall the app silently. + *

Without root permission must hold + * {@code android:sharedUserId="android.uid.shell"} and + * {@code }

+ * + * @param packageName The name of the package. + * @return {@code true}: success
{@code false}: fail + */ + public static boolean uninstallAppSilent(final String packageName) { + return uninstallAppSilent(packageName, false); + } + + /** + * Uninstall the app silently. + *

Without root permission must hold + * {@code android:sharedUserId="android.uid.shell"} and + * {@code }

+ * + * @param packageName The name of the package. + * @param isKeepData Is keep the data. + * @return {@code true}: success
{@code false}: fail + */ + public static boolean uninstallAppSilent(final String packageName, final boolean isKeepData) { + return uninstallAppSilent(packageName, isKeepData, isDeviceRooted()); + } + + /** + * Uninstall the app silently. + *

Without root permission must hold + * {@code android:sharedUserId="android.uid.shell"} and + * {@code }

+ * + * @param packageName The name of the package. + * @param isKeepData Is keep the data. + * @param isRooted True to use root, false otherwise. + * @return {@code true}: success
{@code false}: fail + */ + public static boolean uninstallAppSilent(final String packageName, + final boolean isKeepData, + final boolean isRooted) { + if (isSpace(packageName)) return false; + String command = "LD_LIBRARY_PATH=/vendor/lib*:/system/lib* pm uninstall " + + (isKeepData ? "-k " : "") + + packageName; + ShellUtils.CommandResult commandResult = ShellUtils.execCmd(command, isRooted); + if (commandResult.successMsg != null + && commandResult.successMsg.toLowerCase().contains("success")) { + return true; + } else { + Log.e("AppUtils", "uninstallAppSilent successMsg: " + commandResult.successMsg + + ", errorMsg: " + commandResult.errorMsg); + return false; + } + } + + /** + * Return whether the app is installed. + * + * @param packageName The name of the package. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isAppInstalled(@NonNull final String packageName) { + PackageManager packageManager = CommonBaseLibrary.getApplication().getPackageManager(); + try { + return packageManager.getApplicationInfo(packageName, 0) != null; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return false; + } + } + + /** + * Return whether the application with root permission. + * + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isAppRoot() { + ShellUtils.CommandResult result = ShellUtils.execCmd("echo root", true); + if (result.result == 0) return true; + if (result.errorMsg != null) { + Log.d("AppUtils", "isAppRoot() called" + result.errorMsg); + } + return false; + } + + /** + * Return whether it is a debug application. + * + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isAppDebug() { + return isAppDebug(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Return whether it is a debug application. + * + * @param packageName The name of the package. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isAppDebug(final String packageName) { + if (isSpace(packageName)) return false; + try { + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + ApplicationInfo ai = pm.getApplicationInfo(packageName, 0); + return ai != null && (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return false; + } + } + + /** + * Return whether it is a system application. + * + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isAppSystem() { + return isAppSystem(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Return whether it is a system application. + * + * @param packageName The name of the package. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isAppSystem(final String packageName) { + if (isSpace(packageName)) return false; + try { + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + ApplicationInfo ai = pm.getApplicationInfo(packageName, 0); + return ai != null && (ai.flags & ApplicationInfo.FLAG_SYSTEM) != 0; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return false; + } + } + + + /** + * Return whether application is foreground. + *

Target APIs greater than 21 must hold + * {@code }

+ * + * @param packageName The name of the package. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isAppForeground(@NonNull final String packageName) { + return !isSpace(packageName) && packageName.equals(getForegroundProcessName()); + } + + /** + * Launch the application. + * + * @param packageName The name of the package. + */ + public static void launchApp(final String packageName) { + if (isSpace(packageName)) return; + CommonBaseLibrary.getApplication().startActivity(getLaunchAppIntent(packageName, true)); + } + + /** + * Launch the application. + * + * @param activity The activity. + * @param packageName The name of the package. + * @param requestCode If >= 0, this code will be returned in + * onActivityResult() when the activity exits. + */ + public static void launchApp(final Activity activity, + final String packageName, + final int requestCode) { + if (isSpace(packageName)) return; + activity.startActivityForResult(getLaunchAppIntent(packageName), requestCode); + } + + /** + * Relaunch the application. + */ + public static void relaunchApp() { + relaunchApp(false); + } + + /** + * Relaunch the application. + * + * @param isKillProcess True to kill the process, false otherwise. + */ + public static void relaunchApp(final boolean isKillProcess) { + PackageManager packageManager = CommonBaseLibrary.getApplication().getPackageManager(); + Intent intent = packageManager.getLaunchIntentForPackage(CommonBaseLibrary.getApplication().getPackageName()); + if (intent == null) return; + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + CommonBaseLibrary.getApplication().startActivity(intent); + if (!isKillProcess) return; + android.os.Process.killProcess(android.os.Process.myPid()); + System.exit(0); + } + + /** + * Launch the application's details settings. + */ + public static void launchAppDetailsSettings() { + launchAppDetailsSettings(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Launch the application's details settings. + * + * @param packageName The name of the package. + */ + public static void launchAppDetailsSettings(final String packageName) { + if (isSpace(packageName)) return; + Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.parse("package:" + packageName)); + CommonBaseLibrary.getApplication().startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + } + + + /** + * Return the application's icon. + * + * @return the application's icon + */ + public static Drawable getAppIcon() { + return getAppIcon(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Return the application's icon. + * + * @param packageName The name of the package. + * @return the application's icon + */ + public static Drawable getAppIcon(final String packageName) { + if (isSpace(packageName)) return null; + try { + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + PackageInfo pi = pm.getPackageInfo(packageName, 0); + return pi == null ? null : pi.applicationInfo.loadIcon(pm); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return null; + } + } + + /** + * Return the application's package name. + * + * @return the application's package name + */ + public static String getAppPackageName() { + return CommonBaseLibrary.getApplication().getPackageName(); + } + + /** + * Return the application's name. + * + * @return the application's name + */ + public static String getAppName() { + return getAppName(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Return the application's name. + * + * @param packageName The name of the package. + * @return the application's name + */ + public static String getAppName(final String packageName) { + if (isSpace(packageName)) return ""; + try { + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + PackageInfo pi = pm.getPackageInfo(packageName, 0); + return pi == null ? null : pi.applicationInfo.loadLabel(pm).toString(); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return ""; + } + } + + /** + * Return the application's path. + * + * @return the application's path + */ + public static String getAppPath() { + return getAppPath(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Return the application's path. + * + * @param packageName The name of the package. + * @return the application's path + */ + public static String getAppPath(final String packageName) { + if (isSpace(packageName)) return ""; + try { + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + PackageInfo pi = pm.getPackageInfo(packageName, 0); + return pi == null ? null : pi.applicationInfo.sourceDir; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return ""; + } + } + + /** + * Return the application's version name. + * + * @return the application's version name + */ + public static String getAppVersionName() { + return getAppVersionName(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Return the application's version name. + * + * @param packageName The name of the package. + * @return the application's version name + */ + public static String getAppVersionName(final String packageName) { + if (isSpace(packageName)) return ""; + try { + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + PackageInfo pi = pm.getPackageInfo(packageName, 0); + return pi == null ? null : pi.versionName; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return ""; + } + } + + /** + * Return the application's version code. + * + * @return the application's version code + */ + public static int getAppVersionCode() { + return getAppVersionCode(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Return the application's version code. + * + * @param packageName The name of the package. + * @return the application's version code + */ + public static int getAppVersionCode(final String packageName) { + if (isSpace(packageName)) return -1; + try { + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + PackageInfo pi = pm.getPackageInfo(packageName, 0); + return pi == null ? -1 : pi.versionCode; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return -1; + } + } + + /** + * Return the application's signature. + * + * @return the application's signature + */ + public static Signature[] getAppSignature() { + return getAppSignature(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Return the application's signature. + * + * @param packageName The name of the package. + * @return the application's signature + */ + public static Signature[] getAppSignature(final String packageName) { + if (isSpace(packageName)) return null; + try { + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + @SuppressLint("PackageManagerGetSignatures") + PackageInfo pi = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); + return pi == null ? null : pi.signatures; + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return null; + } + } + + /** + * Return the application's signature for SHA1 value. + * + * @return the application's signature for SHA1 value + */ + public static String getAppSignatureSHA1() { + return getAppSignatureSHA1(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Return the application's signature for SHA1 value. + * + * @param packageName The name of the package. + * @return the application's signature for SHA1 value + */ + public static String getAppSignatureSHA1(final String packageName) { + return getAppSignatureHash(packageName, "SHA1"); + } + + /** + * Return the application's signature for SHA256 value. + * + * @return the application's signature for SHA256 value + */ + public static String getAppSignatureSHA256() { + return getAppSignatureSHA256(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Return the application's signature for SHA256 value. + * + * @param packageName The name of the package. + * @return the application's signature for SHA256 value + */ + public static String getAppSignatureSHA256(final String packageName) { + return getAppSignatureHash(packageName, "SHA256"); + } + + /** + * Return the application's signature for MD5 value. + * + * @return the application's signature for MD5 value + */ + public static String getAppSignatureMD5() { + return getAppSignatureMD5(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Return the application's signature for MD5 value. + * + * @param packageName The name of the package. + * @return the application's signature for MD5 value + */ + public static String getAppSignatureMD5(final String packageName) { + return getAppSignatureHash(packageName, "MD5"); + } + + private static String getAppSignatureHash(final String packageName, final String algorithm) { + if (isSpace(packageName)) return ""; + Signature[] signature = getAppSignature(packageName); + if (signature == null || signature.length <= 0) return ""; + return bytes2HexString(hashTemplate(signature[0].toByteArray(), algorithm)) + .replaceAll("(?<=[0-9A-F]{2})[0-9A-F]{2}", ":$0"); + } + + /** + * Return the application's information. + *
    + *
  • name of package
  • + *
  • icon
  • + *
  • name
  • + *
  • path of package
  • + *
  • version name
  • + *
  • version code
  • + *
  • is system
  • + *
+ * + * @return the application's information + */ + public static AppInfo getAppInfo() { + return getAppInfo(CommonBaseLibrary.getApplication().getPackageName()); + } + + /** + * Return the application's information. + *
    + *
  • name of package
  • + *
  • icon
  • + *
  • name
  • + *
  • path of package
  • + *
  • version name
  • + *
  • version code
  • + *
  • is system
  • + *
+ * + * @param packageName The name of the package. + * @return the application's information + */ + public static AppInfo getAppInfo(final String packageName) { + try { + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + PackageInfo pi = pm.getPackageInfo(packageName, 0); + return getBean(pm, pi); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + return null; + } + } + + /** + * Return the applications' information. + * + * @return the applications' information + */ + public static List getAppsInfo() { + List list = new ArrayList<>(); + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + List installedPackages = pm.getInstalledPackages(0); + for (PackageInfo pi : installedPackages) { + AppInfo ai = getBean(pm, pi); + if (ai == null) continue; + list.add(ai); + } + return list; + } + + /** + * Return the application's package information. + * + * @return the application's package information + */ + public static AppInfo getApkInfo(final File apkFile) { + if (apkFile == null || !apkFile.isFile() || !apkFile.exists()) return null; + return getApkInfo(apkFile.getAbsolutePath()); + } + + /** + * Return the application's package information. + * + * @return the application's package information + */ + public static AppInfo getApkInfo(final String apkFilePath) { + if (isSpace(apkFilePath)) return null; + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + PackageInfo pi = pm.getPackageArchiveInfo(apkFilePath, 0); + ApplicationInfo appInfo = pi.applicationInfo; + appInfo.sourceDir = apkFilePath; + return getBean(pm, pi); + } + + private static AppInfo getBean(final PackageManager pm, final PackageInfo pi) { + if (pm == null || pi == null) return null; + ApplicationInfo ai = pi.applicationInfo; + String packageName = pi.packageName; + String name = ai.loadLabel(pm).toString(); + Drawable icon = ai.loadIcon(pm); + String packagePath = ai.sourceDir; + String versionName = pi.versionName; + int versionCode = pi.versionCode; + boolean isSystem = (ApplicationInfo.FLAG_SYSTEM & ai.flags) != 0; + return new AppInfo(packageName, name, icon, packagePath, versionName, versionCode, isSystem); + } + + /** + * The application's information. + */ + public static class AppInfo { + + private String packageName; + private String name; + private Drawable icon; + private String packagePath; + private String versionName; + private int versionCode; + private boolean isSystem; + + public Drawable getIcon() { + return icon; + } + + public void setIcon(final Drawable icon) { + this.icon = icon; + } + + public boolean isSystem() { + return isSystem; + } + + public void setSystem(final boolean isSystem) { + this.isSystem = isSystem; + } + + public String getPackageName() { + return packageName; + } + + public void setPackageName(final String packageName) { + this.packageName = packageName; + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + + public String getPackagePath() { + return packagePath; + } + + public void setPackagePath(final String packagePath) { + this.packagePath = packagePath; + } + + public int getVersionCode() { + return versionCode; + } + + public void setVersionCode(final int versionCode) { + this.versionCode = versionCode; + } + + public String getVersionName() { + return versionName; + } + + public void setVersionName(final String versionName) { + this.versionName = versionName; + } + + public AppInfo(String packageName, String name, Drawable icon, String packagePath, + String versionName, int versionCode, boolean isSystem) { + this.setName(name); + this.setIcon(icon); + this.setPackageName(packageName); + this.setPackagePath(packagePath); + this.setVersionName(versionName); + this.setVersionCode(versionCode); + this.setSystem(isSystem); + } + + @Override + public String toString() { + return "{" + + "\n pkg name: " + getPackageName() + + "\n app icon: " + getIcon() + + "\n app name: " + getName() + + "\n app path: " + getPackagePath() + + "\n app v name: " + getVersionName() + + "\n app v code: " + getVersionCode() + + "\n is system: " + isSystem() + + "}"; + } + } + + /////////////////////////////////////////////////////////////////////////// + // other utils methods + /////////////////////////////////////////////////////////////////////////// + + private static boolean isFileExists(final File file) { + return file != null && file.exists(); + } + + private static File getFileByPath(final String filePath) { + return isSpace(filePath) ? null : new File(filePath); + } + + private static boolean isSpace(final String s) { + if (s == null) return true; + for (int i = 0, len = s.length(); i < len; ++i) { + if (!Character.isWhitespace(s.charAt(i))) { + return false; + } + } + return true; + } + + private static boolean isDeviceRooted() { + String su = "su"; + String[] locations = {"/system/bin/", "/system/xbin/", "/sbin/", "/system/sd/xbin/", + "/system/bin/failsafe/", "/data/local/xbin/", "/data/local/bin/", "/data/local/", + "/system/sbin/", "/usr/bin/", "/vendor/bin/"}; + for (String location : locations) { + if (new File(location + su).exists()) { + return true; + } + } + return false; + } + + private static final char HEX_DIGITS[] = + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + + private static byte[] hashTemplate(final byte[] data, final String algorithm) { + if (data == null || data.length <= 0) return null; + try { + MessageDigest md = MessageDigest.getInstance(algorithm); + md.update(data); + return md.digest(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + return null; + } + } + + private static String bytes2HexString(final byte[] bytes) { + if (bytes == null) return ""; + int len = bytes.length; + if (len <= 0) return ""; + char[] ret = new char[len << 1]; + for (int i = 0, j = 0; i < len; i++) { + ret[j++] = HEX_DIGITS[bytes[i] >> 4 & 0x0f]; + ret[j++] = HEX_DIGITS[bytes[i] & 0x0f]; + } + return new String(ret); + } + + private static Intent getInstallAppIntent(final File file) { + return getInstallAppIntent(file, false); + } + + private static Intent getInstallAppIntent(final File file, final boolean isNewTask) { + Intent intent = new Intent(Intent.ACTION_VIEW); + Uri data; + String type = "application/vnd.android.package-archive"; + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { + data = Uri.fromFile(file); + } else { + String authority = CommonBaseLibrary.getApplication().getPackageName() + ".utilcode.provider"; + data = FileProvider.getUriForFile(CommonBaseLibrary.getApplication(), authority, file); + intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } + CommonBaseLibrary.getApplication().grantUriPermission(CommonBaseLibrary.getApplication().getPackageName(), data, Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.setDataAndType(data, type); + return isNewTask ? intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) : intent; + } + + private static Intent getUninstallAppIntent(final String packageName) { + return getUninstallAppIntent(packageName, false); + } + + private static Intent getUninstallAppIntent(final String packageName, final boolean isNewTask) { + Intent intent = new Intent(Intent.ACTION_DELETE); + intent.setData(Uri.parse("package:" + packageName)); + return isNewTask ? intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) : intent; + } + + private static Intent getLaunchAppIntent(final String packageName) { + return getLaunchAppIntent(packageName, false); + } + + private static Intent getLaunchAppIntent(final String packageName, final boolean isNewTask) { + Intent intent = CommonBaseLibrary.getApplication().getPackageManager().getLaunchIntentForPackage(packageName); + if (intent == null) return null; + return isNewTask ? intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) : intent; + } + + private static String getForegroundProcessName() { + ActivityManager am = + (ActivityManager) CommonBaseLibrary.getApplication().getSystemService(Context.ACTIVITY_SERVICE); + //noinspection ConstantConditions + List pInfo = am.getRunningAppProcesses(); + if (pInfo != null && pInfo.size() > 0) { + for (ActivityManager.RunningAppProcessInfo aInfo : pInfo) { + if (aInfo.importance + == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { + return aInfo.processName; + } + } + } + if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) { + PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager(); + Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS); + List list = + pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); + Log.i("ProcessUtils", list.toString()); + if (list.size() <= 0) { + Log.i("ProcessUtils", + "getForegroundProcessName: noun of access to usage information."); + return ""; + } + try {// Access to usage information. + ApplicationInfo info = + pm.getApplicationInfo(CommonBaseLibrary.getApplication().getPackageName(), 0); + AppOpsManager aom = + (AppOpsManager) CommonBaseLibrary.getApplication().getSystemService(Context.APP_OPS_SERVICE); + //noinspection ConstantConditions + if (aom.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, + info.uid, + info.packageName) != AppOpsManager.MODE_ALLOWED) { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + CommonBaseLibrary.getApplication().startActivity(intent); + } + if (aom.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, + info.uid, + info.packageName) != AppOpsManager.MODE_ALLOWED) { + Log.i("ProcessUtils", + "getForegroundProcessName: refuse to device usage stats."); + return ""; + } + UsageStatsManager usageStatsManager = (UsageStatsManager) CommonBaseLibrary.getApplication() + .getSystemService(Context.USAGE_STATS_SERVICE); + List usageStatsList = null; + if (usageStatsManager != null) { + long endTime = System.currentTimeMillis(); + long beginTime = endTime - 86400000 * 7; + usageStatsList = usageStatsManager + .queryUsageStats(UsageStatsManager.INTERVAL_BEST, + beginTime, endTime); + } + if (usageStatsList == null || usageStatsList.isEmpty()) return null; + UsageStats recentStats = null; + for (UsageStats usageStats : usageStatsList) { + if (recentStats == null + || usageStats.getLastTimeUsed() > recentStats.getLastTimeUsed()) { + recentStats = usageStats; + } + } + return recentStats == null ? null : recentStats.getPackageName(); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } + } + return ""; + } +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/BarUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/BarUtils.java new file mode 100644 index 0000000..30ccf39 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/BarUtils.java @@ -0,0 +1,678 @@ +package com.dahe.mylibrary.utils; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Context; +import android.content.ContextWrapper; +import android.content.res.Resources; +import android.graphics.Color; +import android.graphics.Point; +import android.os.Build; +import android.util.Log; +import android.util.TypedValue; +import android.view.Display; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.ViewGroup; +import android.view.ViewGroup.MarginLayoutParams; +import android.view.Window; +import android.view.WindowManager; + +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; +import androidx.annotation.RequiresPermission; +import androidx.drawerlayout.widget.DrawerLayout; + + +import com.dahe.mylibrary.CommonBaseLibrary; + +import java.lang.reflect.Method; + +import static android.Manifest.permission.EXPAND_STATUS_BAR; + +/** + * getStatusBarHeight : 获取状态栏高度(px) + * setStatusBarVisibility : 设置状态栏是否可见 + * isStatusBarVisible : 判断状态栏是否可见 + * setStatusBarLightMode : 设置状态栏是否为浅色模式 + * addMarginTopEqualStatusBarHeight : 为 view 增加 MarginTop 为状态栏高度 + * subtractMarginTopEqualStatusBarHeight: 为 view 减少 MarginTop 为状态栏高度 + * setStatusBarColor : 设置状态栏颜色 + * setStatusBarColor4Drawer : 为 DrawerLayout 设置状态栏颜色 + * getActionBarHeight : 获取 ActionBar 高度 + * setNotificationBarVisibility : 设置通知栏是否可见 + * getNavBarHeight : 获取导航栏高度 + * setNavBarVisibility : 设置导航栏是否可见 + * isNavBarVisible : 判断导航栏是否可见 + * setNavBarColor : 设置导航栏颜色 + * getNavBarColor : 获取导航栏颜色 + * isSupportNavBar : 判断是否支持导航栏 + */ +public final class BarUtils { + + /////////////////////////////////////////////////////////////////////////// + // status bar + /////////////////////////////////////////////////////////////////////////// + + private static final String TAG_STATUS_BAR = "TAG_STATUS_BAR"; + private static final String TAG_OFFSET = "TAG_OFFSET"; + private static final int KEY_OFFSET = -123; + + private BarUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + /** + * Return the status bar's height. + * + * @return the status bar's height + */ + public static int getStatusBarHeight() { + Resources resources = Resources.getSystem(); + int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android"); + return resources.getDimensionPixelSize(resourceId); + } + + /** + * Set the status bar's visibility. + * + * @param activity The activity. + * @param isVisible True to set status bar visible, false otherwise. + */ + public static void setStatusBarVisibility(@NonNull final Activity activity, + final boolean isVisible) { + setStatusBarVisibility(activity.getWindow(), isVisible); + } + + /** + * Set the status bar's visibility. + * + * @param window The window. + * @param isVisible True to set status bar visible, false otherwise. + */ + public static void setStatusBarVisibility(@NonNull final Window window, + final boolean isVisible) { + if (isVisible) { + window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + showStatusBarView(window); + addMarginTopEqualStatusBarHeight(window); + } else { + window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); + hideStatusBarView(window); + subtractMarginTopEqualStatusBarHeight(window); + } + } + + /** + * Return whether the status bar is visible. + * + * @param activity The activity. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isStatusBarVisible(@NonNull final Activity activity) { + int flags = activity.getWindow().getAttributes().flags; + return (flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) == 0; + } + + /** + * Set the status bar's light mode. + * + * @param activity The activity. + * @param isLightMode True to set status bar light mode, false otherwise. + */ + public static void setStatusBarLightMode(@NonNull final Activity activity, + final boolean isLightMode) { + setStatusBarLightMode(activity.getWindow(), isLightMode); + } + + /** + * Set the status bar's light mode. + * + * @param window The window. + * @param isLightMode True to set status bar light mode, false otherwise. + */ + public static void setStatusBarLightMode(@NonNull final Window window, + final boolean isLightMode) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + View decorView = window.getDecorView(); + if (decorView != null) { + int vis = decorView.getSystemUiVisibility(); + if (isLightMode) { + vis |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; + } else { + vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR; + } + decorView.setSystemUiVisibility(vis); + } + } + } + + /** + * Is the status bar light mode. + * + * @param activity The activity. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isStatusBarLightMode(@NonNull final Activity activity) { + return isStatusBarLightMode(activity.getWindow()); + } + + /** + * Is the status bar light mode. + * + * @param window The window. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isStatusBarLightMode(@NonNull final Window window) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + View decorView = window.getDecorView(); + if (decorView != null) { + int vis = decorView.getSystemUiVisibility(); + return (vis & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0; + } + } + return false; + } + + /** + * Add the top margin size equals status bar's height for view. + * + * @param view The view. + */ + public static void addMarginTopEqualStatusBarHeight(@NonNull View view) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + view.setTag(TAG_OFFSET); + Object haveSetOffset = view.getTag(KEY_OFFSET); + if (haveSetOffset != null && (Boolean) haveSetOffset) return; + MarginLayoutParams layoutParams = (MarginLayoutParams) view.getLayoutParams(); + layoutParams.setMargins(layoutParams.leftMargin, + layoutParams.topMargin + getStatusBarHeight(), + layoutParams.rightMargin, + layoutParams.bottomMargin); + view.setTag(KEY_OFFSET, true); + } + + /** + * Subtract the top margin size equals status bar's height for view. + * + * @param view The view. + */ + public static void subtractMarginTopEqualStatusBarHeight(@NonNull View view) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + Object haveSetOffset = view.getTag(KEY_OFFSET); + if (haveSetOffset == null || !(Boolean) haveSetOffset) return; + MarginLayoutParams layoutParams = (MarginLayoutParams) view.getLayoutParams(); + layoutParams.setMargins(layoutParams.leftMargin, + layoutParams.topMargin - getStatusBarHeight(), + layoutParams.rightMargin, + layoutParams.bottomMargin); + view.setTag(KEY_OFFSET, false); + } + + private static void addMarginTopEqualStatusBarHeight(final Window window) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + View withTag = window.getDecorView().findViewWithTag(TAG_OFFSET); + if (withTag == null) return; + addMarginTopEqualStatusBarHeight(withTag); + } + + private static void subtractMarginTopEqualStatusBarHeight(final Window window) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + View withTag = window.getDecorView().findViewWithTag(TAG_OFFSET); + if (withTag == null) return; + subtractMarginTopEqualStatusBarHeight(withTag); + } + + /** + * Set the status bar's color. + * + * @param activity The activity. + * @param color The status bar's color. + */ + public static View setStatusBarColor(@NonNull final Activity activity, + @ColorInt final int color) { + return setStatusBarColor(activity, color, false); + } + + /** + * Set the status bar's color. + * + * @param activity The activity. + * @param color The status bar's color. + * @param isDecor True to add fake status bar in DecorView, + * false to add fake status bar in ContentView. + */ + public static View setStatusBarColor(@NonNull final Activity activity, + @ColorInt final int color, + final boolean isDecor) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return null; + transparentStatusBar(activity); + return applyStatusBarColor(activity, color, isDecor); + } + + /** + * Set the status bar's color. + * + * @param fakeStatusBar The fake status bar view. + * @param color The status bar's color. + */ + public static void setStatusBarColor(@NonNull final View fakeStatusBar, + @ColorInt final int color) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + Activity activity = getActivityByView(fakeStatusBar); + if (activity == null) return; + transparentStatusBar(activity); + fakeStatusBar.setVisibility(View.VISIBLE); + ViewGroup.LayoutParams layoutParams = fakeStatusBar.getLayoutParams(); + layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT; + layoutParams.height = getStatusBarHeight(); + fakeStatusBar.setBackgroundColor(color); + } + + /** + * Set the custom status bar. + * + * @param fakeStatusBar The fake status bar view. + */ + public static void setStatusBarCustom(@NonNull final View fakeStatusBar) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + Activity activity = getActivityByView(fakeStatusBar); + if (activity == null) return; + transparentStatusBar(activity); + fakeStatusBar.setVisibility(View.VISIBLE); + ViewGroup.LayoutParams layoutParams = fakeStatusBar.getLayoutParams(); + if (layoutParams == null) { + layoutParams = new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, + getStatusBarHeight() + ); + fakeStatusBar.setLayoutParams(layoutParams); + } else { + layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT; + layoutParams.height = getStatusBarHeight(); + } + } + + /** + * Set the status bar's color for DrawerLayout. + *

DrawLayout must add {@code android:fitsSystemWindows="true"}

+ * + * @param drawer The DrawLayout. + * @param fakeStatusBar The fake status bar view. + * @param color The status bar's color. + */ + public static void setStatusBarColor4Drawer(@NonNull final DrawerLayout drawer, + @NonNull final View fakeStatusBar, + @ColorInt final int color) { + setStatusBarColor4Drawer(drawer, fakeStatusBar, color, false); + } + + /** + * Set the status bar's color for DrawerLayout. + *

DrawLayout must add {@code android:fitsSystemWindows="true"}

+ * + * @param drawer The DrawLayout. + * @param fakeStatusBar The fake status bar view. + * @param color The status bar's color. + * @param isTop True to set DrawerLayout at the top layer, false otherwise. + */ + public static void setStatusBarColor4Drawer(@NonNull final DrawerLayout drawer, + @NonNull final View fakeStatusBar, + @ColorInt final int color, + final boolean isTop) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + Activity activity = getActivityByView(fakeStatusBar); + if (activity == null) return; + transparentStatusBar(activity); + drawer.setFitsSystemWindows(false); + setStatusBarColor(fakeStatusBar, color); + for (int i = 0, count = drawer.getChildCount(); i < count; i++) { + drawer.getChildAt(i).setFitsSystemWindows(false); + } + if (isTop) { + hideStatusBarView(activity); + } else { + setStatusBarColor(activity, color, false); + } + } + + private static View applyStatusBarColor(final Activity activity, + final int color, + boolean isDecor) { + ViewGroup parent = isDecor ? + (ViewGroup) activity.getWindow().getDecorView() : + (ViewGroup) activity.findViewById(android.R.id.content); + View fakeStatusBarView = parent.findViewWithTag(TAG_STATUS_BAR); + if (fakeStatusBarView != null) { + if (fakeStatusBarView.getVisibility() == View.GONE) { + fakeStatusBarView.setVisibility(View.VISIBLE); + } + fakeStatusBarView.setBackgroundColor(color); + } else { + fakeStatusBarView = createStatusBarView(activity, color); + parent.addView(fakeStatusBarView); + } + return fakeStatusBarView; + } + + private static void hideStatusBarView(final Activity activity) { + hideStatusBarView(activity.getWindow()); + } + + private static void hideStatusBarView(final Window window) { + ViewGroup decorView = (ViewGroup) window.getDecorView(); + View fakeStatusBarView = decorView.findViewWithTag(TAG_STATUS_BAR); + if (fakeStatusBarView == null) return; + fakeStatusBarView.setVisibility(View.GONE); + } + + private static void showStatusBarView(final Window window) { + ViewGroup decorView = (ViewGroup) window.getDecorView(); + View fakeStatusBarView = decorView.findViewWithTag(TAG_STATUS_BAR); + if (fakeStatusBarView == null) return; + fakeStatusBarView.setVisibility(View.VISIBLE); + } + + private static View createStatusBarView(final Activity activity, + final int color) { + View statusBarView = new View(activity); + statusBarView.setLayoutParams(new ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight())); + statusBarView.setBackgroundColor(color); + statusBarView.setTag(TAG_STATUS_BAR); + return statusBarView; + } + + private static void transparentStatusBar(final Activity activity) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + Window window = activity.getWindow(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + int option = View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN; + window.getDecorView().setSystemUiVisibility(option); + window.setStatusBarColor(Color.TRANSPARENT); + } else { + window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + } + } + + /////////////////////////////////////////////////////////////////////////// + // action bar + /////////////////////////////////////////////////////////////////////////// + + /** + * Return the action bar's height. + * + * @return the action bar's height + */ + public static int getActionBarHeight() { + TypedValue tv = new TypedValue(); + if (CommonBaseLibrary.getApplication().getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) { + return TypedValue.complexToDimensionPixelSize( + tv.data, CommonBaseLibrary.getApplication().getResources().getDisplayMetrics() + ); + } + return 0; + } + + /////////////////////////////////////////////////////////////////////////// + // notification bar + /////////////////////////////////////////////////////////////////////////// + + /** + * Set the notification bar's visibility. + *

Must hold {@code }

+ * + * @param isVisible True to set notification bar visible, false otherwise. + */ + @RequiresPermission(EXPAND_STATUS_BAR) + public static void setNotificationBarVisibility(final boolean isVisible) { + String methodName; + if (isVisible) { + methodName = (Build.VERSION.SDK_INT <= 16) ? "expand" : "expandNotificationsPanel"; + } else { + methodName = (Build.VERSION.SDK_INT <= 16) ? "collapse" : "collapsePanels"; + } + invokePanels(methodName); + } + + private static void invokePanels(final String methodName) { + try { + @SuppressLint("WrongConstant") + Object service = CommonBaseLibrary.getApplication().getSystemService("statusbar"); + @SuppressLint("PrivateApi") + Class statusBarManager = Class.forName("android.app.StatusBarManager"); + Method expand = statusBarManager.getMethod(methodName); + expand.invoke(service); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /////////////////////////////////////////////////////////////////////////// + // navigation bar + /////////////////////////////////////////////////////////////////////////// + + /** + * Return the navigation bar's height. + * + * @return the navigation bar's height + */ + public static int getNavBarHeight() { + Resources res = Resources.getSystem(); + int resourceId = res.getIdentifier("navigation_bar_height", "dimen", "android"); + if (resourceId != 0) { + return res.getDimensionPixelSize(resourceId); + } else { + return 0; + } + } + + /** + * Set the navigation bar's visibility. + * + * @param activity The activity. + * @param isVisible True to set navigation bar visible, false otherwise. + */ + public static void setNavBarVisibility(@NonNull final Activity activity, boolean isVisible) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + setNavBarVisibility(activity.getWindow(), isVisible); + + } + + /** + * Set the navigation bar's visibility. + * + * @param window The window. + * @param isVisible True to set navigation bar visible, false otherwise. + */ + public static void setNavBarVisibility(@NonNull final Window window, boolean isVisible) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return; + final ViewGroup decorView = (ViewGroup) window.getDecorView(); + for (int i = 0, count = decorView.getChildCount(); i < count; i++) { + final View child = decorView.getChildAt(i); + final int id = child.getId(); + if (id != View.NO_ID) { + String resourceEntryName = CommonBaseLibrary.getApplication() + .getResources() + .getResourceEntryName(id); + if ("navigationBarBackground".equals(resourceEntryName)) { + child.setVisibility(isVisible ? View.VISIBLE : View.INVISIBLE); + } + } + } + final int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; + if (isVisible) { + decorView.setSystemUiVisibility(decorView.getSystemUiVisibility() & ~uiOptions); + } else { + decorView.setSystemUiVisibility(decorView.getSystemUiVisibility() | uiOptions); + } + } + + /** + * Return whether the navigation bar visible. + *

Call it in onWindowFocusChanged will get right result.

+ * + * @param activity The activity. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isNavBarVisible(@NonNull final Activity activity) { + return isNavBarVisible(activity.getWindow()); + } + + + + /** + * 判断是否显示了导航栏 + * (说明这里的context 一定要是activity的context 否则类型转换失败) + * + * @param context + * @return + */ +// public static boolean isShowNavBar(Context context) { +// if (null == context) { +// node_return false; +// } +// /** +// * 获取应用区域高度 +// */ +// Rect outRect1 = new Rect(); +// try { +// ((Activity) context).getWindow().getDecorView().getWindowVisibleDisplayFrame(outRect1); +// } catch (ClassCastException e) { +// e.printStackTrace(); +// node_return false; +// } +// int activityHeight = outRect1.height(); +// /** +// * 获取状态栏高度 +// */ +// int statuBarHeight = WindowDispaly.getStatusBarHeight(); +// /** +// * 屏幕物理高度 减去 状态栏高度 +// */ +// int remainHeight = WindowDispaly.getRealHeight() - statuBarHeight; +// /** +// * 剩余高度跟应用区域高度相等 说明导航栏没有显示 否则相反 +// */ +// if (activityHeight == remainHeight) { +// node_return false; +// } else { +// node_return true; +// } +// +// } + + /** + * Return whether the navigation bar visible. + *

Call it in onWindowFocusChanged will get right result.

+ * + * @param window The window. + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isNavBarVisible(@NonNull final Window window) { + boolean isVisible = false; + ViewGroup decorView = (ViewGroup) window.getDecorView(); + for (int i = 0, count = decorView.getChildCount(); i < count; i++) { + final View child = decorView.getChildAt(i); + final int id = child.getId(); + if (id != View.NO_ID) { + String resourceEntryName = CommonBaseLibrary.getApplication() + .getResources() + .getResourceEntryName(id); + if ("navigationBarBackground".equals(resourceEntryName) + && child.getVisibility() == View.VISIBLE) { + isVisible = true; + break; + } + } + } + if (isVisible) { + int visibility = decorView.getSystemUiVisibility(); + isVisible = (visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0; + } + return isVisible; + } + + /** + * Set the navigation bar's color. + * + * @param activity The activity. + * @param color The navigation bar's color. + */ + @RequiresApi(Build.VERSION_CODES.LOLLIPOP) + public static void setNavBarColor(@NonNull final Activity activity, @ColorInt final int color) { + setNavBarColor(activity.getWindow(), color); + } + + /** + * Set the navigation bar's color. + * + * @param window The window. + * @param color The navigation bar's color. + */ + @RequiresApi(Build.VERSION_CODES.LOLLIPOP) + public static void setNavBarColor(@NonNull final Window window, @ColorInt final int color) { + window.setNavigationBarColor(color); + } + + /** + * Return the color of navigation bar. + * + * @param activity The activity. + * @return the color of navigation bar + */ + @RequiresApi(Build.VERSION_CODES.LOLLIPOP) + public static int getNavBarColor(@NonNull final Activity activity) { + return getNavBarColor(activity.getWindow()); + } + + /** + * Return the color of navigation bar. + * + * @param window The window. + * @return the color of navigation bar + */ + @RequiresApi(Build.VERSION_CODES.LOLLIPOP) + public static int getNavBarColor(@NonNull final Window window) { + return window.getNavigationBarColor(); + } + + /** + * Return whether the navigation bar visible. + * + * @return {@code true}: yes
{@code false}: no + */ + public static boolean isSupportNavBar() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + WindowManager wm = (WindowManager) CommonBaseLibrary.getApplication().getSystemService(Context.WINDOW_SERVICE); + if (wm == null) return false; + Display display = wm.getDefaultDisplay(); + Point size = new Point(); + Point realSize = new Point(); + display.getSize(size); + display.getRealSize(realSize); + return realSize.y != size.y || realSize.x != size.x; + } + boolean menu = ViewConfiguration.get(CommonBaseLibrary.getApplication()).hasPermanentMenuKey(); + boolean back = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK); + return !menu && !back; + } + + private static Activity getActivityByView(@NonNull final View view) { + Context context = view.getContext(); + while (context instanceof ContextWrapper) { + if (context instanceof Activity) { + return (Activity) context; + } + context = ((ContextWrapper) context).getBaseContext(); + } + Log.e("BarUtils", "the view's Context is not an Activity."); + return null; + } +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/Base64Utils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/Base64Utils.java new file mode 100644 index 0000000..8278fda --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/Base64Utils.java @@ -0,0 +1,13 @@ +package com.dahe.mylibrary.utils; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.util.Base64; + +public class Base64Utils { + + public static Bitmap asdf(String imageBase64){ + byte[] decodedString = Base64.decode(imageBase64, Base64.DEFAULT); + return BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/BaseSPUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/BaseSPUtils.java new file mode 100644 index 0000000..9450e59 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/BaseSPUtils.java @@ -0,0 +1,193 @@ +package com.dahe.mylibrary.utils; + +import android.content.Context; +import android.content.SharedPreferences; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Map; + +/** + * 轻量级数据存储工具类 + * + * @author Administrator + */ +public class BaseSPUtils { + /** + * 保存在手机里面的文件名 + */ + public static final String FILE_NAME = "sp_data"; + public static final String USER_INFO_KEY = "user_info_key"; + public static final String NET_SERVICE_TEST = "net_service_test"; + public static final String SEARRH_CACHE = "search_cache"; + public static final String NAVI_PH_EDIT_CACHE = "navi_ph_edit_cache"; + public static final String FIRST_OPEN = "first_open"; + public static final String KEY_PRIVACY_AGREEMENT = "privacy_agreement"; + + /** + * 保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法 + * + * @param context + * @param key + * @param object + */ + public static void put(Context context, String key, Object object) { + SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sp.edit(); + if (object instanceof String) { + editor.putString(key, (String) object); + } else if (object instanceof Integer) { + editor.putInt(key, (Integer) object); + } else if (object instanceof Boolean) { + editor.putBoolean(key, (Boolean) object); + } else if (object instanceof Float) { + editor.putFloat(key, (Float) object); + } else if (object instanceof Long) { + editor.putLong(key, (Long) object); + } else { + editor.putString(key, object.toString()); + } + + SharedPreferencesCompat.apply(editor); + } + + /** + * 得到保存数据的方法,我们根据默认值得到保存的数据的具体类型,然后调用相对于的方法获取值 + * + * @param context + * @param key + * @param defaultObject + * @return + */ + public static Object get(Context context, String key, Object defaultObject) { + SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); + + if (defaultObject instanceof String) { + return sp.getString(key, (String) defaultObject); + } else if (defaultObject instanceof Integer) { + return sp.getInt(key, (Integer) defaultObject); + } else if (defaultObject instanceof Boolean) { + return sp.getBoolean(key, (Boolean) defaultObject); + } else if (defaultObject instanceof Float) { + return sp.getFloat(key, (Float) defaultObject); + } else if (defaultObject instanceof Long) { + return sp.getLong(key, (Long) defaultObject); + } + + return null; + } + + /** + * 移除某个key值已经对应的值 + * + * @param context + * @param key + */ + public static void remove(Context context, String key) { + SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sp.edit(); + editor.remove(key); + SharedPreferencesCompat.apply(editor); + } + + /** + * 清除所有数据 + * + * @param context + */ + public static void clear(Context context) { + SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sp.edit(); + editor.clear(); + SharedPreferencesCompat.apply(editor); + } + + /** + * 查询某个key是否已经存在 + * + * @param context + * @param key + * @return + */ + public static boolean contains(Context context, String key) { + SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); + return sp.contains(key); + } + + /** + * 返回所有的键值对 + * + * @param context + * @return + */ + public static Map getAll(Context context) { + SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE); + return sp.getAll(); + } + + /** + * 创建一个解决SharedPreferencesCompat.apply方法的一个兼容类 + * + * @author zhy + */ + private static class SharedPreferencesCompat { + private static final Method sApplyMethod = findApplyMethod(); + + /** + * 反射查找apply的方法 + * + * @return + */ + @SuppressWarnings( + {"unchecked", "rawtypes"}) + private static Method findApplyMethod() { + try { + Class clz = SharedPreferences.Editor.class; + return clz.getMethod("apply"); + } catch (NoSuchMethodException e) { + } + + return null; + } + + /** + * 如果找到则使用apply执行,否则使用commit + * + * @param editor + */ + public static void apply(SharedPreferences.Editor editor) { + try { + if (sApplyMethod != null) { + sApplyMethod.invoke(editor); + return; + } + } catch (IllegalArgumentException e) { + } catch (IllegalAccessException e) { + } catch (InvocationTargetException e) { + } + editor.commit(); + } + } + + /*****---------------------------------------------***/ + /** + * 是否含有用户信息 + * + * @param context + * @return + */ + public static boolean hasUserInfo(Context context) { + return contains(context, USER_INFO_KEY); + } + + /** + * 清除用户信息 + * + * @param context + * @return + */ + public static void cleanUserInfo(Context context) { + remove(context, USER_INFO_KEY); + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/BaseUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/BaseUtils.java new file mode 100644 index 0000000..da2d6de --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/BaseUtils.java @@ -0,0 +1,243 @@ +package com.dahe.mylibrary.utils; + +import android.app.Activity; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.database.Cursor; +import android.net.Uri; +import android.os.Build; +import android.provider.ContactsContract; +import android.text.TextUtils; +import android.view.View; +import android.view.inputmethod.InputMethodManager; + +import androidx.appcompat.app.AppCompatActivity; + +import com.dahe.mylibrary.R; +import com.shehuan.nicedialog.BaseNiceDialog; +import com.shehuan.nicedialog.NiceDialog; +import com.shehuan.nicedialog.ViewConvertListener; +import com.shehuan.nicedialog.ViewHolder; + +import java.util.Locale; + +public class BaseUtils { + /** + * 验证手机格式 + */ + public static boolean isMobileNO(String mobiles) { + String telRegex = "[1][3456789]\\d{9}"; + // "[1]"代表第1位为数字1,"[358]"代表第二位可以为3、5、8中的一个,"\\d{9}"代表后面是可以是0~9的数字,有9位。 + if (TextUtils.isEmpty(mobiles)) return false; + else return mobiles.matches(telRegex); + } + + + /** + * 获取语言 + * + * @param context + * @return + */ + public static int getLanguage(Context context) { + Locale curLocale = getLocale(context); + String language = curLocale.getLanguage(); + String country = curLocale.getCountry(); + if (language.equals(Locale.CHINA.getLanguage())) { + //0是简体中文,1是繁体中文 + return country.equals(Locale.SIMPLIFIED_CHINESE.getCountry()) ? 0 : 1; + } else if (language.equals(Locale.ENGLISH.getLanguage())) { + //英语 + return 2; + } else if (language.equals("th")) { + //泰文 + return 3; + } else if (language.equals(Locale.KOREAN.getLanguage())) { + //韩文 + return 4; + } else if (language.equals("vi")) { + //越南语 + return 5; + } else if (language.equals(Locale.JAPAN.getLanguage())) { + //日语 + return 6; + } else if (language.equals("in")) { + //印尼语 + return 7; + } else { + return 2; + } + } + + //获取Locale + private static Locale getLocale(Context context) { + Locale locale; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + locale = context.getResources().getConfiguration().getLocales().get(0); + } else { + locale = context.getResources().getConfiguration().locale; + } + return locale; + } + + + /** + * 拨打电话(直接拨打电话) + * @param phoneNum 电话号码 + */ + public static void callPhone(AppCompatActivity context , String phoneNum){ + + NiceDialog.init() + .setLayoutId(R.layout.dialog_phone) + .setConvertListener(new ViewConvertListener() { + @Override + protected void convertView(ViewHolder viewHolder, BaseNiceDialog baseNiceDialog) { + viewHolder.setText(R.id.message, phoneNum); + viewHolder.setOnClickListener(R.id.ok, new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(Intent.ACTION_CALL); + Uri data = Uri.parse("tel:" + phoneNum); + intent.setData(data); + context.startActivity(intent); + baseNiceDialog.dismiss(); + } + }); + viewHolder.setOnClickListener(R.id.cancel, new View.OnClickListener() { + @Override + public void onClick(View v) { + baseNiceDialog.dismiss(); + } + }); + } + }) + .setWidth(260).show(context.getSupportFragmentManager()); + + } + + /** + * 获取VersionCode + * + * @param context + * @return + */ + public static String geVersionCode(Context context) { + try { + PackageInfo packageInfo = context.getPackageManager() + .getPackageInfo(context.getPackageName(), 0); + return packageInfo.versionName; + } catch (Exception e) { + return "1.0.0"; + } + } + + /** + * 跳转qq + * + * @param context + * @return + */ + public static String goToQQ(Context context, String qqNumber) { + try { + context.getPackageManager().getApplicationInfo("com.tencent.mobileqq", + PackageManager.GET_UNINSTALLED_PACKAGES); + context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("mqqwpa://im/chat?chat_type=wpa&uin=" + qqNumber + "&version=1"))); + } catch (PackageManager.NameNotFoundException e) { + return "客服为qq在线,联系客服请先安装qq"; + } + return ""; + } + + /** + * 跳转手机通讯录 选择联系人 并返回联系人信息 + * + * @param context + * @param uri + * @return + */ + public static String[] getPhoneContacts(Context context, Uri uri) { + String[] contact = new String[2]; + ContentResolver cr = context.getContentResolver(); + Cursor cursor = cr.query(uri, null, null, null, null); + if (cursor != null && cursor.getCount() != 0) { + cursor.moveToFirst(); + int nameFieldColumnIndex = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME); + contact[0] = cursor.getString(nameFieldColumnIndex); + String ContactId = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID)); + Cursor phone = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, + ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + ContactId, null, null); + if (phone != null && phone.getCount() != 0) { + phone.moveToFirst(); + contact[1] = phone.getString(phone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)).trim().replace(" ", "").toString(); + } else { + contact[1] = ""; + } + phone.close(); + cursor.close(); + } else { + return null; + } + return contact; + } + + /** + * 根据手机的分辨率从 dp 的单位 转成为 px(像素) + */ + public static int dip2px(Context context, float dpValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (dpValue * scale + 0.5f); + } + + /** + * 根据手机的分辨率从 px(像素) 的单位 转成为 dp + */ + public static int px2dip(Context context, float pxValue) { + final float scale = context.getResources().getDisplayMetrics().density; + return (int) (pxValue / scale + 0.5f); + } + + /** + * 将sp值转换为px值,保证文字大小不变 + * + * @param spValue + * @param spValue (DisplayMetrics类中属性scaledDensity) + * @return + */ + public static int sp2px(Context context, float spValue) { + final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; + return (int) (spValue * fontScale + 0.5f); + } + + /** + * 强制隐藏输入法键盘 + * + * @param context Context + * @param view EditText + */ + public static void hideInput(Context context, View view) { + InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); + inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0); + } + + /** + * 隐藏软键盘(只适用于Activity,不适用于Fragment) + */ + public static void hideSoftKeyboard(Activity activity) { + View view = activity.getCurrentFocus(); + if (view != null) { + InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE); + inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); + } + } + + //view为接受软键盘输入的视图,SHOW_FORCED表示强制显示 + public static void hideSoftKeyboard(Activity activity, View view) { + InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); + imm.showSoftInput(view, InputMethodManager.SHOW_FORCED); + imm.hideSoftInputFromWindow(view.getWindowToken(), 0); //强制隐藏键盘 + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/CNPinyinIndex.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/CNPinyinIndex.java new file mode 100644 index 0000000..d55d146 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/CNPinyinIndex.java @@ -0,0 +1,76 @@ +package com.dahe.mylibrary.utils; + +import java.io.UnsupportedEncodingException; + +public class CNPinyinIndex { + + + //自动获取汉子的首字母 + static final int GB_SP_DIFF = 160; + // 存放国标一级汉字不同读音的起始区位码 + static final int[] secPosValueList = {1601, 1637, 1833, 2078, 2274, 2302, + 2433, 2594, 2787, 3106, 3212, 3472, 3635, 3722, 3730, 3858, 4027, + 4086, 4390, 4558, 4684, 4925, 5249, 5600}; + // 存放国标一级汉字不同读音的起始区位码对应读音 + static final char[] firstLetter = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', + 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'w', 'x', + 'y', 'z'}; + + + + public static String getSpells(String characters) { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < characters.length(); i++) { + + char ch = characters.charAt(i); + if ((ch >> 7) == 0) { + // 判断是否为汉字,如果左移7为为0就不是汉字,否则是汉字 + } else { + char spell = getFirstLetter(ch); + buffer.append(String.valueOf(spell)); + } + } + return buffer.toString(); + } + + // 获取一个汉字的首字母 + public static Character getFirstLetter(char ch) { + + byte[] uniCode = null; + try { + uniCode = String.valueOf(ch).getBytes("GBK"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + return null; + } + if (uniCode[0] < 128 && uniCode[0] > 0) { // 非汉字 + return null; + } else { + return convert(uniCode); + } + } + + /** + * 获取一个汉字的拼音首字母。 GB码两个字节分别减去160,转换成10进制码组合就可以得到区位码 + * 例如汉字“你”的GB码是0xC4/0xE3,分别减去0xA0(160)就是0x24/0x43 + * 0x24转成10进制就是36,0x43是67,那么它的区位码就是3667,在对照表中读音为‘n’ + */ + static char convert(byte[] bytes) { + char result = '-'; + int secPosValue = 0; + int i; + for (i = 0; i < bytes.length; i++) { + bytes[i] -= GB_SP_DIFF; + } + secPosValue = bytes[0] * 100 + bytes[1]; + for (i = 0; i < 23; i++) { + if (secPosValue >= secPosValueList[i] + && secPosValue < secPosValueList[i + 1]) { + result = firstLetter[i]; + break; + } + } + return result; + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/ConvertUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ConvertUtils.java new file mode 100644 index 0000000..a45c471 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ConvertUtils.java @@ -0,0 +1,645 @@ +package com.dahe.mylibrary.utils; + + +import android.annotation.SuppressLint; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.PixelFormat; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.view.View; + + +import com.dahe.mylibrary.CommonBaseLibrary; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +/** + * bytes2Bits, bits2Bytes : bytes 与 bits 互转 + * bytes2Chars, chars2Bytes : bytes 与 chars 互转 + * bytes2HexString, hexString2Bytes : bytes 与 hexString 互转 + * memorySize2Byte, byte2MemorySize : 以 unit 为单位的内存大小与字节数互转 + * byte2FitMemorySize : 字节数转合适内存大小 + * timeSpan2Millis, millis2TimeSpan : 以 unit 为单位的时间长度与毫秒时间戳互转 + * millis2FitTimeSpan : 毫秒时间戳转合适时间长度 + * input2OutputStream, output2InputStream : inputStream 与 outputStream 互转 + * inputStream2Bytes, bytes2InputStream : inputStream 与 bytes 互转 + * outputStream2Bytes, bytes2OutputStream : outputStream 与 bytes 互转 + * inputStream2String, string2InputStream : inputStream 与 string 按编码互转 + * outputStream2String, string2OutputStream: outputStream 与 string 按编码互转 + * bitmap2Bytes, bytes2Bitmap : bitmap 与 bytes 互转 + * drawable2Bitmap, bitmap2Drawable : drawable 与 bitmap 互转 + * drawable2Bytes, bytes2Drawable : drawable 与 bytes 互转 + * view2Bitmap : view 转 Bitmap + * dp2px, px2dp : dp 与 px 互转 + * sp2px, px2sp : sp 与 px 互转 + */ +public final class ConvertUtils { + + private ConvertUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + private static final char hexDigits[] = + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + + /** + * Bytes to bits. + * + * @param bytes The bytes. + * @return bits + */ + public static String bytes2Bits(final byte[] bytes) { + if (bytes == null || bytes.length == 0) return ""; + StringBuilder sb = new StringBuilder(); + for (byte aByte : bytes) { + for (int j = 7; j >= 0; --j) { + sb.append(((aByte >> j) & 0x01) == 0 ? '0' : '1'); + } + } + return sb.toString(); + } + + /** + * Bits to bytes. + * + * @param bits The bits. + * @return bytes + */ + public static byte[] bits2Bytes(String bits) { + int lenMod = bits.length() % 8; + int byteLen = bits.length() / 8; + // add "0" until length to 8 times + if (lenMod != 0) { + for (int i = lenMod; i < 8; i++) { + bits = "0" + bits; + } + byteLen++; + } + byte[] bytes = new byte[byteLen]; + for (int i = 0; i < byteLen; ++i) { + for (int j = 0; j < 8; ++j) { + bytes[i] <<= 1; + bytes[i] |= bits.charAt(i * 8 + j) - '0'; + } + } + return bytes; + } + + /** + * Bytes to chars. + * + * @param bytes The bytes. + * @return chars + */ + public static char[] bytes2Chars(final byte[] bytes) { + if (bytes == null) return null; + int len = bytes.length; + if (len <= 0) return null; + char[] chars = new char[len]; + for (int i = 0; i < len; i++) { + chars[i] = (char) (bytes[i] & 0xff); + } + return chars; + } + + /** + * Chars to bytes. + * + * @param chars The chars. + * @return bytes + */ + public static byte[] chars2Bytes(final char[] chars) { + if (chars == null || chars.length <= 0) return null; + int len = chars.length; + byte[] bytes = new byte[len]; + for (int i = 0; i < len; i++) { + bytes[i] = (byte) (chars[i]); + } + return bytes; + } + + /** + * Bytes to hex string. + *

e.g. bytes2HexString(new byte[] { 0, (byte) 0xa8 }) returns "00A8"

+ * + * @param bytes The bytes. + * @return hex string + */ + public static String bytes2HexString(final byte[] bytes) { + if (bytes == null) return ""; + int len = bytes.length; + if (len <= 0) return ""; + char[] ret = new char[len << 1]; + for (int i = 0, j = 0; i < len; i++) { + ret[j++] = hexDigits[bytes[i] >> 4 & 0x0f]; + ret[j++] = hexDigits[bytes[i] & 0x0f]; + } + return new String(ret); + } + + /** + * Hex string to bytes. + *

e.g. hexString2Bytes("00A8") returns { 0, (byte) 0xA8 }

+ * + * @param hexString The hex string. + * @return the bytes + */ + public static byte[] hexString2Bytes(String hexString) { + if (isSpace(hexString)) return null; + int len = hexString.length(); + if (len % 2 != 0) { + hexString = "0" + hexString; + len = len + 1; + } + char[] hexBytes = hexString.toUpperCase().toCharArray(); + byte[] ret = new byte[len >> 1]; + for (int i = 0; i < len; i += 2) { + ret[i >> 1] = (byte) (hex2Int(hexBytes[i]) << 4 | hex2Int(hexBytes[i + 1])); + } + return ret; + } + + private static int hex2Int(final char hexChar) { + if (hexChar >= '0' && hexChar <= '9') { + return hexChar - '0'; + } else if (hexChar >= 'A' && hexChar <= 'F') { + return hexChar - 'A' + 10; + } else { + throw new IllegalArgumentException(); + } + } + + /** + * Size of memory in unit to size of byte. + * + * @param memorySize Size of memory. + * @param unit The unit of memory size. + *
    + *
  • {@link MemoryConstants#BYTE}
  • + *
  • {@link MemoryConstants#KB}
  • + *
  • {@link MemoryConstants#MB}
  • + *
  • {@link MemoryConstants#GB}
  • + *
+ * @return size of byte + */ + public static long memorySize2Byte(final long memorySize, + @MemoryConstants.Unit final int unit) { + if (memorySize < 0) return -1; + return memorySize * unit; + } + + /** + * Size of byte to size of memory in unit. + * + * @param byteSize Size of byte. + * @param unit The unit of memory size. + *
    + *
  • {@link MemoryConstants#BYTE}
  • + *
  • {@link MemoryConstants#KB}
  • + *
  • {@link MemoryConstants#MB}
  • + *
  • {@link MemoryConstants#GB}
  • + *
+ * @return size of memory in unit + */ + public static double byte2MemorySize(final long byteSize, + @MemoryConstants.Unit final int unit) { + if (byteSize < 0) return -1; + return (double) byteSize / unit; + } + + /** + * Size of byte to fit size of memory. + *

to three decimal places

+ * + * @param byteSize Size of byte. + * @return fit size of memory + */ + @SuppressLint("DefaultLocale") + public static String byte2FitMemorySize(final long byteSize) { + if (byteSize < 0) { + return "shouldn't be less than zero!"; + } else if (byteSize < MemoryConstants.KB) { + return String.format("%.3fB", (double) byteSize); + } else if (byteSize < MemoryConstants.MB) { + return String.format("%.3fKB", (double) byteSize / MemoryConstants.KB); + } else if (byteSize < MemoryConstants.GB) { + return String.format("%.3fMB", (double) byteSize / MemoryConstants.MB); + } else { + return String.format("%.3fGB", (double) byteSize / MemoryConstants.GB); + } + } + + /** + * Time span in unit to milliseconds. + * + * @param timeSpan The time span. + * @param unit The unit of time span. + *
    + *
  • {@link TimeConstants#MSEC}
  • + *
  • {@link TimeConstants#SEC }
  • + *
  • {@link TimeConstants#MIN }
  • + *
  • {@link TimeConstants#HOUR}
  • + *
  • {@link TimeConstants#DAY }
  • + *
+ * @return milliseconds + */ + public static long timeSpan2Millis(final long timeSpan, @TimeConstants.Unit final int unit) { + return timeSpan * unit; + } + + /** + * Milliseconds to time span in unit. + * + * @param millis The milliseconds. + * @param unit The unit of time span. + *
    + *
  • {@link TimeConstants#MSEC}
  • + *
  • {@link TimeConstants#SEC }
  • + *
  • {@link TimeConstants#MIN }
  • + *
  • {@link TimeConstants#HOUR}
  • + *
  • {@link TimeConstants#DAY }
  • + *
+ * @return time span in unit + */ + public static long millis2TimeSpan(final long millis, @TimeConstants.Unit final int unit) { + return millis / unit; + } + + /** + * Milliseconds to fit time span. + * + * @param millis The milliseconds. + *

millis <= 0, node_return null

+ * @param precision The precision of time span. + *
    + *
  • precision = 0, node_return null
  • + *
  • precision = 1, node_return 天
  • + *
  • precision = 2, node_return 天, 小时
  • + *
  • precision = 3, node_return 天, 小时, 分钟
  • + *
  • precision = 4, node_return 天, 小时, 分钟, 秒
  • + *
  • precision >= 5,node_return 天, 小时, 分钟, 秒, 毫秒
  • + *
+ * @return fit time span + */ + @SuppressLint("DefaultLocale") + public static String millis2FitTimeSpan(long millis, int precision) { + if (millis <= 0 || precision <= 0) return null; + StringBuilder sb = new StringBuilder(); + String[] units = {"天", "小时", "分钟", "秒", "毫秒"}; + int[] unitLen = {86400000, 3600000, 60000, 1000, 1}; + precision = Math.min(precision, 5); + for (int i = 0; i < precision; i++) { + if (millis >= unitLen[i]) { + long mode = millis / unitLen[i]; + millis -= mode * unitLen[i]; + sb.append(mode).append(units[i]); + } + } + return sb.toString(); + } + + /** + * Input stream to output stream. + * + * @param is The input stream. + * @return output stream + */ + public static ByteArrayOutputStream input2OutputStream(final InputStream is) { + if (is == null) return null; + try { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + byte[] b = new byte[MemoryConstants.KB]; + int len; + while ((len = is.read(b, 0, MemoryConstants.KB)) != -1) { + os.write(b, 0, len); + } + return os; + } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { + try { + is.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * Output stream to input stream. + * + * @param out The output stream. + * @return input stream + */ + public ByteArrayInputStream output2InputStream(final OutputStream out) { + if (out == null) return null; + return new ByteArrayInputStream(((ByteArrayOutputStream) out).toByteArray()); + } + + /** + * Input stream to bytes. + * + * @param is The input stream. + * @return bytes + */ + public static byte[] inputStream2Bytes(final InputStream is) { + if (is == null) return null; + return input2OutputStream(is).toByteArray(); + } + + /** + * Bytes to input stream. + * + * @param bytes The bytes. + * @return input stream + */ + public static InputStream bytes2InputStream(final byte[] bytes) { + if (bytes == null || bytes.length <= 0) return null; + return new ByteArrayInputStream(bytes); + } + + /** + * Output stream to bytes. + * + * @param out The output stream. + * @return bytes + */ + public static byte[] outputStream2Bytes(final OutputStream out) { + if (out == null) return null; + return ((ByteArrayOutputStream) out).toByteArray(); + } + + /** + * Bytes to output stream. + * + * @param bytes The bytes. + * @return output stream + */ + public static OutputStream bytes2OutputStream(final byte[] bytes) { + if (bytes == null || bytes.length <= 0) return null; + ByteArrayOutputStream os = null; + try { + os = new ByteArrayOutputStream(); + os.write(bytes); + return os; + } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { + try { + if (os != null) { + os.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + /** + * Input stream to string. + * + * @param is The input stream. + * @param charsetName The name of charset. + * @return string + */ + public static String inputStream2String(final InputStream is, final String charsetName) { + if (is == null || isSpace(charsetName)) return ""; + try { + return new String(inputStream2Bytes(is), charsetName); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + return ""; + } + } + + /** + * String to input stream. + * + * @param string The string. + * @param charsetName The name of charset. + * @return input stream + */ + public static InputStream string2InputStream(final String string, final String charsetName) { + if (string == null || isSpace(charsetName)) return null; + try { + return new ByteArrayInputStream(string.getBytes(charsetName)); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + return null; + } + } + + /** + * Output stream to string. + * + * @param out The output stream. + * @param charsetName The name of charset. + * @return string + */ + public static String outputStream2String(final OutputStream out, final String charsetName) { + if (out == null || isSpace(charsetName)) return ""; + try { + return new String(outputStream2Bytes(out), charsetName); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + return ""; + } + } + + /** + * String to output stream. + * + * @param string The string. + * @param charsetName The name of charset. + * @return output stream + */ + public static OutputStream string2OutputStream(final String string, final String charsetName) { + if (string == null || isSpace(charsetName)) return null; + try { + return bytes2OutputStream(string.getBytes(charsetName)); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + return null; + } + } + + /** + * Bitmap to bytes. + * + * @param bitmap The bitmap. + * @param format The format of bitmap. + * @return bytes + */ + public static byte[] bitmap2Bytes(final Bitmap bitmap, final Bitmap.CompressFormat format) { + if (bitmap == null) return null; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + bitmap.compress(format, 100, baos); + return baos.toByteArray(); + } + + /** + * Bytes to bitmap. + * + * @param bytes The bytes. + * @return bitmap + */ + public static Bitmap bytes2Bitmap(final byte[] bytes) { + return (bytes == null || bytes.length == 0) + ? null + : BitmapFactory.decodeByteArray(bytes, 0, bytes.length); + } + + /** + * Drawable to bitmap. + * + * @param drawable The drawable. + * @return bitmap + */ + public static Bitmap drawable2Bitmap(final Drawable drawable) { + if (drawable instanceof BitmapDrawable) { + BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; + if (bitmapDrawable.getBitmap() != null) { + return bitmapDrawable.getBitmap(); + } + } + Bitmap bitmap; + if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) { + bitmap = Bitmap.createBitmap(1, 1, + drawable.getOpacity() != PixelFormat.OPAQUE + ? Bitmap.Config.ARGB_8888 + : Bitmap.Config.RGB_565); + } else { + bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), + drawable.getIntrinsicHeight(), + drawable.getOpacity() != PixelFormat.OPAQUE + ? Bitmap.Config.ARGB_8888 + : Bitmap.Config.RGB_565); + } + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + drawable.draw(canvas); + return bitmap; + } + + /** + * Bitmap to drawable. + * + * @param bitmap The bitmap. + * @return drawable + */ + public static Drawable bitmap2Drawable(final Bitmap bitmap) { + return bitmap == null ? null : new BitmapDrawable(CommonBaseLibrary.getApplication().getResources(), bitmap); + } + + /** + * Drawable to bytes. + * + * @param drawable The drawable. + * @param format The format of bitmap. + * @return bytes + */ + public static byte[] drawable2Bytes(final Drawable drawable, + final Bitmap.CompressFormat format) { + return drawable == null ? null : bitmap2Bytes(drawable2Bitmap(drawable), format); + } + + /** + * Bytes to drawable. + * + * @param bytes The bytes. + * @return drawable + */ + public static Drawable bytes2Drawable(final byte[] bytes) { + return bytes == null ? null : bitmap2Drawable(bytes2Bitmap(bytes)); + } + + /** + * View to bitmap. + * + * @param view The view. + * @return bitmap + */ + public static Bitmap view2Bitmap(final View view) { + if (view == null) return null; + Bitmap ret = + Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(ret); + Drawable bgDrawable = view.getBackground(); + if (bgDrawable != null) { + bgDrawable.draw(canvas); + } else { + canvas.drawColor(Color.WHITE); + } + view.draw(canvas); + return ret; + } + + /** + * Value of dp to value of px. + * + * @param dpValue The value of dp. + * @return value of px + */ + public static int dp2px(final float dpValue) { + final float scale = Resources.getSystem().getDisplayMetrics().density; + return (int) (dpValue * scale + 0.5f); + } + + /** + * Value of px to value of dp. + * + * @param pxValue The value of px. + * @return value of dp + */ + public static int px2dp(final float pxValue) { + final float scale = Resources.getSystem().getDisplayMetrics().density; + return (int) (pxValue / scale + 0.5f); + } + + /** + * Value of sp to value of px. + * + * @param spValue The value of sp. + * @return value of px + */ + public static int sp2px(final float spValue) { + final float fontScale = Resources.getSystem().getDisplayMetrics().scaledDensity; + return (int) (spValue * fontScale + 0.5f); + } + + /** + * Value of px to value of sp. + * + * @param pxValue The value of px. + * @return value of sp + */ + public static int px2sp(final float pxValue) { + final float fontScale = Resources.getSystem().getDisplayMetrics().scaledDensity; + return (int) (pxValue / fontScale + 0.5f); + } + + /////////////////////////////////////////////////////////////////////////// + // other utils methods + /////////////////////////////////////////////////////////////////////////// + + private static boolean isSpace(final String s) { + if (s == null) return true; + for (int i = 0, len = s.length(); i < len; ++i) { + if (!Character.isWhitespace(s.charAt(i))) { + return false; + } + } + return true; + } +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/CountDownTimerUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/CountDownTimerUtils.java new file mode 100644 index 0000000..faf18ab --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/CountDownTimerUtils.java @@ -0,0 +1,38 @@ +package com.dahe.mylibrary.utils; + +import android.os.CountDownTimer; +import android.widget.TextView; + +public class CountDownTimerUtils extends CountDownTimer { + + private TextView mTextView; + /** + * @param millisInFuture The number of millis in the future from the call + * to {@link #start()} until the countdown is done and {@link #onFinish()} + * is called. + * @param countDownInterval The interval along the way to receive + * {@link #onTick(long)} callbacks. + */ + public CountDownTimerUtils(TextView textView, long millisInFuture, long countDownInterval) { + super(millisInFuture, countDownInterval); + this.mTextView = textView; + } + + @Override + public void onTick(long millisUntilFinished) { + mTextView.setClickable(false); //设置不可点击 + mTextView.setText(millisUntilFinished / 1000 + "秒后重新发送"); //设置倒计时时间 +// mTextView.setBackgroundResource(R.drawable.bg_identify_code_press); //设置按钮为灰色,这时是不能点击的 +// SpannableString spannableString = new SpannableString(mTextView.getText().toString()); //获取按钮上的文字 +// ForegroundColorSpan span = new ForegroundColorSpan(Color.RED); +// spannableString.setSpan(span, 0, 2, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);//将倒计时的时间设置为红色 +// mTextView.setText(spannableString); + } + + @Override + public void onFinish() { + mTextView.setText("获取验证码"); + mTextView.setClickable(true);//重新获得点击 +// mTextView.setBackgroundResource(R.drawable.bg_identify_code_normal); //还原背景色 + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/CrashHandler.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/CrashHandler.java new file mode 100644 index 0000000..928d308 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/CrashHandler.java @@ -0,0 +1,243 @@ +package com.dahe.mylibrary.utils; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Environment; +import android.os.Looper; +import android.os.SystemClock; +import android.util.Log; +import android.widget.Toast; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.FilenameFilter; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.reflect.Field; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import static android.os.Environment.DIRECTORY_ALARMS; + +/** + *

全局捕获异常

+ *
+ * 当程序发生Uncaught异常的时候,有该类来接管程序,并记录错误日志 + * + */ +@SuppressLint("SimpleDateFormat") +public class CrashHandler implements Thread.UncaughtExceptionHandler { + + public static String TAG = "MyCrash"; + // 系统默认的UncaughtException处理类 + private Thread.UncaughtExceptionHandler mDefaultHandler; + + private static CrashHandler instance = new CrashHandler(); + private Context mContext; + + // 用来存储设备信息和异常信息 + private Map infos = new HashMap(); + + // 用于格式化日期,作为日志文件名的一部分 + private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + /** 保证只有一个CrashHandler实例 */ + private CrashHandler() { + } + + /** 获取CrashHandler实例 ,单例模式 */ + public static CrashHandler getInstance() { + return instance; + } + + /** + * 初始化 + * + * @param context + */ + public void init(Context context) { + mContext = context; + // 获取系统默认的UncaughtException处理器 + mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); + // 设置该CrashHandler为程序的默认处理器 + Thread.setDefaultUncaughtExceptionHandler(this); + FileUtil.removeFileByTime(getGlobalpath()); +// autoClear(5); + } + + /** + * 当UncaughtException发生时会转入该函数来处理 + */ + @Override + public void uncaughtException(Thread thread, Throwable ex) { + if (!handleException(ex) && mDefaultHandler != null) { + // 如果用户没有处理则让系统默认的异常处理器来处理 + mDefaultHandler.uncaughtException(thread, ex); + } else { + SystemClock.sleep(3000); + // 退出程序 + android.os.Process.killProcess(android.os.Process.myPid()); + System.exit(1); + } + } + + /** + * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. + * + * @param ex + * @return true:如果处理了该异常信息; 否则返回false. + */ + private boolean handleException(Throwable ex) { + if (ex == null) + return false; + try { + // 使用Toast来显示异常信息 + new Thread() { + + @Override + public void run() { + Looper.prepare(); + Toast.makeText(mContext, "很抱歉,程序出现异常,即将重启.", + Toast.LENGTH_LONG).show(); + Looper.loop(); + } + }.start(); + // 收集设备参数信息 + collectDeviceInfo(mContext); + // 保存日志文件 + saveCrashInfoFile(ex); + SystemClock.sleep(3000); + } catch (Exception e) { + e.printStackTrace(); + } + + return true; + } + + /** + * 收集设备参数信息 + * + * @param ctx + */ + public void collectDeviceInfo(Context ctx) { + try { + PackageManager pm = ctx.getPackageManager(); + PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), + PackageManager.GET_ACTIVITIES); + if (pi != null) { + String versionName = pi.versionName + ""; + String versionCode = pi.versionCode + ""; + infos.put("versionName", versionName); + infos.put("versionCode", versionCode); + } + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "an error occured when collect package info", e); + } + Field[] fields = Build.class.getDeclaredFields(); + for (Field field : fields) { + try { + field.setAccessible(true); + infos.put(field.getName(), field.get(null).toString()); + } catch (Exception e) { + Log.e(TAG, "an error occured when collect crash info", e); + } + } + } + + /** + * 保存错误信息到文件中 + * @param ex + * @return 返回文件名称,便于将文件传送到服务器 + * @throws Exception + */ + private String saveCrashInfoFile(Throwable ex) throws Exception { + StringBuffer sb = new StringBuffer(); + try { + SimpleDateFormat sDateFormat = new SimpleDateFormat( + "yyyy-MM-dd HH:mm:ss"); + String date = sDateFormat.format(new java.util.Date()); + sb.append("\r\n" + date + "\n"); + for (Map.Entry entry : infos.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + sb.append(key + "=" + value + "\n"); + } + + Writer writer = new StringWriter(); + PrintWriter printWriter = new PrintWriter(writer); + ex.printStackTrace(printWriter); + Throwable cause = ex.getCause(); + while (cause != null) { + cause.printStackTrace(printWriter); + cause = cause.getCause(); + } + printWriter.flush(); + printWriter.close(); + String result = writer.toString(); + sb.append(result); + + String fileName = writeFile(sb.toString()); + return fileName; + } catch (Exception e) { + Log.e(TAG, "an error occured while writing file...", e); + sb.append("an error occured while writing file...\r\n"); + writeFile(sb.toString()); + } + return null; + } + + private String writeFile(String sb) throws Exception { + String time = formatter.format(new Date()); + String fileName = "crash-" + time + ".log"; +// if (FileUtil.hasSdcard()) { + String path = getGlobalpath(); + File dir = new File(path); + if (!dir.exists()) + dir.mkdirs(); + + String filePath = path + fileName; + File txtFile = new File(filePath); + if (!txtFile.exists()) + txtFile.createNewFile(); + + FileOutputStream fos = new FileOutputStream(txtFile, true); + fos.write(sb.getBytes()); + fos.flush(); + fos.close(); +// } + return fileName; + } + + public static String getGlobalpath() { + return Environment.getExternalStorageDirectory().getAbsolutePath() + + File.separator + "crash" + File.separator; + } + + public static void setTag(String tag) { + TAG = tag; + } + + /** + * 文件删除 + * @param day 文件保存天数 + */ +// public void autoClear(final int autoClearDay) { +// FileUtil.delete(getGlobalpath(), new FilenameFilter() { +// +// @Override +// public boolean accept(File file, String filename) { +// String s = FileUtil.getFileNameWithoutExtension(filename); +// int day = autoClearDay < 0 ? autoClearDay : -1 * autoClearDay; +// String date = "crash-" + DateUtil.getOtherDay(day); +// return date.compareTo(s) >= 0; +// } +// }); +// } +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/FileUtil.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/FileUtil.java new file mode 100644 index 0000000..1eda86f --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/FileUtil.java @@ -0,0 +1,89 @@ +package com.dahe.mylibrary.utils; + +import android.util.Log; + +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.List; + +import static com.dahe.mylibrary.utils.CrashHandler.TAG; + +public class FileUtil { + + + + + //移除文件,获取文件时间与当前时间对比,我这时间定位5天,删除五天前的文件 + public static void removeFileByTime(String dirPath) { + //获取目录下所有文件 + List allFile = getDirAllFile(new File(dirPath)); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + //获取当前时间 + Date end = new Date(System.currentTimeMillis()); + try { + end = dateFormat.parse(dateFormat.format(new Date(System.currentTimeMillis()))); + } catch (Exception e){ + Log.d(TAG, "dataformat exeption e " + e.toString()); + } + Log.d(TAG, "getNeedRemoveFile dirPath = " +dirPath); + for (File file : allFile) {//ComDef + try { + //文件时间减去当前时间 + Date start = dateFormat.parse(dateFormat.format(new Date(file.lastModified()))); + long diff = end.getTime() - start.getTime();//这样得到的差值是微秒级别 + long days = diff / (1000 * 60 * 60 * 24); +// if(ComDef.LOGMAXKEEPTIME <= days){ + if(5 <= days){ + deleteFile(file); + } + + } catch (Exception e){ + Log.d(TAG, "dataformat exeption e " + e.toString()); + } + } + } + + //删除文件夹及文件夹下所有文件 + public static void deleteFile(File file) { + if (file.isDirectory()) { + File[] files = file.listFiles(); + for (int i = 0; i < files.length; i++) { + File f = files[i]; + deleteFile(f); + } + file.delete(); + } else if (file.exists()) { + file.delete(); + } + } + + //获取指定目录下一级文件 + public static List getDirAllFile(File file) { + List fileList = new ArrayList<>(); + File[] fileArray = file.listFiles(); + if(fileArray == null) + return fileList; + for (File f : fileArray) { + fileList.add(f); + } + fileSortByTime(fileList); + return fileList; + } + + + //对文件进行时间排序 + public static void fileSortByTime(List fileList) { + Collections.sort(fileList, new Comparator() { + public int compare(File p1, File p2) { + if (p1.lastModified() < p2.lastModified()) { + return -1; + } + return 1; + } + }); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/ImageLoader.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ImageLoader.java new file mode 100644 index 0000000..1890f38 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ImageLoader.java @@ -0,0 +1,204 @@ +package com.dahe.mylibrary.utils; + +import android.content.Context; +import android.widget.ImageView; + +import androidx.core.content.ContextCompat; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.MultiTransformation; +import com.bumptech.glide.load.resource.bitmap.CenterCrop; +import com.bumptech.glide.load.resource.bitmap.RoundedCorners; +import com.bumptech.glide.request.RequestOptions; +import com.dahe.mylibrary.weight.GlideCircleWithBorder; + +/** + * Created by Administrator on 2017/11/27 0027. + * 图片加载工具类 + */ + +public class ImageLoader { + public static ImageLoader mInstance = null; + + public static ImageLoader getInstance() { + if (null == mInstance) { + synchronized (ImageLoader.class) { + if (null == mInstance) { + mInstance = new ImageLoader(); + } + } + } + return mInstance; + } + + /** + * 普通的加载图片 带占位图 + * + * @param context + * @param url + * @param imageView + * @param multiTransformation 同时设置scaleType在设置圆角或者圆形 + */ + public void loadingImage(Context context, final Object url, final ImageView imageView, MultiTransformation multiTransformation, int placeholder) { + RequestOptions requestOptions = new RequestOptions(); + if (null != context) { + if (placeholder != -1) + requestOptions = requestOptions.placeholder(placeholder).error(placeholder); + if (null != multiTransformation) + requestOptions = requestOptions.transform(multiTransformation); + Glide.with(context).load(url).apply(requestOptions).into(imageView); + } + } + + /** + * 普通的加载图片 + * + * @param context + * @param url + * @param imageView + */ + public void loadingImage(Context context, final Object url, final ImageView imageView) { + loadingImage(context, url, imageView, null, -1); + } + + /** + * 普通的加载图片 带展位图 + * + * @param context + * @param url + * @param imageView + */ + public void loadImage(Context context, final Object url, final ImageView imageView, RequestOptions requestOptions, int placeholder) { + if (null != context) { + if (placeholder != -1) + requestOptions = requestOptions.placeholder(placeholder).error(placeholder); + Glide.with(context).load(url).centerCrop().apply(requestOptions).into(imageView); + } + } + + /** + * 普通的加载图片 不带占位图的 + * + * @param context + * @param url + * @param imageView + */ + @Deprecated + public void loadImage(Context context, final Object url, final ImageView imageView) { + loadImage(context, url, imageView, -1); + } + + /** + * 普通的加载图片 不带占位图的 + * + * @param context + * @param url + * @param imageView + */ + public void loadImage(Context context, final Object url, final ImageView imageView, int placeholder) { + RequestOptions requestOptions = new RequestOptions(); + loadImage(context, url, imageView, requestOptions, placeholder); + } + + /** + * 加载圆形图片 + * + * @param context + * @param url + * @param imageView + */ + public void loadCircleImage(Context context, Object url, ImageView imageView, int placeholder) { + if (null != context) { + loadImage(context, url, imageView, RequestOptions.circleCropTransform(), placeholder); + } + } + + /** + * 加载圆形图片 + * + * @param context + * @param url + * @param imageView + */ + public void loadCircleImage(Context context, Object url, ImageView imageView) { + if (null != context) { + loadCircleImage(context, url, imageView, -1); + } + } + + /** + * 加载圆角图片 + * + * @param context + * @param url + * @param round + * @param imageView + */ + public void loadRoundImage(Context context, Object url, int round, ImageView imageView, int placeholder) { + if (null != context) { + RequestOptions requestOptions = RequestOptions.fitCenterTransform().transform(new CenterCrop(), new RoundedCorners(round)); +// RequestOptions requestOptions = new RequestOptions(); +// requestOptions.transform(new GlideRoundTransform(context, round)); + loadImage(context, url, imageView, requestOptions, placeholder); + } + } + + /** + * 加载圆角图片 + * + * @param context + * @param url + * @param round + * @param imageView + */ + public void loadRoundImage(Context context, Object url, int round, ImageView imageView) { + if (null != context) { + loadRoundImage(context, url, round, imageView, -1); + } + } + + /** + * 加载圆形带圆环图片 + * + * @param context + * @param url + * @param imageView + */ + public void loadCircleWithBorderImage(Context context, Object url, int borderWidth, int borderColor, ImageView imageView, int placeholder) { + if (null != context) { + RequestOptions requestOptions = new RequestOptions(); + requestOptions.transform(new GlideCircleWithBorder(context, borderWidth, ContextCompat.getColor(context, borderColor))); + loadImage(context, url, imageView, requestOptions, placeholder); + } + } + + + /** + * 加载圆形带圆环图片 + * + * @param context + * @param url + * @param imageView + */ + public void loadCircleWithBorderImage(Context context, Object url,RequestOptions requestOptions, int borderWidth, int borderColor, ImageView imageView, int placeholder) { + if (null != context) { + requestOptions.transform(new GlideCircleWithBorder(context, borderWidth, ContextCompat.getColor(context, borderColor))); + loadImage(context, url, imageView, requestOptions, placeholder); + } + } + + /** + * 加载圆形带圆环图片 + * + * @param context + * @param url + * @param imageView + */ + public void loadCircleWithBorderImage(Context context, Object url, int borderWidth, int borderColor, ImageView imageView) { + if (null != context) { + loadCircleWithBorderImage(context, url, borderWidth, borderColor, imageView, -1); + } + } + + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/MD5Utils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/MD5Utils.java new file mode 100644 index 0000000..4c2afac --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/MD5Utils.java @@ -0,0 +1,60 @@ +package com.dahe.mylibrary.utils; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.security.MessageDigest; + +public class MD5Utils { + + private static final int BUFFERSIZE = 8196; + private static final String ALGORITHM = "MD5"; + private static final String CHARSET = "UTF-8"; + + public MD5Utils() { + } + + public static String md5(String input) { + return md5(input, CHARSET); + } + + private static String md5(String input, String charsetName) { + try { + MessageDigest md5 = MessageDigest.getInstance(ALGORITHM); + byte md5Bytes[] = md5.digest(input.getBytes(charsetName)); + return StringUtils.byte2hex(md5Bytes); + } catch (Exception e) { + e.printStackTrace(); + } + return input; + } + + public static String md5file(File filename) { + BufferedInputStream bufferedInputStream = null; + MessageDigest md; + try { + bufferedInputStream = new BufferedInputStream(new FileInputStream(filename), BUFFERSIZE); + md = MessageDigest.getInstance(ALGORITHM); + byte[] buffer = new byte[BUFFERSIZE]; + int i = 0; + while ((i = bufferedInputStream.read(buffer)) != -1) { + md.update(buffer, 0, i); + } + return StringUtils.byte2hex(md.digest()); + } catch (Exception e) { + e.printStackTrace(); + return null; + } finally { + try { + bufferedInputStream.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + public static String md5reverse(String md5) { + return ""; + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/MemoryConstants.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/MemoryConstants.java new file mode 100644 index 0000000..7566d70 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/MemoryConstants.java @@ -0,0 +1,28 @@ +package com.dahe.mylibrary.utils; + + +import androidx.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + *
+ *     author: Blankj
+ *     blog  : http://blankj.com
+ *     time  : 2017/03/13
+ *     desc  : constants of memory
+ * 
+ */ +public final class MemoryConstants { + + public static final int BYTE = 1; + public static final int KB = 1024; + public static final int MB = 1048576; + public static final int GB = 1073741824; + + @IntDef({BYTE, KB, MB, GB}) + @Retention(RetentionPolicy.SOURCE) + public @interface Unit { + } +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/PatternUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/PatternUtils.java new file mode 100644 index 0000000..f3ec6fa --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/PatternUtils.java @@ -0,0 +1,28 @@ +package com.dahe.mylibrary.utils; + +import java.util.regex.Pattern; + +public class PatternUtils { + + + /** + * 正则表达式:验证密码(包含大小写,数字,特殊字符,6-12位) + */ +// public static final String REGEX_PASSWORD = "^(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*,\\.])[0-9a-zA-Z!@#$%^&*,\\\\.]{6,12}$"; + public static final String REGEX_PASSWORD = "^(?=.*[0-9])(?=.*[a-z])(?=.*[!@#$%^&*,\\.])[0-9a-zA-Z!@#$%^&*,\\\\.]{6,12}$"; + public static final String REGEX_WORD = "^[A-Za-z]+$"; + + /** + * 校验密码 + * + * @param password + * @return 校验通过返回true,否则返回false + */ + public static boolean isPassword(String password) { + return Pattern.matches(REGEX_PASSWORD, password); + } + + public static boolean isLetter(String password){ + return Pattern.matches(REGEX_WORD, password); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/PhoneFormatCheckUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/PhoneFormatCheckUtils.java new file mode 100644 index 0000000..2ab5ba1 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/PhoneFormatCheckUtils.java @@ -0,0 +1,55 @@ +package com.dahe.mylibrary.utils; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +public class PhoneFormatCheckUtils { + + /** + * 大陆号码或香港号码均可 + */ + public static boolean isPhoneLegal(String str) throws PatternSyntaxException { + return isChinaPhoneLegal(str) || isHKPhoneLegal(str); + } + + /** + * 大陆手机号码11位数,匹配格式:前三位固定格式+后8位任意数 + * 此方法中前三位格式有: + * 13+任意数 + * 145,147,149 + * 15+除4的任意数(不要写^4,这样的话字母也会被认为是正确的) + * 166 + * 17+3,5,6,7,8 + * 18+任意数 + * 198,199 + */ + public static boolean isChinaPhoneLegal(String str) throws PatternSyntaxException { + // ^ 匹配输入字符串开始的位置 + // \d 匹配一个或多个数字,其中 \ 要转义,所以是 \\d + // $ 匹配输入字符串结尾的位置 + String regExp = "^((13[0-9])|(14[5,7,9])|(15[0-3,5-9])|(166)|(17[3,5,6,7,8])" + + "|(18[0-9])|(19[8,9]))\\d{8}$"; + Pattern p = Pattern.compile(regExp); + Matcher m = p.matcher(str); + return m.matches(); + } + + /** + * 香港手机号码8位数,5|6|8|9开头+7位任意数 + */ + public static boolean isHKPhoneLegal(String str) throws PatternSyntaxException { + // ^ 匹配输入字符串开始的位置 + // \d 匹配一个或多个数字,其中 \ 要转义,所以是 \\d + // $ 匹配输入字符串结尾的位置 + String regExp = "^(5|6|8|9)\\d{7}$"; + Pattern p = Pattern.compile(regExp); + Matcher m = p.matcher(str); + return m.matches(); + } + + public static String hintPhone(String phone){ + return phone.substring(0, 3) + "****" + phone.substring(7, 11); + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/SelectPhotoUtils4.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/SelectPhotoUtils4.java new file mode 100644 index 0000000..a77622a --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/SelectPhotoUtils4.java @@ -0,0 +1,366 @@ +package com.dahe.mylibrary.utils; + +import android.app.Activity; +import android.graphics.Color; +import android.view.View; +import android.widget.ImageView; + +import androidx.core.content.ContextCompat; + +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.adapter.GridImageAdapter; +import com.dahe.mylibrary.dialog.DialogPhotoSelect; +import com.dahe.mylibrary.net.CommonResponseBean; +import com.dahe.mylibrary.weight.GlideEngine; +import com.luck.picture.lib.PictureSelector; +import com.luck.picture.lib.config.PictureConfig; +import com.luck.picture.lib.config.PictureMimeType; +import com.luck.picture.lib.entity.LocalMedia; +import com.luck.picture.lib.listener.OnResultCallbackListener; +import com.luck.picture.lib.style.PictureCropParameterStyle; +import com.luck.picture.lib.style.PictureParameterStyle; +import com.luck.picture.lib.style.PictureSelectorUIStyle; +import com.luck.picture.lib.tools.SdkVersionUtils; + +import java.lang.ref.WeakReference; +import java.util.List; + +public class SelectPhotoUtils4 implements View.OnClickListener { + + + + private Activity ctx; + private OnResultCallbackListener listener; + private GridImageAdapter mAdapter; + + public void selectSimple(Activity ctx,ImageView imageView, OnResultCallbackListener callbackListener){ + this.ctx = ctx; + this.listener = callbackListener; + imageView.setOnClickListener(this); + imageView.performClick(); + } + + + private final GridImageAdapter.onAddPicClickListener onAddPicClickListener = new GridImageAdapter.onAddPicClickListener() { + @Override + public void onAddPicClick() { + PictureSelector.create(ctx) + .openGallery(PictureMimeType.ofImage()) + .imageEngine(GlideEngine.createGlideEngine()) + .selectionMode(PictureConfig.MULTIPLE)// 多选 or 单选 PictureConfig.MULTIPLE or PictureConfig.SINGLE + .maxSelectNum(6) + .isPreviewImage(true)// 是否可预览图片 true or fals + .isGif(false)// 是否显示gif图片 true or false + .isCamera(true)// 是否显示拍照按钮 true or false + .isEnableCrop(true)// 是否裁剪 true or false + .selectionData(mAdapter.getData())// 是否传入已选图片 + .circleDimmedLayer(false)// 是否圆形裁剪 true or false + .freeStyleCropEnabled(true)// 裁剪框是否可拖拽 true or false + + .minimumCompressSize(30)// 小于100kb的图片不压缩 + .showCropFrame(true)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false true or false + .showCropGrid(true)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false true or false +// .rotateEnabled(true) // 裁剪是否可旋转图片 true or false + .scaleEnabled(true)// 裁剪是否可放大缩小图片 true or false + .forResult(new MyResultCallback(mAdapter)); + } + + @Override + public void onDelPicClick(int postion, LocalMedia localMedia) { +// DataManager.getInstance().remove(localMedia.getId()+"") +// .compose(DataManager.setThread()) +// .subscribe(new BaseObserver(ctx, new RxHttpCallBack(ctx) { +// @Override +// public void onSuccess(CommonResponseBean t) { +// super.onSuccess(t); +//// list.remove(index); +// mAdapter.getData().remove(postion); +// mAdapter.notifyItemRemoved(postion); +// mAdapter.notifyItemRangeChanged(postion, mAdapter.getData().size()); +// } +// })); + } + }; + + /** + * 返回结果回调 + */ + private class MyResultCallback implements OnResultCallbackListener { + private WeakReference mAdapterWeakReference; + + public MyResultCallback(GridImageAdapter adapter) { + super(); + this.mAdapterWeakReference = new WeakReference<>(adapter); + } + + @Override + public void onResult(List result) { +// for (LocalMedia media : result) { +// Log.i(TAG, "是否压缩:" + media.isCompressed()); +// Log.i(TAG, "压缩:" + media.getCompressPath()); +// Log.i(TAG, "原图:" + media.getPath()); +// Log.i(TAG, "绝对路径:" + media.getRealPath()); +// Log.i(TAG, "是否裁剪:" + media.isCut()); +// Log.i(TAG, "裁剪:" + media.getCutPath()); +// Log.i(TAG, "是否开启原图:" + media.isOriginal()); +// Log.i(TAG, "原图路径:" + media.getOriginalPath()); +// Log.i(TAG, "Android Q 特有Path:" + media.getAndroidQToPath()); +// Log.i(TAG, "宽高: " + media.getWidth() + "x" + media.getHeight()); +// Log.i(TAG, "Size: " + media.getSize()); +// +// Log.i("MMM", "onResult: " + media.toString()); +// // TODO 可以通过PictureSelectorExternalUtils.getExifInterface();方法获取一些额外的资源信息,如旋转角度、经纬度等信息 +// } + listener.onResult(result); + if (mAdapterWeakReference.get() != null) { + mAdapterWeakReference.get().setList(result); + mAdapterWeakReference.get().notifyDataSetChanged(); + } + } + + @Override + public void onCancel() { +// Log.i(TAG, "PictureSelector Cancel"); + } + } + + + + + + + + + + + + + private PictureCropParameterStyle mCropParameterStyle; + + private PictureParameterStyle getDefaultStyle() { + // 相册主题 + PictureParameterStyle mPictureParameterStyle = new PictureParameterStyle(); + // 是否改变状态栏字体颜色(黑白切换) + mPictureParameterStyle.isChangeStatusBarFontColor = false; + // 是否开启右下角已完成(0/9)风格 + mPictureParameterStyle.isOpenCompletedNumStyle = false; + // 是否开启类似QQ相册带数字选择风格 + mPictureParameterStyle.isOpenCheckNumStyle = false; + // 相册状态栏背景色 + mPictureParameterStyle.pictureStatusBarColor = Color.parseColor("#393a3e"); + // 相册列表标题栏背景色 + mPictureParameterStyle.pictureTitleBarBackgroundColor = Color.parseColor("#393a3e"); + // 相册父容器背景色 + mPictureParameterStyle.pictureContainerBackgroundColor = ContextCompat.getColor(ctx, R.color.black); + // 相册列表标题栏右侧上拉箭头 + mPictureParameterStyle.pictureTitleUpResId = R.drawable.picture_icon_arrow_up; + // 相册列表标题栏右侧下拉箭头 + mPictureParameterStyle.pictureTitleDownResId = R.drawable.picture_icon_arrow_down; + // 相册文件夹列表选中圆点 + mPictureParameterStyle.pictureFolderCheckedDotStyle = R.drawable.picture_orange_oval; + // 相册返回箭头 + mPictureParameterStyle.pictureLeftBackIcon = R.drawable.picture_icon_back; + // 标题栏字体颜色 + mPictureParameterStyle.pictureTitleTextColor = ContextCompat.getColor(ctx, R.color.picture_color_white); + // 相册右侧取消按钮字体颜色 废弃 改用.pictureRightDefaultTextColor和.pictureRightDefaultTextColor + mPictureParameterStyle.pictureCancelTextColor = ContextCompat.getColor(ctx, R.color.picture_color_white); + // 选择相册目录背景样式 +// mPictureParameterStyle.pictureAlbumStyle = R.drawable.picture_new_item_select_bg; + // 相册列表勾选图片样式 + mPictureParameterStyle.pictureCheckedStyle = R.drawable.picture_checkbox_selector; + // 相册列表底部背景色 + mPictureParameterStyle.pictureBottomBgColor = ContextCompat.getColor(ctx, R.color.picture_color_grey); + // 已选数量圆点背景样式 + mPictureParameterStyle.pictureCheckNumBgStyle = R.drawable.picture_num_oval; + // 相册列表底下预览文字色值(预览按钮可点击时的色值) + mPictureParameterStyle.picturePreviewTextColor = ContextCompat.getColor(ctx, R.color.picture_color_fa632d); + // 相册列表底下不可预览文字色值(预览按钮不可点击时的色值) + mPictureParameterStyle.pictureUnPreviewTextColor = ContextCompat.getColor(ctx, R.color.picture_color_white); + // 相册列表已完成色值(已完成 可点击色值) + mPictureParameterStyle.pictureCompleteTextColor = ContextCompat.getColor(ctx, R.color.picture_color_fa632d); + // 相册列表未完成色值(请选择 不可点击色值) + mPictureParameterStyle.pictureUnCompleteTextColor = ContextCompat.getColor(ctx, R.color.picture_color_white); + // 预览界面底部背景色 + mPictureParameterStyle.picturePreviewBottomBgColor = ContextCompat.getColor(ctx, R.color.picture_color_grey); + // 外部预览界面删除按钮样式 + mPictureParameterStyle.pictureExternalPreviewDeleteStyle = R.drawable.picture_icon_delete; + // 原图按钮勾选样式 需设置.isOriginalImageControl(true); 才有效 + mPictureParameterStyle.pictureOriginalControlStyle = R.drawable.picture_original_wechat_checkbox; + // 原图文字颜色 需设置.isOriginalImageControl(true); 才有效 + mPictureParameterStyle.pictureOriginalFontColor = ContextCompat.getColor(ctx, R.color.white); + // 外部预览界面是否显示删除按钮 + mPictureParameterStyle.pictureExternalPreviewGonePreviewDelete = true; + // 设置NavBar Color SDK Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP有效 + mPictureParameterStyle.pictureNavBarColor = Color.parseColor("#393a3e"); + // 文件夹字体颜色 + mPictureParameterStyle.folderTextColor = Color.parseColor("#4d4d4d"); + // 文件夹字体大小 + mPictureParameterStyle.folderTextSize = 16; +// // 自定义相册右侧文本内容设置 +// mPictureParameterStyle.pictureRightDefaultText = ""; +// // 自定义相册未完成文本内容 +// mPictureParameterStyle.pictureUnCompleteText = ""; +// // 自定义相册完成文本内容 +// mPictureParameterStyle.pictureCompleteText = ""; +// // 自定义相册列表不可预览文字 +// mPictureParameterStyle.pictureUnPreviewText = ""; +// // 自定义相册列表预览文字 +// mPictureParameterStyle.picturePreviewText = ""; +// +// // 自定义相册标题字体大小 +// mPictureParameterStyle.pictureTitleTextSize = 18; +// // 自定义相册右侧文字大小 +// mPictureParameterStyle.pictureRightTextSize = 14; +// // 自定义相册预览文字大小 +// mPictureParameterStyle.picturePreviewTextSize = 14; +// // 自定义相册完成文字大小 +// mPictureParameterStyle.pictureCompleteTextSize = 14; +// // 自定义原图文字大小 +// mPictureParameterStyle.pictureOriginalTextSize = 14; + + // 裁剪主题 + mCropParameterStyle = new PictureCropParameterStyle( + ContextCompat.getColor(ctx, R.color.picture_color_grey), + ContextCompat.getColor(ctx, R.color.picture_color_grey), + Color.parseColor("#393a3e"), + ContextCompat.getColor(ctx, R.color.white), + mPictureParameterStyle.isChangeStatusBarFontColor); + + return mPictureParameterStyle; + } + + /** + * 相机拍照 + */ + private void doTakePhoto(Activity ctx) { + + // 裁剪主题 + mCropParameterStyle = new PictureCropParameterStyle( + ContextCompat.getColor(ctx, R.color.picture_color_grey), + ContextCompat.getColor(ctx, R.color.picture_color_grey), + Color.parseColor("#393a3e"), + ContextCompat.getColor(ctx, R.color.white), + false); + + PictureSelector.create(ctx) + .openCamera(PictureMimeType.ofImage()) + .imageEngine(GlideEngine.createGlideEngine()) + .setPictureCropStyle(mCropParameterStyle)// 动态自定义裁剪主题 + .minSelectNum(1) + .maxSelectNum(1) + .isSingleDirectReturn(true)// 单选模式下是否直接返回,PictureConfig.SINGLE模式下有效 +// .setPictureUIStyle(PictureSelectorUIStyle.ofDefaultStyle()) + .isEnableCrop(true)// 是否裁剪 true or false + .isCompress(true)// 是否压缩 true or false + .isGif(false)// 是否显示gif图片 true or false + .circleDimmedLayer(false)// 是否圆形裁剪 true or false + .freeStyleCropEnabled(true)// 裁剪框是否可拖拽 true or false + .cutOutQuality(30)// 裁剪压缩质量 默认90 int + .minimumCompressSize(30)// 小于100kb的图片不压缩 + .showCropFrame(true)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false true or false + .showCropGrid(true)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false true or false + .rotateEnabled(true) // 裁剪是否可旋转图片 true or false + .scaleEnabled(true)// 裁剪是否可放大缩小图片 true or false + .forResult(listener); + + + + // 单独拍照 +// PictureSelector.create(ctx) +// .openCamera(PictureMimeType.ofAll())// 单独拍照,也可录像或也可音频 看你传入的类型是图片or视频 +// .theme(R.style.picture_default_style)// 主题样式设置 具体参考 values/styles +// .imageEngine(GlideEngine.createGlideEngine())// 外部传入图片加载引擎,必传项 +// .maxSelectNum(1)// 最大图片选择数量 +// .minSelectNum(1)// 最小选择数量 +// .closeAndroidQChangeWH(true)//如果图片有旋转角度则对换宽高,默认为true +// .closeAndroidQChangeVideoWH(!SdkVersionUtils.checkedAndroid_Q())// 如果视频有旋转角度则对换宽高,默认false +// .selectionMode(cb_choose_mode.isChecked() ? +// PictureConfig.MULTIPLE : PictureConfig.SINGLE)// 多选 or 单选 +// .loadCacheResourcesCallback(GlideCacheEngine.createCacheEngine())// 获取图片资源缓存,主要是解决华为10部分机型在拷贝文件过多时会出现卡的问题,这里可以判断只在会出现一直转圈问题机型上使用 +// .isPreviewImage(cb_preview_img.isChecked())// 是否可预览图片 +// .isPreviewVideo(cb_preview_video.isChecked())// 是否可预览视频 +// .isEnablePreviewAudio(cb_preview_audio.isChecked()) // 是否可播放音频 +// .isCamera(cb_isCamera.isChecked())// 是否显示拍照按钮 +// .isEnableCrop(cb_crop.isChecked())// 是否裁剪 +// .isCompress(cb_compress.isChecked())// 是否压缩 +// .compressQuality(60)// 图片压缩后输出质量 +// .glideOverride(160, 160)// glide 加载宽高,越小图片列表越流畅,但会影响列表图片浏览的清晰度 +// .withAspectRatio(aspect_ratio_x, aspect_ratio_y)// 裁剪比例 如16:9 3:2 3:4 1:1 可自定义 +// .hideBottomControls(!cb_hide.isChecked())// 是否显示uCrop工具栏,默认不显示 +// .isGif(cb_isGif.isChecked())// 是否显示gif图片 +// .freeStyleCropEnabled(cb_styleCrop.isChecked())// 裁剪框是否可拖拽 +// .circleDimmedLayer(cb_crop_circular.isChecked())// 是否圆形裁剪 +// .showCropFrame(cb_showCropFrame.isChecked())// 是否显示裁剪矩形边框 圆形裁剪时建议设为false +// .showCropGrid(cb_showCropGrid.isChecked())// 是否显示裁剪矩形网格 圆形裁剪时建议设为false +// .isOpenClickSound(cb_voice.isChecked())// 是否开启点击声音 +// .selectionData(mAdapter.getData())// 是否传入已选图片 +// .cutOutQuality(90)// 裁剪输出质量 默认100 +// .minimumCompressSize(100)// 小于100kb的图片不压缩 +// .forResult(new MyResultCallback(mAdapter)); + } + + //从本地相册中选择 + private void doSelectPhoto(Activity ctx) { + PictureSelector.create(ctx) + .openGallery(PictureMimeType.ofImage()) + .imageEngine(GlideEngine.createGlideEngine()) + .selectionMode(PictureConfig.SINGLE)// 多选 or 单选 PictureConfig.MULTIPLE or PictureConfig.SINGLE + .isPreviewImage(true)// 是否可预览图片 true or fals + .isGif(false)// 是否显示gif图片 true or false + .isCamera(false)// 是否显示拍照按钮 true or false + .isEnableCrop(true)// 是否裁剪 true or false + .isCompress(true)// 是否压缩 true or false + .circleDimmedLayer(false)// 是否圆形裁剪 true or false + .freeStyleCropEnabled(true)// 裁剪框是否可拖拽 true or false + .cutOutQuality(30)// 裁剪压缩质量 默认90 int + .minimumCompressSize(30)// 小于100kb的图片不压缩 + .showCropFrame(true)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false true or false + .showCropGrid(true)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false true or false + .rotateEnabled(true) // 裁剪是否可旋转图片 true or false + .scaleEnabled(true)// 裁剪是否可放大缩小图片 true or false + .forResult(listener); +// .forResult(PictureConfig.CHOOSE_REQUEST); + } + + + @Override + public void onClick(View view) { + +// PictureSelector.create(ctx) +// .openGallery(PictureMimeType.ofImage()) +// .imageEngine(GlideEngine.createGlideEngine()) +// .selectionMode(PictureConfig.SINGLE)// 多选 or 单选 PictureConfig.MULTIPLE or PictureConfig.SINGLE +// .isSingleDirectReturn(true) +// .maxSelectNum(1) +// .minSelectNum(1) +// .isPreviewImage(true)// 是否可预览图片 true or fals +// .isGif(false)// 是否显示gif图片 true or false +// .isCamera(true)// 是否显示拍照按钮 true or false +// .isEnableCrop(true)// 是否裁剪 true or false +// .isCompress(true)// 是否压缩 true or false +// .circleDimmedLayer(false)// 是否圆形裁剪 true or false +// .freeStyleCropEnabled(true)// 裁剪框是否可拖拽 true or false +// .cutOutQuality(30)// 裁剪压缩质量 默认90 int +// .minimumCompressSize(100)// 小于100kb的图片不压缩 +// .showCropFrame(true)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false true or false +// .showCropGrid(true)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false true or false +// .rotateEnabled(true) // 裁剪是否可旋转图片 true or false +// .scaleEnabled(true)// 裁剪是否可放大缩小图片 true or false +// .forResult(listener); + + + DialogPhotoSelect dialogPhotoSelect = new DialogPhotoSelect(ctx); + dialogPhotoSelect.show(); + dialogPhotoSelect.setOnSelectClickListener(new DialogPhotoSelect.onSelectClickListener() { + @Override + public void onTakePhoto() { + doTakePhoto(ctx); + } + + @Override + public void onSelectPhoto() { + doSelectPhoto(ctx); + } + }); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/SelectPhotoUtils5.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/SelectPhotoUtils5.java new file mode 100644 index 0000000..4eeb7a9 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/SelectPhotoUtils5.java @@ -0,0 +1,353 @@ +package com.dahe.mylibrary.utils; + +import android.app.Activity; +import android.graphics.Color; +import android.view.View; +import android.widget.ImageView; + +import androidx.core.content.ContextCompat; + +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.adapter.GridImageAdapter; +import com.dahe.mylibrary.dialog.DialogPhotoSelect; +import com.dahe.mylibrary.weight.GlideEngine; +import com.luck.picture.lib.PictureSelector; +import com.luck.picture.lib.config.PictureConfig; +import com.luck.picture.lib.config.PictureMimeType; +import com.luck.picture.lib.entity.LocalMedia; +import com.luck.picture.lib.listener.OnResultCallbackListener; +import com.luck.picture.lib.style.PictureCropParameterStyle; +import com.luck.picture.lib.style.PictureParameterStyle; + +import java.lang.ref.WeakReference; +import java.util.List; + +public class SelectPhotoUtils5 implements View.OnClickListener { + + private SelectPhotoUtils5 selectPhotoUtils5; + private Activity ctx; + private OnResultCallbackListener listener; + private GridImageAdapter mAdapter; + + public void selectSimple(Activity ctx, ImageView imageView, OnResultCallbackListener callbackListener) { + this.ctx = ctx; + this.listener = callbackListener; + imageView.setOnClickListener(this); + imageView.performClick(); + } + + + + + private final GridImageAdapter.onAddPicClickListener onAddPicClickListener = new GridImageAdapter.onAddPicClickListener() { + @Override + public void onAddPicClick() { + PictureSelector.create(ctx) + .openGallery(PictureMimeType.ofImage()) + .imageEngine(GlideEngine.createGlideEngine()) + .selectionMode(PictureConfig.MULTIPLE)// 多选 or 单选 PictureConfig.MULTIPLE or PictureConfig.SINGLE + .maxSelectNum(6) + .isPreviewImage(true)// 是否可预览图片 true or fals + .isGif(false)// 是否显示gif图片 true or false + .isCamera(true)// 是否显示拍照按钮 true or false + .isEnableCrop(false)// 是否裁剪 true or false + .selectionData(mAdapter.getData())// 是否传入已选图片 + .circleDimmedLayer(false)// 是否圆形裁剪 true or false + .freeStyleCropEnabled(true)// 裁剪框是否可拖拽 true or false + + .minimumCompressSize(30)// 小于100kb的图片不压缩 + .showCropFrame(true)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false true or false + .showCropGrid(true)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false true or false +// .rotateEnabled(true) // 裁剪是否可旋转图片 true or false + .scaleEnabled(true)// 裁剪是否可放大缩小图片 true or false + .forResult(new MyResultCallback(mAdapter)); + } + + @Override + public void onDelPicClick(int postion, LocalMedia localMedia) { +// DataManager.getInstance().remove(localMedia.getId()+"") +// .compose(DataManager.setThread()) +// .subscribe(new BaseObserver(ctx, new RxHttpCallBack(ctx) { +// @Override +// public void onSuccess(CommonResponseBean t) { +// super.onSuccess(t); +//// list.remove(index); +// mAdapter.getData().remove(postion); +// mAdapter.notifyItemRemoved(postion); +// mAdapter.notifyItemRangeChanged(postion, mAdapter.getData().size()); +// } +// })); + } + }; + + /** + * 返回结果回调 + */ + private class MyResultCallback implements OnResultCallbackListener { + private WeakReference mAdapterWeakReference; + + public MyResultCallback(GridImageAdapter adapter) { + super(); + this.mAdapterWeakReference = new WeakReference<>(adapter); + } + + @Override + public void onResult(List result) { +// for (LocalMedia media : result) { +// Log.i(TAG, "是否压缩:" + media.isCompressed()); +// Log.i(TAG, "压缩:" + media.getCompressPath()); +// Log.i(TAG, "原图:" + media.getPath()); +// Log.i(TAG, "绝对路径:" + media.getRealPath()); +// Log.i(TAG, "是否裁剪:" + media.isCut()); +// Log.i(TAG, "裁剪:" + media.getCutPath()); +// Log.i(TAG, "是否开启原图:" + media.isOriginal()); +// Log.i(TAG, "原图路径:" + media.getOriginalPath()); +// Log.i(TAG, "Android Q 特有Path:" + media.getAndroidQToPath()); +// Log.i(TAG, "宽高: " + media.getWidth() + "x" + media.getHeight()); +// Log.i(TAG, "Size: " + media.getSize()); +// +// Log.i("MMM", "onResult: " + media.toString()); +// // TODO 可以通过PictureSelectorExternalUtils.getExifInterface();方法获取一些额外的资源信息,如旋转角度、经纬度等信息 +// } + listener.onResult(result); + if (mAdapterWeakReference.get() != null) { + mAdapterWeakReference.get().setList(result); + mAdapterWeakReference.get().notifyDataSetChanged(); + } + } + + @Override + public void onCancel() { +// Log.i(TAG, "PictureSelector Cancel"); + } + } + + + private PictureCropParameterStyle mCropParameterStyle; + + private PictureParameterStyle getDefaultStyle() { + // 相册主题 + PictureParameterStyle mPictureParameterStyle = new PictureParameterStyle(); + // 是否改变状态栏字体颜色(黑白切换) + mPictureParameterStyle.isChangeStatusBarFontColor = false; + // 是否开启右下角已完成(0/9)风格 + mPictureParameterStyle.isOpenCompletedNumStyle = false; + // 是否开启类似QQ相册带数字选择风格 + mPictureParameterStyle.isOpenCheckNumStyle = false; + // 相册状态栏背景色 + mPictureParameterStyle.pictureStatusBarColor = Color.parseColor("#393a3e"); + // 相册列表标题栏背景色 + mPictureParameterStyle.pictureTitleBarBackgroundColor = Color.parseColor("#393a3e"); + // 相册父容器背景色 + mPictureParameterStyle.pictureContainerBackgroundColor = ContextCompat.getColor(ctx, R.color.black); + // 相册列表标题栏右侧上拉箭头 + mPictureParameterStyle.pictureTitleUpResId = R.drawable.picture_icon_arrow_up; + // 相册列表标题栏右侧下拉箭头 + mPictureParameterStyle.pictureTitleDownResId = R.drawable.picture_icon_arrow_down; + // 相册文件夹列表选中圆点 + mPictureParameterStyle.pictureFolderCheckedDotStyle = R.drawable.picture_orange_oval; + // 相册返回箭头 + mPictureParameterStyle.pictureLeftBackIcon = R.drawable.picture_icon_back; + // 标题栏字体颜色 + mPictureParameterStyle.pictureTitleTextColor = ContextCompat.getColor(ctx, R.color.picture_color_white); + // 相册右侧取消按钮字体颜色 废弃 改用.pictureRightDefaultTextColor和.pictureRightDefaultTextColor + mPictureParameterStyle.pictureCancelTextColor = ContextCompat.getColor(ctx, R.color.picture_color_white); + // 选择相册目录背景样式 +// mPictureParameterStyle.pictureAlbumStyle = R.drawable.picture_new_item_select_bg; + // 相册列表勾选图片样式 + mPictureParameterStyle.pictureCheckedStyle = R.drawable.picture_checkbox_selector; + // 相册列表底部背景色 + mPictureParameterStyle.pictureBottomBgColor = ContextCompat.getColor(ctx, R.color.picture_color_grey); + // 已选数量圆点背景样式 + mPictureParameterStyle.pictureCheckNumBgStyle = R.drawable.picture_num_oval; + // 相册列表底下预览文字色值(预览按钮可点击时的色值) + mPictureParameterStyle.picturePreviewTextColor = ContextCompat.getColor(ctx, R.color.picture_color_fa632d); + // 相册列表底下不可预览文字色值(预览按钮不可点击时的色值) + mPictureParameterStyle.pictureUnPreviewTextColor = ContextCompat.getColor(ctx, R.color.picture_color_white); + // 相册列表已完成色值(已完成 可点击色值) + mPictureParameterStyle.pictureCompleteTextColor = ContextCompat.getColor(ctx, R.color.picture_color_fa632d); + // 相册列表未完成色值(请选择 不可点击色值) + mPictureParameterStyle.pictureUnCompleteTextColor = ContextCompat.getColor(ctx, R.color.picture_color_white); + // 预览界面底部背景色 + mPictureParameterStyle.picturePreviewBottomBgColor = ContextCompat.getColor(ctx, R.color.picture_color_grey); + // 外部预览界面删除按钮样式 + mPictureParameterStyle.pictureExternalPreviewDeleteStyle = R.drawable.picture_icon_delete; + // 原图按钮勾选样式 需设置.isOriginalImageControl(true); 才有效 + mPictureParameterStyle.pictureOriginalControlStyle = R.drawable.picture_original_wechat_checkbox; + // 原图文字颜色 需设置.isOriginalImageControl(true); 才有效 + mPictureParameterStyle.pictureOriginalFontColor = ContextCompat.getColor(ctx, R.color.white); + // 外部预览界面是否显示删除按钮 + mPictureParameterStyle.pictureExternalPreviewGonePreviewDelete = true; + // 设置NavBar Color SDK Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP有效 + mPictureParameterStyle.pictureNavBarColor = Color.parseColor("#393a3e"); + // 文件夹字体颜色 + mPictureParameterStyle.folderTextColor = Color.parseColor("#4d4d4d"); + // 文件夹字体大小 + mPictureParameterStyle.folderTextSize = 16; +// // 自定义相册右侧文本内容设置 +// mPictureParameterStyle.pictureRightDefaultText = ""; +// // 自定义相册未完成文本内容 +// mPictureParameterStyle.pictureUnCompleteText = ""; +// // 自定义相册完成文本内容 +// mPictureParameterStyle.pictureCompleteText = ""; +// // 自定义相册列表不可预览文字 +// mPictureParameterStyle.pictureUnPreviewText = ""; +// // 自定义相册列表预览文字 +// mPictureParameterStyle.picturePreviewText = ""; +// +// // 自定义相册标题字体大小 +// mPictureParameterStyle.pictureTitleTextSize = 18; +// // 自定义相册右侧文字大小 +// mPictureParameterStyle.pictureRightTextSize = 14; +// // 自定义相册预览文字大小 +// mPictureParameterStyle.picturePreviewTextSize = 14; +// // 自定义相册完成文字大小 +// mPictureParameterStyle.pictureCompleteTextSize = 14; +// // 自定义原图文字大小 +// mPictureParameterStyle.pictureOriginalTextSize = 14; + + // 裁剪主题 + mCropParameterStyle = new PictureCropParameterStyle( + ContextCompat.getColor(ctx, R.color.picture_color_grey), + ContextCompat.getColor(ctx, R.color.picture_color_grey), + Color.parseColor("#393a3e"), + ContextCompat.getColor(ctx, R.color.white), + mPictureParameterStyle.isChangeStatusBarFontColor); + + return mPictureParameterStyle; + } + + /** + * 相机拍照 + */ + private void doTakePhoto(Activity ctx) { + + // 裁剪主题 + mCropParameterStyle = new PictureCropParameterStyle( + ContextCompat.getColor(ctx, R.color.picture_color_grey), + ContextCompat.getColor(ctx, R.color.picture_color_grey), + Color.parseColor("#393a3e"), + ContextCompat.getColor(ctx, R.color.white), + false); + + PictureSelector.create(ctx) + .openCamera(PictureMimeType.ofImage()) + .imageEngine(GlideEngine.createGlideEngine()) + .setPictureCropStyle(mCropParameterStyle)// 动态自定义裁剪主题 + .minSelectNum(1) + .maxSelectNum(1) + .isSingleDirectReturn(true)// 单选模式下是否直接返回,PictureConfig.SINGLE模式下有效 +// .setPictureUIStyle(PictureSelectorUIStyle.ofDefaultStyle()) + .isEnableCrop(false)// 是否裁剪 true or false + .isCompress(true)// 是否压缩 true or false + .isGif(false)// 是否显示gif图片 true or false + .circleDimmedLayer(false)// 是否圆形裁剪 true or false + .freeStyleCropEnabled(true)// 裁剪框是否可拖拽 true or false + .cutOutQuality(30)// 裁剪压缩质量 默认90 int + .minimumCompressSize(30)// 小于100kb的图片不压缩 + .showCropFrame(true)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false true or false + .showCropGrid(true)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false true or false + .rotateEnabled(true) // 裁剪是否可旋转图片 true or false + .scaleEnabled(true)// 裁剪是否可放大缩小图片 true or false + .forResult(listener); + + + // 单独拍照 +// PictureSelector.create(ctx) +// .openCamera(PictureMimeType.ofAll())// 单独拍照,也可录像或也可音频 看你传入的类型是图片or视频 +// .theme(R.style.picture_default_style)// 主题样式设置 具体参考 values/styles +// .imageEngine(GlideEngine.createGlideEngine())// 外部传入图片加载引擎,必传项 +// .maxSelectNum(1)// 最大图片选择数量 +// .minSelectNum(1)// 最小选择数量 +// .closeAndroidQChangeWH(true)//如果图片有旋转角度则对换宽高,默认为true +// .closeAndroidQChangeVideoWH(!SdkVersionUtils.checkedAndroid_Q())// 如果视频有旋转角度则对换宽高,默认false +// .selectionMode(cb_choose_mode.isChecked() ? +// PictureConfig.MULTIPLE : PictureConfig.SINGLE)// 多选 or 单选 +// .loadCacheResourcesCallback(GlideCacheEngine.createCacheEngine())// 获取图片资源缓存,主要是解决华为10部分机型在拷贝文件过多时会出现卡的问题,这里可以判断只在会出现一直转圈问题机型上使用 +// .isPreviewImage(cb_preview_img.isChecked())// 是否可预览图片 +// .isPreviewVideo(cb_preview_video.isChecked())// 是否可预览视频 +// .isEnablePreviewAudio(cb_preview_audio.isChecked()) // 是否可播放音频 +// .isCamera(cb_isCamera.isChecked())// 是否显示拍照按钮 +// .isEnableCrop(cb_crop.isChecked())// 是否裁剪 +// .isCompress(cb_compress.isChecked())// 是否压缩 +// .compressQuality(60)// 图片压缩后输出质量 +// .glideOverride(160, 160)// glide 加载宽高,越小图片列表越流畅,但会影响列表图片浏览的清晰度 +// .withAspectRatio(aspect_ratio_x, aspect_ratio_y)// 裁剪比例 如16:9 3:2 3:4 1:1 可自定义 +// .hideBottomControls(!cb_hide.isChecked())// 是否显示uCrop工具栏,默认不显示 +// .isGif(cb_isGif.isChecked())// 是否显示gif图片 +// .freeStyleCropEnabled(cb_styleCrop.isChecked())// 裁剪框是否可拖拽 +// .circleDimmedLayer(cb_crop_circular.isChecked())// 是否圆形裁剪 +// .showCropFrame(cb_showCropFrame.isChecked())// 是否显示裁剪矩形边框 圆形裁剪时建议设为false +// .showCropGrid(cb_showCropGrid.isChecked())// 是否显示裁剪矩形网格 圆形裁剪时建议设为false +// .isOpenClickSound(cb_voice.isChecked())// 是否开启点击声音 +// .selectionData(mAdapter.getData())// 是否传入已选图片 +// .cutOutQuality(90)// 裁剪输出质量 默认100 +// .minimumCompressSize(100)// 小于100kb的图片不压缩 +// .forResult(new MyResultCallback(mAdapter)); + } + + //从本地相册中选择 + private void doSelectPhoto(Activity ctx) { + PictureSelector.create(ctx) + .openGallery(PictureMimeType.ofImage()) + .imageEngine(GlideEngine.createGlideEngine()) + .selectionMode(PictureConfig.SINGLE)// 多选 or 单选 PictureConfig.MULTIPLE or PictureConfig.SINGLE + .isPreviewImage(true)// 是否可预览图片 true or fals + .isGif(false)// 是否显示gif图片 true or false + .isCamera(false)// 是否显示拍照按钮 true or false + .isEnableCrop(false)// 是否裁剪 true or false + .isCompress(true)// 是否压缩 true or false + .circleDimmedLayer(false)// 是否圆形裁剪 true or false + .freeStyleCropEnabled(true)// 裁剪框是否可拖拽 true or false + .cutOutQuality(30)// 裁剪压缩质量 默认90 int + .minimumCompressSize(30)// 小于100kb的图片不压缩 + .showCropFrame(true)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false true or false + .showCropGrid(true)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false true or false + .rotateEnabled(true) // 裁剪是否可旋转图片 true or false + .scaleEnabled(true)// 裁剪是否可放大缩小图片 true or false + .forResult(listener); +// .forResult(PictureConfig.CHOOSE_REQUEST); + } + + + @Override + public void onClick(View view) { + +// PictureSelector.create(ctx) +// .openGallery(PictureMimeType.ofImage()) +// .imageEngine(GlideEngine.createGlideEngine()) +// .selectionMode(PictureConfig.SINGLE)// 多选 or 单选 PictureConfig.MULTIPLE or PictureConfig.SINGLE +// .isSingleDirectReturn(true) +// .maxSelectNum(1) +// .minSelectNum(1) +// .isPreviewImage(true)// 是否可预览图片 true or fals +// .isGif(false)// 是否显示gif图片 true or false +// .isCamera(true)// 是否显示拍照按钮 true or false +// .isEnableCrop(true)// 是否裁剪 true or false +// .isCompress(true)// 是否压缩 true or false +// .circleDimmedLayer(false)// 是否圆形裁剪 true or false +// .freeStyleCropEnabled(true)// 裁剪框是否可拖拽 true or false +// .cutOutQuality(30)// 裁剪压缩质量 默认90 int +// .minimumCompressSize(100)// 小于100kb的图片不压缩 +// .showCropFrame(true)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false true or false +// .showCropGrid(true)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false true or false +// .rotateEnabled(true) // 裁剪是否可旋转图片 true or false +// .scaleEnabled(true)// 裁剪是否可放大缩小图片 true or false +// .forResult(listener); + + + DialogPhotoSelect dialogPhotoSelect = new DialogPhotoSelect(ctx); + dialogPhotoSelect.show(); + dialogPhotoSelect.setOnSelectClickListener(new DialogPhotoSelect.onSelectClickListener() { + @Override + public void onTakePhoto() { + doTakePhoto(ctx); + } + + @Override + public void onSelectPhoto() { + doSelectPhoto(ctx); + } + }); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/SelectPhotoUtils6.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/SelectPhotoUtils6.java new file mode 100644 index 0000000..02b244c --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/SelectPhotoUtils6.java @@ -0,0 +1,318 @@ +package com.dahe.mylibrary.utils; + +import android.app.Activity; +import android.content.pm.ActivityInfo; +import android.text.TextUtils; +import android.view.View; +import android.widget.ImageView; + +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.adapter.GridImageAdapter; +import com.dahe.mylibrary.dialog.DialogPhotoSelect; +import com.dahe.mylibrary.net.CommonResponseBean; +import com.dahe.mylibrary.weight.FullyGridLayoutManager; +import com.dahe.mylibrary.weight.GlideEngine; +import com.luck.picture.lib.PictureSelector; +import com.luck.picture.lib.config.PictureConfig; +import com.luck.picture.lib.config.PictureMimeType; +import com.luck.picture.lib.decoration.GridSpacingItemDecoration; +import com.luck.picture.lib.entity.LocalMedia; +import com.luck.picture.lib.listener.OnResultCallbackListener; +import com.luck.picture.lib.tools.ScreenUtils; + +import java.lang.ref.WeakReference; +import java.util.List; + +public class SelectPhotoUtils6 implements View.OnClickListener { + private Activity ctx; + private OnResultCallbackListener listener; + private GridImageAdapter mAdapter; + private Build build; + + private SelectPhotoUtils6(Build build, Activity ctx) { + this.build = build; + this.ctx = ctx; + this.listener = build.listener; + if (null == listener) { + ToastUtils.showToast(ctx, "请初始化回调listener"); + return; + } + if (build.isSingle) {//单选 + if (null == build.imageView) { + ToastUtils.showToast(ctx, "请初始化ImageView"); + return; + } + selectSimple(build.imageView); + } else {//多选 + if (null == build.recyclerView || !(build.recyclerView instanceof RecyclerView)) { + ToastUtils.showToast(ctx, "请初始化RecycleView"); + return; + } + selectMul(build.recyclerView); + + } + } + + + public static class Build { + private int maxSelect; + private boolean isSingle; + private boolean isOnlyShow; + private ImageView imageView; + private RecyclerView recyclerView; + private List pics; + private OnResultCallbackListener listener; + + public Build maxSelect(int max) { + this.maxSelect = max; + return this; + } + + public Build isSingle(boolean isSingle) { + this.isSingle = isSingle; + return this; + } + + public Build isOnlyShow(boolean isOnlyShow) { + this.isOnlyShow = isOnlyShow; + return this; + } + + public Build imageview(ImageView imageView) { + this.imageView = imageView; + return this; + } + + public Build recycleview(RecyclerView recyclerView) { + this.recyclerView = recyclerView; + return this; + } + + public Build newPics(List pics) { + this.pics = pics; + return this; + } + + public Build resultListener(OnResultCallbackListener listener) { + this.listener = listener; + return this; + } + + public SelectPhotoUtils6 create(Activity ctx) { + return new SelectPhotoUtils6(this, ctx); + } + } + + public GridImageAdapter getmAdapter() { + return mAdapter; + } + + + public void selectSimple(ImageView imageView) { + imageView.setOnClickListener(this); + } + + + public void selectMul(RecyclerView recyclerView) { + FullyGridLayoutManager manager = new FullyGridLayoutManager(ctx, + 4, GridLayoutManager.VERTICAL, false); + + recyclerView.addItemDecoration(new GridSpacingItemDecoration(40, + ScreenUtils.dip2px(ctx, 8), true + )); + recyclerView.setLayoutManager(manager); + mAdapter = new GridImageAdapter(ctx, onAddPicClickListener); + mAdapter.setSelectMax(build.maxSelect); + mAdapter.setIsOnlyShow(build.isOnlyShow); + recyclerView.setAdapter(mAdapter); + + mAdapter.setOnItemClickListener((v, position) -> { + List selectList = mAdapter.getData(); + if (selectList.size() > 0) { + LocalMedia media = selectList.get(position); + String mimeType = media.getMimeType(); + int mediaType = PictureMimeType.getMimeType(mimeType); + switch (mediaType) { + case PictureConfig.TYPE_VIDEO: + // 预览视频 + PictureSelector.create(ctx) + .themeStyle(R.style.picture_default_style) +// .setPictureStyle(mPictureParameterStyle)// 动态自定义相册主题 + .externalPictureVideo(TextUtils.isEmpty(media.getAndroidQToPath()) ? media.getPath() : media.getAndroidQToPath()); + break; + case PictureConfig.TYPE_AUDIO: + // 预览音频 + PictureSelector.create(ctx) + .externalPictureAudio(PictureMimeType.isContent(media.getPath()) ? media.getAndroidQToPath() : media.getPath()); + break; + default: + // 预览图片 可自定长按保存路径 +// PictureWindowAnimationStyle animationStyle = new PictureWindowAnimationStyle(); +// animationStyle.activityPreviewEnterAnimation = R.anim.picture_anim_up_in; +// animationStyle.activityPreviewExitAnimation = R.anim.picture_anim_down_out; + PictureSelector.create(ctx) + .themeStyle(R.style.picture_default_style) // xml设置主题 +// .setPictureStyle(mPictureParameterStyle)// 动态自定义相册主题 + //.setPictureWindowAnimationStyle(animationStyle)// 自定义页面启动动画 + .setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)// 设置相册Activity方向,不设置默认使用系统 + .isNotPreviewDownload(true)// 预览图片长按是否可以下载 + //.bindCustomPlayVideoCallback(new MyVideoSelectedPlayCallback(getContext()))// 自定义播放回调控制,用户可以使用自己的视频播放界面 + .imageEngine(GlideEngine.createGlideEngine())// 外部传入图片加载引擎,必传项 + .openExternalPreview(position, selectList); + break; + } + } + }); + } + + + private final GridImageAdapter.onAddPicClickListener onAddPicClickListener = new GridImageAdapter.onAddPicClickListener() { + @Override + public void onAddPicClick() { + PictureSelector.create(ctx) + .openGallery(PictureMimeType.ofImage()) + .imageEngine(GlideEngine.createGlideEngine()) + .selectionMode(build.isSingle ? PictureConfig.SINGLE : PictureConfig.MULTIPLE)// 多选 or 单选 PictureConfig.MULTIPLE or PictureConfig.SINGLE + .maxSelectNum(build.maxSelect) + .isPreviewImage(true)// 是否可预览图片 true or fals + .isGif(false)// 是否显示gif图片 true or false + .isCamera(true)// 是否显示拍照按钮 true or false + .isEnableCrop(false)// 是否裁剪 true or false + .selectionData(mAdapter.getData())// 是否传入已选图片 + .isCompress(true)// 是否压缩 true or false + .circleDimmedLayer(false)// 是否圆形裁剪 true or false + .freeStyleCropEnabled(false)// 裁剪框是否可拖拽 true or false + .cutOutQuality(30)// 裁剪压缩质量 默认90 int + .minimumCompressSize(30)// 小于100kb的图片不压缩 + .showCropFrame(false)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false true or false + .showCropGrid(false)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false true or false +// .rotateEnabled(true) // 裁剪是否可旋转图片 true or false + .scaleEnabled(false)// 裁剪是否可放大缩小图片 true or false + .forResult(new MyResultCallback(mAdapter)); + } + + @Override + public void onDelPicClick(int postion, LocalMedia localMedia) { +// DataManager.getInstance().remove(localMedia.getId() + "") +// .compose(DataManager.setThread()) +// .subscribe(new BaseObserver(ctx, new RxHttpCallBack(ctx) { +// @Override +// public void onSuccess(CommonResponseBean t) { +// super.onSuccess(t); +//// list.remove(index); +// mAdapter.getData().remove(postion); +// mAdapter.notifyItemRemoved(postion); +// mAdapter.notifyItemRangeChanged(postion, mAdapter.getData().size()); +// } +// })); + } + }; + + /** + * 返回结果回调 + */ + private class MyResultCallback implements OnResultCallbackListener { + private WeakReference mAdapterWeakReference; + + public MyResultCallback(GridImageAdapter adapter) { + super(); + this.mAdapterWeakReference = new WeakReference<>(adapter); + } + + @Override + public void onResult(List result) { +// for (LocalMedia media : result) { +// Log.i(TAG, "是否压缩:" + media.isCompressed()); +// Log.i(TAG, "压缩:" + media.getCompressPath()); +// Log.i(TAG, "原图:" + media.getPath()); +// Log.i(TAG, "绝对路径:" + media.getRealPath()); +// Log.i(TAG, "是否裁剪:" + media.isCut()); +// Log.i(TAG, "裁剪:" + media.getCutPath()); +// Log.i(TAG, "是否开启原图:" + media.isOriginal()); +// Log.i(TAG, "原图路径:" + media.getOriginalPath()); +// Log.i(TAG, "Android Q 特有Path:" + media.getAndroidQToPath()); +// Log.i(TAG, "宽高: " + media.getWidth() + "x" + media.getHeight()); +// Log.i(TAG, "Size: " + media.getSize()); +// +// Log.i("MMM", "onResult: " + media.toString()); +// // TODO 可以通过PictureSelectorExternalUtils.getExifInterface();方法获取一些额外的资源信息,如旋转角度、经纬度等信息 +// } + listener.onResult(result); + if (mAdapterWeakReference.get() != null) { + mAdapterWeakReference.get().setList(result); + mAdapterWeakReference.get().notifyDataSetChanged(); + } + } + + @Override + public void onCancel() { +// Log.i(TAG, "PictureSelector Cancel"); + } + } + + + /** + * 相机拍照 + */ + private void doTakePhoto(Activity ctx) { + PictureSelector.create(ctx) + .openCamera(PictureMimeType.ofImage()) + .imageEngine(GlideEngine.createGlideEngine()) + .isEnableCrop(false)// 是否裁剪 true or false + .isCompress(true)// 是否压缩 true or false + .isGif(false)// 是否显示gif图片 true or false + .circleDimmedLayer(false)// 是否圆形裁剪 true or false + .freeStyleCropEnabled(false)// 裁剪框是否可拖拽 true or false + .cutOutQuality(30)// 裁剪压缩质量 默认90 int + .minimumCompressSize(30)// 小于100kb的图片不压缩 + .showCropFrame(false)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false true or false + .showCropGrid(false)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false true or false + .rotateEnabled(false) // 裁剪是否可旋转图片 true or false + .scaleEnabled(false)// 裁剪是否可放大缩小图片 true or false + .forResult(listener); + } + + //从本地相册中选择 + private void doSelectPhoto(Activity ctx) { + PictureSelector.create(ctx) + .openGallery(PictureMimeType.ofImage()) + .imageEngine(GlideEngine.createGlideEngine()) + .selectionMode(PictureConfig.SINGLE)// 多选 or 单选 PictureConfig.MULTIPLE or PictureConfig.SINGLE + .isPreviewImage(true)// 是否可预览图片 true or fals + .isGif(false)// 是否显示gif图片 true or false + .isCamera(false)// 是否显示拍照按钮 true or false + .isEnableCrop(false)// 是否裁剪 true or false + .isCompress(true)// 是否压缩 true or false + .circleDimmedLayer(false)// 是否圆形裁剪 true or false + .freeStyleCropEnabled(false)// 裁剪框是否可拖拽 true or false + .cutOutQuality(30)// 裁剪压缩质量 默认90 int + .minimumCompressSize(30)// 小于100kb的图片不压缩 + .showCropFrame(false)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false true or false + .showCropGrid(false)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false true or false +// .rotateEnabled(true) // 裁剪是否可旋转图片 true or false + .scaleEnabled(false)// 裁剪是否可放大缩小图片 true or false + .forResult(listener); +// .forResult(PictureConfig.CHOOSE_REQUEST); + } + + + @Override + public void onClick(View view) { + DialogPhotoSelect dialogPhotoSelect = new DialogPhotoSelect(ctx); + dialogPhotoSelect.show(); + dialogPhotoSelect.setOnSelectClickListener(new DialogPhotoSelect.onSelectClickListener() { + @Override + public void onTakePhoto() { + doTakePhoto(ctx); + } + + @Override + public void onSelectPhoto() { + doSelectPhoto(ctx); + } + }); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/ShellUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ShellUtils.java new file mode 100644 index 0000000..caf3f45 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ShellUtils.java @@ -0,0 +1,201 @@ +package com.dahe.mylibrary.utils; + + +import java.io.BufferedReader; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.List; + +/** + *
+ *     author: Blankj
+ *     blog  : http://blankj.com
+ *     time  : 2016/08/07
+ *     desc  : utils about shell
+ * 
+ */ +public final class ShellUtils { + + private static final String LINE_SEP = System.getProperty("line.separator"); + + private ShellUtils() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + /** + * Execute the command. + * + * @param command The command. + * @param isRooted True to use root, false otherwise. + * @return the single {@link CommandResult} instance + */ + public static CommandResult execCmd(final String command, final boolean isRooted) { + return execCmd(new String[]{command}, isRooted, true); + } + + /** + * Execute the command. + * + * @param commands The commands. + * @param isRooted True to use root, false otherwise. + * @return the single {@link CommandResult} instance + */ + public static CommandResult execCmd(final List commands, final boolean isRooted) { + return execCmd(commands == null ? null : commands.toArray(new String[]{}), isRooted, true); + } + + /** + * Execute the command. + * + * @param commands The commands. + * @param isRooted True to use root, false otherwise. + * @return the single {@link CommandResult} instance + */ + public static CommandResult execCmd(final String[] commands, final boolean isRooted) { + return execCmd(commands, isRooted, true); + } + + /** + * Execute the command. + * + * @param command The command. + * @param isRooted True to use root, false otherwise. + * @param isNeedResultMsg True to node_return the message of result, false otherwise. + * @return the single {@link CommandResult} instance + */ + public static CommandResult execCmd(final String command, + final boolean isRooted, + final boolean isNeedResultMsg) { + return execCmd(new String[]{command}, isRooted, isNeedResultMsg); + } + + /** + * Execute the command. + * + * @param commands The commands. + * @param isRooted True to use root, false otherwise. + * @param isNeedResultMsg True to node_return the message of result, false otherwise. + * @return the single {@link CommandResult} instance + */ + public static CommandResult execCmd(final List commands, + final boolean isRooted, + final boolean isNeedResultMsg) { + return execCmd(commands == null ? null : commands.toArray(new String[]{}), + isRooted, + isNeedResultMsg); + } + + /** + * Execute the command. + * + * @param commands The commands. + * @param isRooted True to use root, false otherwise. + * @param isNeedResultMsg True to node_return the message of result, false otherwise. + * @return the single {@link CommandResult} instance + */ + public static CommandResult execCmd(final String[] commands, + final boolean isRooted, + final boolean isNeedResultMsg) { + int result = -1; + if (commands == null || commands.length == 0) { + return new CommandResult(result, "", ""); + } + Process process = null; + BufferedReader successResult = null; + BufferedReader errorResult = null; + StringBuilder successMsg = null; + StringBuilder errorMsg = null; + DataOutputStream os = null; + try { + process = Runtime.getRuntime().exec(isRooted ? "su" : "sh"); + os = new DataOutputStream(process.getOutputStream()); + for (String command : commands) { + if (command == null) continue; + os.write(command.getBytes()); + os.writeBytes(LINE_SEP); + os.flush(); + } + os.writeBytes("exit" + LINE_SEP); + os.flush(); + result = process.waitFor(); + if (isNeedResultMsg) { + successMsg = new StringBuilder(); + errorMsg = new StringBuilder(); + successResult = new BufferedReader( + new InputStreamReader(process.getInputStream(), "UTF-8") + ); + errorResult = new BufferedReader( + new InputStreamReader(process.getErrorStream(), "UTF-8") + ); + String line; + if ((line = successResult.readLine()) != null) { + successMsg.append(line); + while ((line = successResult.readLine()) != null) { + successMsg.append(LINE_SEP).append(line); + } + } + if ((line = errorResult.readLine()) != null) { + errorMsg.append(line); + while ((line = errorResult.readLine()) != null) { + errorMsg.append(LINE_SEP).append(line); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (os != null) { + os.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + try { + if (successResult != null) { + successResult.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + try { + if (errorResult != null) { + errorResult.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } + if (process != null) { + process.destroy(); + } + } + return new CommandResult( + result, + successMsg == null ? "" : successMsg.toString(), + errorMsg == null ? "" : errorMsg.toString() + ); + } + + /** + * The result of command. + */ + public static class CommandResult { + public int result; + public String successMsg; + public String errorMsg; + + public CommandResult(final int result, final String successMsg, final String errorMsg) { + this.result = result; + this.successMsg = successMsg; + this.errorMsg = errorMsg; + } + + @Override + public String toString() { + return "result: " + result + "\n" + + "successMsg: " + successMsg + "\n" + + "errorMsg: " + errorMsg; + } + } +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/SmsTimeUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/SmsTimeUtils.java new file mode 100644 index 0000000..4fcad9b --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/SmsTimeUtils.java @@ -0,0 +1,148 @@ +package com.dahe.mylibrary.utils; + +import android.content.Context; +import android.os.Handler; +import android.os.Message; +import android.widget.TextView; + +import java.util.Timer; +import java.util.TimerTask; + +/** + * 文件名:SmsTimeUtils + */ +public class SmsTimeUtils { + + /*倒计时时长 单位:秒*/ + private final static int COUNT = 60; + /*当前做*/ + private static int CURR_COUNT = 0; + /*发送验证码*/ + public final static int SETTING_FINANCE_ACCOUNT_TIME = 1; + public final static int WITHDRAW_CASH = 4; + + private static long SETTING_FINANCE_ACCOUNT_TIME_END = 0; + private static long WITHDRAW_CASH_END = 0; + + private static Timer countdownTimer; + private static TextView tvSendCode; + private static Context mContext; + + public static String currPhone;//记录获取验证码的手机号,倒计时结束后清空 + + /** + * 检查是否超过60秒 + * 给当前要从多少开始倒数赋值 + * + * @param first true 表示第一次 false不是 + * @return 是否需要调用startCountdown(TextView textView),主要用于判断在重新打开页,需不需要继续倒计时 + */ + public static boolean check(int type, boolean first) { + long data = System.currentTimeMillis(); + long time = 0; + switch (type) { + case SETTING_FINANCE_ACCOUNT_TIME: + time = SETTING_FINANCE_ACCOUNT_TIME_END; + break; + case WITHDRAW_CASH: + time = WITHDRAW_CASH_END; + break; + } + if (data > time) { + /*主要是区别于是否是第一次进入。第一次进入不需要赋值*/ + if (!first) { + CURR_COUNT = COUNT; + time = data + COUNT * 1000; + switch (type) { + case SETTING_FINANCE_ACCOUNT_TIME: + SETTING_FINANCE_ACCOUNT_TIME_END = time; + break; + case WITHDRAW_CASH: + WITHDRAW_CASH_END = time; + break; + } + } + return false; + } else { + int the_difference = ((int) (time - data)) / 1000; + CURR_COUNT = the_difference; + return true; + } + } + + /** + * 开始倒计时 + * + * @param textView 控制倒计时的view + */ + public static void startCountdown(TextView textView, Context context) { + tvSendCode = textView; + mContext = context; + if (countdownTimer == null) { + countdownTimer = new Timer(); + countdownTimer.schedule(new TimerTask() { + @Override + public void run() { + Message msg = new Message(); + msg.what = CURR_COUNT--; + handler.sendMessage(msg); + } + }, 0, 1000); + } + } + + + /** + * 开始倒计时 + * + * @param textView 控制倒计时的view + */ + public static void startCountdown(TextView textView, Context context,String phone) { + currPhone = phone; + tvSendCode = textView; + mContext = context; + if (countdownTimer == null) { + countdownTimer = new Timer(); + countdownTimer.schedule(new TimerTask() { + @Override + public void run() { + Message msg = new Message(); + msg.what = CURR_COUNT--; + handler.sendMessage(msg); + } + }, 0, 1000); + } + } + + private static Handler handler = new Handler() { + public void handleMessage(Message msg) { + if (msg.what <= 0) { + if (countdownTimer != null) { + countdownTimer.cancel(); + countdownTimer = null; + } + currPhone=""; + tvSendCode.setText("获取验证码"); + tvSendCode.setEnabled(true); + } else { + tvSendCode.setText(msg.what + "s后重新获取"); + tvSendCode.setEnabled(false); + } + super.handleMessage(msg); + } + }; + + + public static void stopCountdown(TextView textView, Context context){ + tvSendCode = textView; + mContext = context; + if (countdownTimer != null) { + countdownTimer.cancel(); + countdownTimer=null; + currPhone=""; + SETTING_FINANCE_ACCOUNT_TIME_END =0; + tvSendCode.setText("获取验证码"); + tvSendCode.setEnabled(true); + } + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBar.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBar.java new file mode 100644 index 0000000..d7bcaf4 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBar.java @@ -0,0 +1,111 @@ +package com.dahe.mylibrary.utils; + +import android.app.Activity; +import android.os.Build; +import android.view.View; +import android.view.Window; + +import androidx.annotation.ColorInt; +import androidx.annotation.NonNull; +import androidx.appcompat.widget.Toolbar; + +import com.google.android.material.appbar.AppBarLayout; +import com.google.android.material.appbar.CollapsingToolbarLayout; + + +/** + * Utils for status bar + * Created by qiu on 3/29/16. + */ +public class StatusBar { + + //Get alpha color + static int calculateStatusBarColor(int color, int alpha) { + float a = 1 - alpha / 255f; + int red = color >> 16 & 0xff; + int green = color >> 8 & 0xff; + int blue = color & 0xff; + red = (int) (red * a + 0.5); + green = (int) (green * a + 0.5); + blue = (int) (blue * a + 0.5); + return 0xff << 24 | red << 16 | green << 8 | blue; + } + + /** + * set statusBarColor + * @param statusColor color + * @param alpha 0 - 255 + */ + public static void setStatusBarColor(@NonNull Activity activity, @ColorInt int statusColor, int alpha) { + setStatusBarColor(activity, calculateStatusBarColor(statusColor, alpha)); + } + + public static void setStatusBarColor(@NonNull Activity activity, @ColorInt int statusColor) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + StatusBarCompatLollipop.setStatusBarColor(activity, statusColor); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + StatusBarCompatKitKat.setStatusBarColor(activity, statusColor); + } + } + + public static void translucentStatusBar(@NonNull Activity activity) { + translucentStatusBar(activity, false); + } + + /** + * change to full screen mode + * @param hideStatusBarBackground hide status bar alpha Background when SDK > 21, true if hide it + */ + public static void translucentStatusBar(@NonNull Activity activity, boolean hideStatusBarBackground) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + StatusBarCompatLollipop.translucentStatusBar(activity, hideStatusBarBackground); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + StatusBarCompatKitKat.translucentStatusBar(activity); + } + } + + public static void setStatusBarColorForCollapsingToolbar(@NonNull Activity activity, AppBarLayout appBarLayout, CollapsingToolbarLayout collapsingToolbarLayout, + Toolbar toolbar, @ColorInt int statusColor) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + StatusBarCompatLollipop.setStatusBarColorForCollapsingToolbar(activity, appBarLayout, collapsingToolbarLayout, toolbar, statusColor); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { + StatusBarCompatKitKat.setStatusBarColorForCollapsingToolbar(activity, appBarLayout, collapsingToolbarLayout, toolbar, statusColor); + } + } + + public static void changeToLightStatusBar(@NonNull Activity activity) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + return; + } + if (activity == null) { + return; + } + Window window = activity.getWindow(); + if (window == null) { + return; + } + View decorView = window.getDecorView(); + if (decorView == null) { + return; + } + decorView.setSystemUiVisibility(decorView.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + } + + public static void cancelLightStatusBar(@NonNull Activity activity) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + return; + } + if (activity == null) { + return; + } + Window window = activity.getWindow(); + if (window == null) { + return; + } + View decorView = window.getDecorView(); + if (decorView == null) { + return; + } + decorView.setSystemUiVisibility(decorView.getSystemUiVisibility() ^ View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBarCompatKitKat.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBarCompatKitKat.java new file mode 100644 index 0000000..5e9c98e --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBarCompatKitKat.java @@ -0,0 +1,221 @@ +package com.dahe.mylibrary.utils; + +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Context; +import android.os.Build; +import android.view.Gravity; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; +import android.widget.FrameLayout; + +import androidx.appcompat.widget.Toolbar; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.core.view.ViewCompat; + +import com.google.android.material.appbar.AppBarLayout; +import com.google.android.material.appbar.CollapsingToolbarLayout; + + +/** + * After kitkat add fake status bar + * Created by qiu on 8/27/16. + */ +@TargetApi(Build.VERSION_CODES.KITKAT) +class StatusBarCompatKitKat { + + private static final String TAG_FAKE_STATUS_BAR_VIEW = "statusBarView"; + private static final String TAG_MARGIN_ADDED = "marginAdded"; + + /** + * node_return statusBar's Height in pixels + */ + private static int getStatusBarHeight(Context context) { + int result = 0; + int resId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); + if (resId > 0) { + result = context.getResources().getDimensionPixelOffset(resId); + } + return result; + } + + /** + * 1. Add fake statusBarView. + * 2. set tag to statusBarView. + */ + private static View addFakeStatusBarView(Activity activity, int statusBarColor, int statusBarHeight) { + Window window = activity.getWindow(); + ViewGroup mDecorView = (ViewGroup) window.getDecorView(); + + View mStatusBarView = new View(activity); + FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, statusBarHeight); + layoutParams.gravity = Gravity.TOP; + mStatusBarView.setLayoutParams(layoutParams); + mStatusBarView.setBackgroundColor(statusBarColor); + mStatusBarView.setTag(TAG_FAKE_STATUS_BAR_VIEW); + + mDecorView.addView(mStatusBarView); + return mStatusBarView; + } + + /** + * use reserved order to remove is more quickly. + */ + private static void removeFakeStatusBarViewIfExist(Activity activity) { + Window window = activity.getWindow(); + ViewGroup mDecorView = (ViewGroup) window.getDecorView(); + + View fakeView = mDecorView.findViewWithTag(TAG_FAKE_STATUS_BAR_VIEW); + if (fakeView != null) { + mDecorView.removeView(fakeView); + } + } + + /** + * add marginTop to simulate set FitsSystemWindow true + */ + private static void addMarginTopToContentChild(View mContentChild, int statusBarHeight) { + if (mContentChild == null) { + return; + } + if (!TAG_MARGIN_ADDED.equals(mContentChild.getTag())) { + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mContentChild.getLayoutParams(); + lp.topMargin += statusBarHeight; + mContentChild.setLayoutParams(lp); + mContentChild.setTag(TAG_MARGIN_ADDED); + } + } + + /** + * remove marginTop to simulate set FitsSystemWindow false + */ + private static void removeMarginTopOfContentChild(View mContentChild, int statusBarHeight) { + if (mContentChild == null) { + return; + } + if (TAG_MARGIN_ADDED.equals(mContentChild.getTag())) { + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mContentChild.getLayoutParams(); + lp.topMargin -= statusBarHeight; + mContentChild.setLayoutParams(lp); + mContentChild.setTag(null); + } + } + + /** + * set StatusBarColor + * + * 1. set Window Flag : WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS + * 2. removeFakeStatusBarViewIfExist + * 3. addFakeStatusBarView + * 4. addMarginTopToContentChild + * 5. cancel ContentChild's fitsSystemWindow + */ + static void setStatusBarColor(Activity activity, int statusColor) { + Window window = activity.getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + + ViewGroup mContentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT); + View mContentChild = mContentView.getChildAt(0); + int statusBarHeight = getStatusBarHeight(activity); + + removeFakeStatusBarViewIfExist(activity); + addFakeStatusBarView(activity, statusColor, statusBarHeight); + addMarginTopToContentChild(mContentChild, statusBarHeight); + + if (mContentChild != null) { + ViewCompat.setFitsSystemWindows(mContentChild, false); + } + } + + /** + * translucentStatusBar + * + * 1. set Window Flag : WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS + * 2. removeFakeStatusBarViewIfExist + * 3. removeMarginTopOfContentChild + * 4. cancel ContentChild's fitsSystemWindow + */ + static void translucentStatusBar(Activity activity) { + Window window = activity.getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + + ViewGroup mContentView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT); + View mContentChild = mContentView.getChildAt(0); + + removeFakeStatusBarViewIfExist(activity); + removeMarginTopOfContentChild(mContentChild, getStatusBarHeight(activity)); + if (mContentChild != null) { + ViewCompat.setFitsSystemWindows(mContentChild, false); + } + } + + /** + * compat for CollapsingToolbarLayout + * + * 1. set Window Flag : WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS + * 2. set FitsSystemWindows for views. + * 3. add Toolbar's height, let it layout from top, then add paddingTop to layout normal. + * 4. removeFakeStatusBarViewIfExist + * 5. removeMarginTopOfContentChild + * 6. add OnOffsetChangedListener to change statusBarView's alpha + */ + static void setStatusBarColorForCollapsingToolbar(Activity activity, final AppBarLayout appBarLayout, final CollapsingToolbarLayout collapsingToolbarLayout, + Toolbar toolbar, int statusColor) { + Window window = activity.getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + ViewGroup mContentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT); + + View mContentChild = mContentView.getChildAt(0); + mContentChild.setFitsSystemWindows(false); + ((View) appBarLayout.getParent()).setFitsSystemWindows(false); + appBarLayout.setFitsSystemWindows(false); + collapsingToolbarLayout.setFitsSystemWindows(false); + collapsingToolbarLayout.getChildAt(0).setFitsSystemWindows(false); + + toolbar.setFitsSystemWindows(false); + if (toolbar.getTag() == null) { + CollapsingToolbarLayout.LayoutParams lp = (CollapsingToolbarLayout.LayoutParams) toolbar.getLayoutParams(); + int statusBarHeight = getStatusBarHeight(activity); + lp.height += statusBarHeight; + toolbar.setLayoutParams(lp); + toolbar.setPadding(toolbar.getPaddingLeft(), toolbar.getPaddingTop() + statusBarHeight, toolbar.getPaddingRight(), toolbar.getPaddingBottom()); + toolbar.setTag(true); + } + + int statusBarHeight = getStatusBarHeight(activity); + removeFakeStatusBarViewIfExist(activity); + removeMarginTopOfContentChild(mContentChild, statusBarHeight); + final View statusView = addFakeStatusBarView(activity, statusColor, statusBarHeight); + + CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams()).getBehavior(); + if (behavior != null && behavior instanceof AppBarLayout.Behavior) { + int verticalOffset = ((AppBarLayout.Behavior) behavior).getTopAndBottomOffset(); + if (Math.abs(verticalOffset) > appBarLayout.getHeight() - collapsingToolbarLayout.getScrimVisibleHeightTrigger()) { + statusView.setAlpha(1f); + } else { + statusView.setAlpha(0f); + } + } else { + statusView.setAlpha(0f); + } + + appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { + @Override + public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { + if (Math.abs(verticalOffset) > appBarLayout.getHeight() - collapsingToolbarLayout.getScrimVisibleHeightTrigger()) { + if (statusView.getAlpha() == 0) { + statusView.animate().cancel(); + statusView.animate().alpha(1f).setDuration(collapsingToolbarLayout.getScrimAnimationDuration()).start(); + } + } else { + if (statusView.getAlpha() == 1) { + statusView.animate().cancel(); + statusView.animate().alpha(0f).setDuration(collapsingToolbarLayout.getScrimAnimationDuration()).start(); + } + } + } + }); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBarCompatLollipop.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBarCompatLollipop.java new file mode 100644 index 0000000..c6e64ae --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBarCompatLollipop.java @@ -0,0 +1,193 @@ +package com.dahe.mylibrary.utils; + +import android.animation.ValueAnimator; +import android.annotation.TargetApi; +import android.app.Activity; +import android.content.Context; +import android.graphics.Color; +import android.os.Build; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.view.WindowManager; + +import androidx.appcompat.widget.Toolbar; +import androidx.coordinatorlayout.widget.CoordinatorLayout; +import androidx.core.view.OnApplyWindowInsetsListener; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsCompat; + +import com.google.android.material.appbar.AppBarLayout; +import com.google.android.material.appbar.CollapsingToolbarLayout; + + +/** + * After Lollipop use system method. + * Created by qiu on 8/27/16. + */ +@TargetApi(Build.VERSION_CODES.LOLLIPOP) +class StatusBarCompatLollipop { + + /** + * node_return statusBar's Height in pixels + */ + private static int getStatusBarHeight(Context context) { + int result = 0; + int resId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); + if (resId > 0) { + result = context.getResources().getDimensionPixelOffset(resId); + } + return result; + } + + /** + * set StatusBarColor + * + * 1. set Flags to call setStatusBarColor + * 2. call setSystemUiVisibility to clear translucentStatusBar's Flag. + * 3. set FitsSystemWindows to false + */ + static void setStatusBarColor(Activity activity, int statusColor) { + Window window = activity.getWindow(); + + window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(statusColor); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + + ViewGroup mContentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT); + View mChildView = mContentView.getChildAt(0); + if (mChildView != null) { + ViewCompat.setFitsSystemWindows(mChildView, false); + ViewCompat.requestApplyInsets(mChildView); + } + } + + /** + * translucentStatusBar(full-screen) + * + * 1. set Flags to full-screen + * 2. set FitsSystemWindows to false + * + * @param hideStatusBarBackground hide statusBar's shadow + */ + static void translucentStatusBar(Activity activity, boolean hideStatusBarBackground) { + Window window = activity.getWindow(); + + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + if (hideStatusBarBackground) { + window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + window.setStatusBarColor(Color.TRANSPARENT); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); + } else { + window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } + + ViewGroup mContentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT); + View mChildView = mContentView.getChildAt(0); + if (mChildView != null) { + ViewCompat.setFitsSystemWindows(mChildView, false); + ViewCompat.requestApplyInsets(mChildView); + } + } + + /** + * compat for CollapsingToolbarLayout + * + * 1. change to full-screen mode(like translucentStatusBar). + * 2. cancel CollapsingToolbarLayout's WindowInsets, let it layout as normal(now setStatusBarScrimColor is useless). + * 3. set View's FitsSystemWindow to false. + * 4. add Toolbar's height, let it layout from top, then add paddingTop to layout normal. + * 5. change statusBarColor by AppBarLayout's offset. + * 6. add Listener to change statusBarColor + */ + static void setStatusBarColorForCollapsingToolbar(Activity activity, final AppBarLayout appBarLayout, final CollapsingToolbarLayout collapsingToolbarLayout, + Toolbar toolbar, final int statusColor) { + final Window window = activity.getWindow(); + + window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); + window.setStatusBarColor(Color.TRANSPARENT); + window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + + ViewCompat.setOnApplyWindowInsetsListener(collapsingToolbarLayout, new OnApplyWindowInsetsListener() { + @Override + public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) { + return insets; + } + }); + + ViewGroup mContentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT); + View mChildView = mContentView.getChildAt(0); + if (mChildView != null) { + ViewCompat.setFitsSystemWindows(mChildView, false); + ViewCompat.requestApplyInsets(mChildView); + } + + ((View) appBarLayout.getParent()).setFitsSystemWindows(false); + appBarLayout.setFitsSystemWindows(false); + + toolbar.setFitsSystemWindows(false); + if (toolbar.getTag() == null) { + CollapsingToolbarLayout.LayoutParams lp = (CollapsingToolbarLayout.LayoutParams) toolbar.getLayoutParams(); + int statusBarHeight = getStatusBarHeight(activity); + lp.height += statusBarHeight; + toolbar.setLayoutParams(lp); + toolbar.setPadding(toolbar.getPaddingLeft(), toolbar.getPaddingTop() + statusBarHeight, toolbar.getPaddingRight(), toolbar.getPaddingBottom()); + toolbar.setTag(true); + } + + CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams()).getBehavior(); + if (behavior != null && behavior instanceof AppBarLayout.Behavior) { + int verticalOffset = ((AppBarLayout.Behavior) behavior).getTopAndBottomOffset(); + if (Math.abs(verticalOffset) > appBarLayout.getHeight() - collapsingToolbarLayout.getScrimVisibleHeightTrigger()) { + window.setStatusBarColor(statusColor); + } else { + window.setStatusBarColor(Color.TRANSPARENT); + } + } else { + window.setStatusBarColor(Color.TRANSPARENT); + } + + collapsingToolbarLayout.setFitsSystemWindows(false); + appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { + @Override + public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { + if (Math.abs(verticalOffset) > appBarLayout.getHeight() - collapsingToolbarLayout.getScrimVisibleHeightTrigger()) { + if (window.getStatusBarColor() != statusColor) { + startColorAnimation(window.getStatusBarColor(), statusColor, collapsingToolbarLayout.getScrimAnimationDuration(), window); + } + } else { + if (window.getStatusBarColor() != Color.TRANSPARENT) { + startColorAnimation(window.getStatusBarColor(), Color.TRANSPARENT, collapsingToolbarLayout.getScrimAnimationDuration(), window); + } + } + } + }); + collapsingToolbarLayout.getChildAt(0).setFitsSystemWindows(false); + collapsingToolbarLayout.setStatusBarScrimColor(statusColor); + } + + /** + * use ValueAnimator to change statusBarColor when using collapsingToolbarLayout + */ + static void startColorAnimation(int startColor, int endColor, long duration, final Window window) { + if (sAnimator != null) { + sAnimator.cancel(); + } + sAnimator = ValueAnimator.ofArgb(startColor, endColor) + .setDuration(duration); + sAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + if (window != null) { + window.setStatusBarColor((Integer) valueAnimator.getAnimatedValue()); + } + } + }); + sAnimator.start(); + } + + private static ValueAnimator sAnimator; +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/StringUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/StringUtils.java new file mode 100644 index 0000000..b71df3a --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/StringUtils.java @@ -0,0 +1,99 @@ +package com.dahe.mylibrary.utils; + +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.net.URLEncoder; + +public class StringUtils { + + public static String byte2hex(byte[] b) { + + String str = ""; + String stmp = ""; + + int length = b.length; + + for (int n = 0; n < length; n++) { + stmp = (Integer.toHexString(b[n] & 0XFF)); + if (stmp.length() == 1) { + str += "0"; + } + str += stmp; + } + + return str.toLowerCase(); + } + + public static String nullToStrTrim(String str) { + + if (str == null) { + str = ""; + } + + return str.trim(); + } + + public static boolean isNotEmpty(String str) { + + return ((str != null) && (str.trim().length() > 0 && !"null".equals(str))); + } + + public static boolean isEmpty(String str) { + + return !isNotEmpty(str); + } + + public static int getRealLength(String str) { + + return getRealLength(str, "utf-8"); + } + + public static int getRealLength(String str, String charsetName) { + + str = nullToStrTrim(str); + + try { + return str.getBytes(charsetName).length; + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + return 0; + } + } + public static String encode(String str, String enc) { + + String strEncode = ""; + + try { + if (str != null) + strEncode = URLEncoder.encode(str, enc); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + return strEncode; + } + + public static String decode(String str, String enc) { + + String strDecode = ""; + + try { + if (str != null) + strDecode = URLDecoder.decode(str, enc); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + return strDecode; + } + + public static String encode(String str) { + + return encode(str, "utf-8"); + } + + public static String decode(String str) { + + return decode(str, "utf-8"); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimeConstants.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimeConstants.java new file mode 100644 index 0000000..d1951da --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimeConstants.java @@ -0,0 +1,44 @@ +package com.dahe.mylibrary.utils; + + +import androidx.annotation.IntDef; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + *
+ *     author: Blankj
+ *     blog  : http://blankj.com
+ *     time  : 2017/03/13
+ *     desc  : 时间相关常量
+ * 
+ */ +public final class TimeConstants { + + /** + * 毫秒与毫秒的倍数 + */ + public static final int MSEC = 1; + /** + * 秒与毫秒的倍数 + */ + public static final int SEC = 1000; + /** + * 分与毫秒的倍数 + */ + public static final int MIN = 60000; + /** + * 时与毫秒的倍数 + */ + public static final int HOUR = 3600000; + /** + * 天与毫秒的倍数 + */ + public static final int DAY = 86400000; + + @IntDef({MSEC, SEC, MIN, HOUR, DAY}) + @Retention(RetentionPolicy.SOURCE) + public @interface Unit { + } +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimeUtil.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimeUtil.java new file mode 100644 index 0000000..0cc51bc --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimeUtil.java @@ -0,0 +1,1703 @@ +package com.dahe.mylibrary.utils; + +import android.text.TextUtils; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.Locale; + +/** + *
+ *     author: LiJia
+ *     time  : 2021/08/02
+ *     desc  : 时间相关工具类
+ * 
+ */ +public final class TimeUtil { + + /** + *

在工具类中经常使用到工具类的格式化描述,这个主要是一个日期的操作类,所以日志格式主要使用 SimpleDateFormat的定义格式.

+ * 格式的意义如下: 日期和时间模式
+ *

日期和时间格式由日期和时间模式字符串指定。在日期和时间模式字符串中,未加引号的字母 'A' 到 'Z' 和 'a' 到 'z' + * 被解释为模式字母,用来表示日期或时间字符串元素。文本可以使用单引号 (') 引起来,以免进行解释。"''" + * 表示单引号。所有其他字符均不解释;只是在格式化时将它们简单复制到输出字符串,或者在分析时与输入字符串进行匹配。 + *

+ * 定义了以下模式字母(所有其他字符 'A' 到 'Z' 和 'a' 到 'z' 都被保留):
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
字母日期或时间元素表示示例
GEra 标志符TextAD
y Year 1996; 96
M 年中的月份 Month July; Jul; 07
w 年中的周数 Number 27
W 月份中的周数 Number 2
D 年中的天数 Number 189
d 月份中的天数 Number 10
F 月份中的星期 Number 2
E 星期中的天数 Text Tuesday; Tue
a Am/pm 标记 Text PM
H 一天中的小时数(0-23) Number 0
k 一天中的小时数(1-24) Number 24
K am/pm 中的小时数(0-11) Number 0
h am/pm 中的小时数(1-12) Number 12
m 小时中的分钟数 Number 30
s 分钟中的秒数 Number 55
S 毫秒数 Number 978
z 时区 General time zone Pacific Standard Time; PST; GMT-08:00
Z 时区 RFC 822 time zone -0800
+ *
+     *                                             HH:mm    15:44
+     *                                            h:mm a    3:44 下午
+     *                                           HH:mm z    15:44 CST
+     *                                           HH:mm Z    15:44 +0800
+     *                                        HH:mm zzzz    15:44 中国标准时间
+     *                                          HH:mm:ss    15:44:40
+     *                                        yyyy-MM-dd    2016-08-12
+     *                                  yyyy-MM-dd HH:mm    2016-08-12 15:44
+     *                               yyyy-MM-dd HH:mm:ss    2016-08-12 15:44:40
+     *                          yyyy-MM-dd HH:mm:ss zzzz    2016-08-12 15:44:40 中国标准时间
+     *                     EEEE yyyy-MM-dd HH:mm:ss zzzz    星期五 2016-08-12 15:44:40 中国标准时间
+     *                          yyyy-MM-dd HH:mm:ss.SSSZ    2016-08-12 15:44:40.461+0800
+     *                        yyyy-MM-dd'T'HH:mm:ss.SSSZ    2016-08-12T15:44:40.461+0800
+     *                      yyyy.MM.dd G 'at' HH:mm:ss z    2016.08.12 公元 at 15:44:40 CST
+     *                                            K:mm a    3:44 下午
+     *                                  EEE, MMM d, ''yy    星期五, 八月 12, '16
+     *                             hh 'o''clock' a, zzzz    03 o'clock 下午, 中国标准时间
+     *                      yyyyy.MMMMM.dd GGG hh:mm aaa    02016.八月.12 公元 03:44 下午
+     *                        EEE, d MMM yyyy HH:mm:ss Z    星期五, 12 八月 2016 15:44:40 +0800
+     *                                     yyMMddHHmmssZ    160812154440+0800
+     *                        yyyy-MM-dd'T'HH:mm:ss.SSSZ    2016-08-12T15:44:40.461+0800
+     * EEEE 'DATE('yyyy-MM-dd')' 'TIME('HH:mm:ss')' zzzz    星期五 DATE(2016-08-12) TIME(15:44:40) 中国标准时间
+     * 
+ * 注意:SimpleDateFormat不是线程安全的,线程安全需用{@code ThreadLocal} + */ + + private static final DateFormat DEFAULT_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()); + private static final DateFormat DEFAULT_FORMAT2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZSS:SS", Locale.getDefault()); + private static final DateFormat DEFAULT_FORMAT3 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.getDefault()); + + private TimeUtil() { + throw new UnsupportedOperationException("u can't instantiate me..."); + } + + /** + * 将时间戳转为时间字符串 + *

格式为yyyy-MM-dd HH:mm:ss

+ * + * @param millis 毫秒时间戳 + * @return 时间字符串 + */ + public static String millis2String(final long millis) { + return millis2String(millis, DEFAULT_FORMAT); + } + + /** + * 将时间戳转为时间字符串 + *

格式为format

+ * + * @param millis 毫秒时间戳 + * @param format 时间格式 + * @return 时间字符串 + */ + public static String millis2String(final long millis, final DateFormat format) { + return format.format(new Date(millis)); + } + + /** + * 将时间字符串转为时间戳 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 毫秒时间戳 + */ + public static long string2Millis(final String time) { + if (TextUtils.isEmpty(time)){ + return -1; + } + return string2Millis(time, DEFAULT_FORMAT); + } + + /** + * 将时间字符串转为时间戳 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 毫秒时间戳 + */ + public static long string2Millis(final String time, final DateFormat format) { + try { + return format.parse(time).getTime(); + } catch (ParseException e) { + e.printStackTrace(); + } + return -1; + } + + /** + * 将时间字符串转为时间戳 + *

time格式为format

+ * + * @param time 时间字符串 + * @return 毫秒时间戳 + */ + public static String string2String(final String time,final SimpleDateFormat format) { + try { + return date2String(format.parse(time)); +// return DEFAULT_FORMAT.format(DEFAULT_FORMAT2.parse(time).getTime()); + } catch (Exception e) { + e.printStackTrace(); + } + return ""; + } + + /** + * 将时间字符串转为Date类型 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return Date类型 + */ + public static Date string2Date(final String time) { + return string2Date(time, DEFAULT_FORMAT); + } + + /** + * 将时间字符串转为Date类型 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return Date类型 + */ + public static Date string2Date(final String time, final DateFormat format) { + try { + return format.parse(time); + } catch (ParseException e) { + e.printStackTrace(); + } + return null; + } + + /** + * 将Date类型转为时间字符串 + *

格式为yyyy-MM-dd HH:mm:ss

+ * + * @param date Date类型时间 + * @return 时间字符串 + */ + public static String date2String(final Date date) { + return date2String(date, DEFAULT_FORMAT); + } + + /** + * 将Date类型转为时间字符串 + *

格式为format

+ * + * @param date Date类型时间 + * @param format 时间格式 + * @return 时间字符串 + */ + public static String date2String(final Date date, final DateFormat format) { + return format.format(date); + } + + /** + * 将Date类型转为时间戳 + * + * @param date Date类型时间 + * @return 毫秒时间戳 + */ + public static long date2Millis(final Date date) { + return date.getTime(); + } + + /** + * 将时间戳转为Date类型 + * + * @param millis 毫秒时间戳 + * @return Date类型时间 + */ + public static Date millis2Date(final long millis) { + return new Date(millis); + } + + /** + * 获取两个时间差(单位:unit) + *

time0和time1格式都为yyyy-MM-dd HH:mm:ss

+ * + * @param time0 时间字符串0 + * @param time1 时间字符串1 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return unit时间戳 + */ + public static long getTimeSpan(final String time0, final String time1, @TimeConstants.Unit final int unit) { + return getTimeSpan(time0, time1, DEFAULT_FORMAT, unit); + } + + /** + * 获取两个时间差(单位:unit) + *

time0和time1格式都为format

+ * + * @param time0 时间字符串0 + * @param time1 时间字符串1 + * @param format 时间格式 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return unit时间戳 + */ + public static long getTimeSpan(final String time0, final String time1, final DateFormat format, @TimeConstants.Unit final int unit) { + return millis2TimeSpan(Math.abs(string2Millis(time0, format) - string2Millis(time1, format)), unit); + } + + /** + * 获取两个时间差(单位:unit) + * + * @param date0 Date类型时间0 + * @param date1 Date类型时间1 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return unit时间戳 + */ + public static long getTimeSpan(final Date date0, final Date date1, @TimeConstants.Unit final int unit) { + return millis2TimeSpan(Math.abs(date2Millis(date0) - date2Millis(date1)), unit); + } + + /** + * 获取两个时间差(单位:unit) + * + * @param millis0 毫秒时间戳0 + * @param millis1 毫秒时间戳1 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return unit时间戳 + */ + public static long getTimeSpan(final long millis0, final long millis1, @TimeConstants.Unit final int unit) { + return millis2TimeSpan(Math.abs(millis0 - millis1), unit); + } + + /** + * 获取合适型两个时间差 + *

time0和time1格式都为yyyy-MM-dd HH:mm:ss

+ * + * @param time0 时间字符串0 + * @param time1 时间字符串1 + * @param precision 精度 + *

precision = 0,返回null

+ *

precision = 1,返回天

+ *

precision = 2,返回天和小时

+ *

precision = 3,返回天、小时和分钟

+ *

precision = 4,返回天、小时、分钟和秒

+ *

precision >= 5,返回天、小时、分钟、秒和毫秒

+ * @return 合适型两个时间差 + */ + public static String getFitTimeSpan(final String time0, final String time1, final int precision) { + if (TextUtils.isEmpty(time0)||TextUtils.isEmpty(time1)){ + return ""; + } + return millis2FitTimeSpan(Math.abs(string2Millis(time0, DEFAULT_FORMAT) - string2Millis(time1, DEFAULT_FORMAT)), precision); + } + + /** + * 获取合适型两个时间差 + *

time0和time1格式都为format

+ * + * @param time0 时间字符串0 + * @param time1 时间字符串1 + * @param format 时间格式 + * @param precision 精度 + *

precision = 0,返回null

+ *

precision = 1,返回天

+ *

precision = 2,返回天和小时

+ *

precision = 3,返回天、小时和分钟

+ *

precision = 4,返回天、小时、分钟和秒

+ *

precision >= 5,返回天、小时、分钟、秒和毫秒

+ * @return 合适型两个时间差 + */ + public static String getFitTimeSpan(final String time0, final String time1, final DateFormat format, final int precision) { + return millis2FitTimeSpan(Math.abs(string2Millis(time0, format) - string2Millis(time1, format)), precision); + } + + /** + * 获取合适型两个时间差 + * + * @param date0 Date类型时间0 + * @param date1 Date类型时间1 + * @param precision 精度 + *

precision = 0,返回null

+ *

precision = 1,返回天

+ *

precision = 2,返回天和小时

+ *

precision = 3,返回天、小时和分钟

+ *

precision = 4,返回天、小时、分钟和秒

+ *

precision >= 5,返回天、小时、分钟、秒和毫秒

+ * @return 合适型两个时间差 + */ + public static String getFitTimeSpan(final Date date0, final Date date1, final int precision) { + return millis2FitTimeSpan(Math.abs(date2Millis(date0) - date2Millis(date1)), precision); + } + + /** + * 获取合适型两个时间差 + * + * @param millis0 毫秒时间戳1 + * @param millis1 毫秒时间戳2 + * @param precision 精度 + *

precision = 0,返回null

+ *

precision = 1,返回天

+ *

precision = 2,返回天和小时

+ *

precision = 3,返回天、小时和分钟

+ *

precision = 4,返回天、小时、分钟和秒

+ *

precision >= 5,返回天、小时、分钟、秒和毫秒

+ * @return 合适型两个时间差 + */ + public static String getFitTimeSpan(final long millis0, final long millis1, final int precision) { + return millis2FitTimeSpan(Math.abs(millis0 - millis1), precision); + } + + /** + * 获取当前毫秒时间戳 + * + * @return 毫秒时间戳 + */ + public static long getNowMills() { + return System.currentTimeMillis(); + } + + /** + * 获取当前时间字符串 + * + * @param pattern 格式化时间的格式 + * @return + */ + public static String getNowString(String pattern) { + return millis2String(System.currentTimeMillis(), TextUtils.isEmpty(pattern) ? DEFAULT_FORMAT : new SimpleDateFormat(pattern, Locale.getDefault())); + } + + /** + * 获取当前时间字符串 + *

格式为format

+ * + * @param format 时间格式 + * @return 时间字符串 + */ + public static String getNowString(final DateFormat format) { + return millis2String(System.currentTimeMillis(), format); + } + + /** + * 获取当前Date + * + * @return Date类型时间 + */ + public static Date getNowDate() { + return new Date(); + } + + /** + * 获取与当前时间的差(单位:unit) + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return unit时间戳 + */ + public static long getTimeSpanByNow(final String time, @TimeConstants.Unit final int unit) { + return getTimeSpan(getNowString(""), time, DEFAULT_FORMAT, unit); + } + + /** + * 获取与当前时间的差(单位:unit) + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return unit时间戳 + */ + public static long getTimeSpanByNow(final String time, final DateFormat format, @TimeConstants.Unit final int unit) { + return getTimeSpan(getNowString(format), time, format, unit); + } + + /** + * 获取与当前时间的差(单位:unit) + * + * @param date Date类型时间 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return unit时间戳 + */ + public static long getTimeSpanByNow(final Date date, @TimeConstants.Unit final int unit) { + return getTimeSpan(new Date(), date, unit); + } + + /** + * 获取与当前时间的差(单位:unit) + * + * @param millis 毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return unit时间戳 + */ + public static long getTimeSpanByNow(final long millis, @TimeConstants.Unit final int unit) { + return getTimeSpan(System.currentTimeMillis(), millis, unit); + } + + /** + * 获取合适型与当前时间的差 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @param precision 精度 + *
    + *
  • precision = 0,返回null
  • + *
  • precision = 1,返回天
  • + *
  • precision = 2,返回天和小时
  • + *
  • precision = 3,返回天、小时和分钟
  • + *
  • precision = 4,返回天、小时、分钟和秒
  • + *
  • precision >= 5,返回天、小时、分钟、秒和毫秒
  • + *
+ * @return 合适型与当前时间的差 + */ + public static String getFitTimeSpanByNow(final String time, final int precision) { + return getFitTimeSpan(getNowString(""), time, DEFAULT_FORMAT, precision); + } + + /** + * 获取合适型与当前时间的差 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @param precision 精度 + *
    + *
  • precision = 0,返回null
  • + *
  • precision = 1,返回天
  • + *
  • precision = 2,返回天和小时
  • + *
  • precision = 3,返回天、小时和分钟
  • + *
  • precision = 4,返回天、小时、分钟和秒
  • + *
  • precision >= 5,返回天、小时、分钟、秒和毫秒
  • + *
+ * @return 合适型与当前时间的差 + */ + public static String getFitTimeSpanByNow(final String time, final DateFormat format, final int precision) { + return getFitTimeSpan(getNowString(format), time, format, precision); + } + + /** + * 获取合适型与当前时间的差 + * + * @param date Date类型时间 + * @param precision 精度 + *
    + *
  • precision = 0,返回null
  • + *
  • precision = 1,返回天
  • + *
  • precision = 2,返回天和小时
  • + *
  • precision = 3,返回天、小时和分钟
  • + *
  • precision = 4,返回天、小时、分钟和秒
  • + *
  • precision >= 5,返回天、小时、分钟、秒和毫秒
  • + *
+ * @return 合适型与当前时间的差 + */ + public static String getFitTimeSpanByNow(final Date date, final int precision) { + return getFitTimeSpan(getNowDate(), date, precision); + } + + /** + * 获取合适型与当前时间的差 + * + * @param millis 毫秒时间戳 + * @param precision 精度 + *
    + *
  • precision = 0,返回null
  • + *
  • precision = 1,返回天
  • + *
  • precision = 2,返回天和小时
  • + *
  • precision = 3,返回天、小时和分钟
  • + *
  • precision = 4,返回天、小时、分钟和秒
  • + *
  • precision >= 5,返回天、小时、分钟、秒和毫秒
  • + *
+ * @return 合适型与当前时间的差 + */ + public static String getFitTimeSpanByNow(final long millis, final int precision) { + return getFitTimeSpan(System.currentTimeMillis(), millis, precision); + } + + /** + * 获取友好型与当前时间的差 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 友好型与当前时间的差 + *
    + *
  • 如果小于1秒钟内,显示刚刚
  • + *
  • 如果在1分钟内,显示XXX秒前
  • + *
  • 如果在1小时内,显示XXX分钟前
  • + *
  • 如果在1小时外的今天内,显示今天15:32
  • + *
  • 如果是昨天的,显示昨天15:32
  • + *
  • 其余显示,2016-10-15
  • + *
  • 时间不合法的情况全部日期和时间信息,如星期六 十月 27 14:21:20 CST 2007
  • + *
+ */ + public static String getFriendlyTimeSpanByNow(final String time) { + return getFriendlyTimeSpanByNow(time, DEFAULT_FORMAT); + } + + /** + * 获取友好型与当前时间的差 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 友好型与当前时间的差 + *
    + *
  • 如果小于1秒钟内,显示刚刚
  • + *
  • 如果在1分钟内,显示XXX秒前
  • + *
  • 如果在1小时内,显示XXX分钟前
  • + *
  • 如果在1小时外的今天内,显示今天15:32
  • + *
  • 如果是昨天的,显示昨天15:32
  • + *
  • 其余显示,2016-10-15
  • + *
  • 时间不合法的情况全部日期和时间信息,如星期六 十月 27 14:21:20 CST 2007
  • + *
+ */ + public static String getFriendlyTimeSpanByNow(final String time, final DateFormat format) { + return getFriendlyTimeSpanByNow(string2Millis(time, format)); + } + + /** + * 获取友好型与当前时间的差 + * + * @param date Date类型时间 + * @return 友好型与当前时间的差 + *
    + *
  • 如果小于1秒钟内,显示刚刚
  • + *
  • 如果在1分钟内,显示XXX秒前
  • + *
  • 如果在1小时内,显示XXX分钟前
  • + *
  • 如果在1小时外的今天内,显示今天15:32
  • + *
  • 如果是昨天的,显示昨天15:32
  • + *
  • 其余显示,2016-10-15
  • + *
  • 时间不合法的情况全部日期和时间信息,如星期六 十月 27 14:21:20 CST 2007
  • + *
+ */ + public static String getFriendlyTimeSpanByNow(final Date date) { + return getFriendlyTimeSpanByNow(date.getTime()); + } + + /** + * 获取友好型与当前时间的差 + * + * @param millis 毫秒时间戳 + * @return 友好型与当前时间的差 + *
    + *
  • 如果小于1秒钟内,显示刚刚
  • + *
  • 如果在1分钟内,显示XXX秒前
  • + *
  • 如果在1小时内,显示XXX分钟前
  • + *
  • 如果在1小时外的今天内,显示今天15:32
  • + *
  • 如果是昨天的,显示昨天15:32
  • + *
  • 其余显示,2016-10-15
  • + *
  • 时间不合法的情况全部日期和时间信息,如星期六 十月 27 14:21:20 CST 2007
  • + *
+ */ + public static String getFriendlyTimeSpanByNow(final long millis) { + long now = System.currentTimeMillis(); + long span = now - millis; + if (span < 0) + return String.format("%tc", millis);// U can read http://www.apihome.cn/api/java/Formatter.html to understand it. + if (span < 1000) { + return "刚刚"; + } else if (span < TimeConstants.MIN) { + return String.format(Locale.getDefault(), "%d秒前", span / TimeConstants.SEC); + } else if (span < TimeConstants.HOUR) { + return String.format(Locale.getDefault(), "%d分钟前", span / TimeConstants.MIN); + } + // 获取当天00:00 + long wee = getWeeOfToday(); + if (millis >= wee) { + return String.format("今天%tR", millis); + } else if (millis >= wee - TimeConstants.DAY) { + return String.format("昨天%tR", millis); + } else { + return String.format("%tF", millis); + } + } + + private static long getWeeOfToday() { + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.HOUR_OF_DAY, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.MILLISECOND, 0); + return cal.getTimeInMillis(); + } + + /** + * 获取与给定时间等于时间差的时间戳 + * + * @param millis 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间戳 + */ + public static long getMillis(final long millis, final long timeSpan, @TimeConstants.Unit final int unit) { + return millis + timeSpan2Millis(timeSpan, unit); + } + + /** + * 获取与给定时间等于时间差的时间戳 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间戳 + */ + public static long getMillis(final String time, final long timeSpan, @TimeConstants.Unit final int unit) { + return getMillis(time, DEFAULT_FORMAT, timeSpan, unit); + } + + /** + * 获取与给定时间等于时间差的时间戳 + *

time格式为format

+ * + * @param time 给定时间 + * @param format 时间格式 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间戳 + */ + public static long getMillis(final String time, final DateFormat format, final long timeSpan, @TimeConstants.Unit final int unit) { + return string2Millis(time, format) + timeSpan2Millis(timeSpan, unit); + } + + /** + * 获取与给定时间等于时间差的时间戳 + * + * @param date 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间戳 + */ + public static long getMillis(final Date date, final long timeSpan, @TimeConstants.Unit final int unit) { + return date2Millis(date) + timeSpan2Millis(timeSpan, unit); + } + + /** + * 获取与给定时间等于时间差的时间字符串 + *

格式为yyyy-MM-dd HH:mm:ss

+ * + * @param millis 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间字符串 + */ + public static String getString(final long millis, final long timeSpan, @TimeConstants.Unit final int unit) { + return getString(millis, DEFAULT_FORMAT, timeSpan, unit); + } + + /** + * 获取与给定时间等于时间差的时间字符串 + *

格式为format

+ * + * @param millis 给定时间 + * @param format 时间格式 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间字符串 + */ + public static String getString(final long millis, final DateFormat format, final long timeSpan, @TimeConstants.Unit final int unit) { + return millis2String(millis + timeSpan2Millis(timeSpan, unit), format); + } + + /** + * 获取与给定时间等于时间差的时间字符串 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间字符串 + */ + public static String getString(final String time, final long timeSpan, @TimeConstants.Unit final int unit) { + return getString(time, DEFAULT_FORMAT, timeSpan, unit); + } + + /** + * 获取与给定时间等于时间差的时间字符串 + *

格式为format

+ * + * @param time 给定时间 + * @param format 时间格式 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间字符串 + */ + public static String getString(final String time, final DateFormat format, final long timeSpan, @TimeConstants.Unit final int unit) { + return millis2String(string2Millis(time, format) + timeSpan2Millis(timeSpan, unit), format); + } + + /** + * 获取与给定时间等于时间差的时间字符串 + *

格式为yyyy-MM-dd HH:mm:ss

+ * + * @param date 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间字符串 + */ + public static String getString(final Date date, final long timeSpan, @TimeConstants.Unit final int unit) { + return getString(date, DEFAULT_FORMAT, timeSpan, unit); + } + + /** + * 获取与给定时间等于时间差的时间字符串 + *

格式为format

+ * + * @param date 给定时间 + * @param format 时间格式 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的时间字符串 + */ + public static String getString(final Date date, final DateFormat format, final long timeSpan, @TimeConstants.Unit final int unit) { + return millis2String(date2Millis(date) + timeSpan2Millis(timeSpan, unit), format); + } + + /** + * 获取与给定时间等于时间差的Date + * + * @param millis 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的Date + */ + public static Date getDate(final long millis, final long timeSpan, @TimeConstants.Unit final int unit) { + return millis2Date(millis + timeSpan2Millis(timeSpan, unit)); + } + + /** + * 获取与给定时间等于时间差的Date + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的Date + */ + public static Date getDate(final String time, final long timeSpan, @TimeConstants.Unit final int unit) { + return getDate(time, DEFAULT_FORMAT, timeSpan, unit); + } + + /** + * 获取与给定时间等于时间差的Date + *

格式为format

+ * + * @param time 给定时间 + * @param format 时间格式 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的Date + */ + public static Date getDate(final String time, final DateFormat format, final long timeSpan, @TimeConstants.Unit final int unit) { + return millis2Date(string2Millis(time, format) + timeSpan2Millis(timeSpan, unit)); + } + + /** + * 获取与给定时间等于时间差的Date + * + * @param date 给定时间 + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与给定时间等于时间差的Date + */ + public static Date getDate(final Date date, final long timeSpan, @TimeConstants.Unit final int unit) { + return millis2Date(date2Millis(date) + timeSpan2Millis(timeSpan, unit)); + } + + /** + * 获取与当前时间等于时间差的时间戳 + * + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与当前时间等于时间差的时间戳 + */ + public static long getMillisByNow(final long timeSpan, @TimeConstants.Unit final int unit) { + return getMillis(getNowMills(), timeSpan, unit); + } + + /** + * 获取与当前时间等于时间差的时间字符串 + *

格式为yyyy-MM-dd HH:mm:ss

+ * + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与当前时间等于时间差的时间字符串 + */ + public static String getStringByNow(final long timeSpan, @TimeConstants.Unit final int unit) { + return getStringByNow(timeSpan, DEFAULT_FORMAT, unit); + } + + /** + * 获取与当前时间等于时间差的时间字符串 + *

格式为format

+ * + * @param timeSpan 时间差的毫秒时间戳 + * @param format 时间格式 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与当前时间等于时间差的时间字符串 + */ + public static String getStringByNow(final long timeSpan, final DateFormat format, @TimeConstants.Unit final int unit) { + return getString(getNowMills(), format, timeSpan, unit); + } + + /** + * 获取与当前时间等于时间差的Date + * + * @param timeSpan 时间差的毫秒时间戳 + * @param unit 单位类型 + *
    + *
  • {@link TimeConstants#MSEC}: 毫秒
  • + *
  • {@link TimeConstants#SEC }: 秒
  • + *
  • {@link TimeConstants#MIN }: 分
  • + *
  • {@link TimeConstants#HOUR}: 小时
  • + *
  • {@link TimeConstants#DAY }: 天
  • + *
+ * @return 与当前时间等于时间差的Date + */ + public static Date getDateByNow(final long timeSpan, @TimeConstants.Unit final int unit) { + return getDate(getNowMills(), timeSpan, unit); + } + + /** + * 判断是否今天 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return {@code true}: 是
{@code false}: 否 + */ + public static boolean isToday(final String time) { + return isToday(string2Millis(time, DEFAULT_FORMAT)); + } + + /** + * 判断是否今天 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return {@code true}: 是
{@code false}: 否 + */ + public static boolean isToday(final String time, final DateFormat format) { + return isToday(string2Millis(time, format)); + } + + /** + * 判断是否今天 + * + * @param date Date类型时间 + * @return {@code true}: 是
{@code false}: 否 + */ + public static boolean isToday(final Date date) { + return isToday(date.getTime()); + } + + /** + * 判断是否今天 + * + * @param millis 毫秒时间戳 + * @return {@code true}: 是
{@code false}: 否 + */ + public static boolean isToday(final long millis) { + long wee = getWeeOfToday(); + return millis >= wee && millis < wee + TimeConstants.DAY; + } + + /** + * 判断是否闰年 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return {@code true}: 闰年
{@code false}: 平年 + */ + public static boolean isLeapYear(final String time) { + return isLeapYear(string2Date(time, DEFAULT_FORMAT)); + } + + /** + * 判断是否闰年 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return {@code true}: 闰年
{@code false}: 平年 + */ + public static boolean isLeapYear(final String time, final DateFormat format) { + return isLeapYear(string2Date(time, format)); + } + + /** + * 判断是否闰年 + * + * @param date Date类型时间 + * @return {@code true}: 闰年
{@code false}: 平年 + */ + public static boolean isLeapYear(final Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + int year = cal.get(Calendar.YEAR); + return isLeapYear(year); + } + + /** + * 判断是否闰年 + * + * @param millis 毫秒时间戳 + * @return {@code true}: 闰年
{@code false}: 平年 + */ + public static boolean isLeapYear(final long millis) { + return isLeapYear(millis2Date(millis)); + } + + /** + * 判断是否闰年 + * + * @param year 年份 + * @return {@code true}: 闰年
{@code false}: 平年 + */ + public static boolean isLeapYear(final int year) { + return year % 4 == 0 && year % 100 != 0 || year % 400 == 0; + } + + /** + * 获取中式星期 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 中式星期 + */ + public static String getChineseWeek(final String time) { + return getChineseWeek(string2Date(time, DEFAULT_FORMAT)); + } + + /** + * 获取当前中式时间 + * + * @return + */ + public static String getChineseNowWeek() { + return getChineseWeek(string2Date(getNowString(""), DEFAULT_FORMAT)); + } + + /** + * 获取中式星期 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 中式星期 + */ + public static String getChineseWeek(final String time, final DateFormat format) { + return getChineseWeek(string2Date(time, format)); + } + + /** + * 获取中式星期 + * + * @param date Date类型时间 + * @return 中式星期 + */ + public static String getChineseWeek(final Date date) { + return new SimpleDateFormat("E", Locale.CHINA).format(date); + } + + /** + * 获取中式星期 + * + * @param millis 毫秒时间戳 + * @return 中式星期 + */ + public static String getChineseWeek(final long millis) { + return getChineseWeek(new Date(millis)); + } + + /** + * 获取美式星期 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 美式星期 + */ + public static String getUSWeek(final String time) { + return getUSWeek(string2Date(time, DEFAULT_FORMAT)); + } + + /** + * 获取美式星期 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 美式星期 + */ + public static String getUSWeek(final String time, final DateFormat format) { + return getUSWeek(string2Date(time, format)); + } + + /** + * 获取美式星期 + * + * @param date Date类型时间 + * @return 美式星期 + */ + public static String getUSWeek(final Date date) { + return new SimpleDateFormat("EEEE", Locale.US).format(date); + } + + /** + * 获取美式星期 + * + * @param millis 毫秒时间戳 + * @return 美式星期 + */ + public static String getUSWeek(final long millis) { + return getUSWeek(new Date(millis)); + } + + /** + * 获取星期索引 + *

注意:周日的Index才是1,周六为7

+ *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 1...7 + * @see Calendar#SUNDAY + * @see Calendar#MONDAY + * @see Calendar#TUESDAY + * @see Calendar#WEDNESDAY + * @see Calendar#THURSDAY + * @see Calendar#FRIDAY + * @see Calendar#SATURDAY + */ + public static int getWeekIndex(final String time) { + return getWeekIndex(string2Date(time, DEFAULT_FORMAT)); + } + + /** + * 获取星期索引 + *

注意:周日的Index才是1,周六为7

+ *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 1...7 + * @see Calendar#SUNDAY + * @see Calendar#MONDAY + * @see Calendar#TUESDAY + * @see Calendar#WEDNESDAY + * @see Calendar#THURSDAY + * @see Calendar#FRIDAY + * @see Calendar#SATURDAY + */ + public static int getWeekIndex(final String time, final DateFormat format) { + return getWeekIndex(string2Date(time, format)); + } + + /** + * 获取星期索引 + *

注意:周日的Index才是1,周六为7

+ * + * @param date Date类型时间 + * @return 1...7 + * @see Calendar#SUNDAY + * @see Calendar#MONDAY + * @see Calendar#TUESDAY + * @see Calendar#WEDNESDAY + * @see Calendar#THURSDAY + * @see Calendar#FRIDAY + * @see Calendar#SATURDAY + */ + public static int getWeekIndex(final Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + return cal.get(Calendar.DAY_OF_WEEK); + } + + /** + * 获取星期索引 + *

注意:周日的Index才是1,周六为7

+ * + * @param millis 毫秒时间戳 + * @return 1...7 + * @see Calendar#SUNDAY + * @see Calendar#MONDAY + * @see Calendar#TUESDAY + * @see Calendar#WEDNESDAY + * @see Calendar#THURSDAY + * @see Calendar#FRIDAY + * @see Calendar#SATURDAY + */ + public static int getWeekIndex(final long millis) { + return getWeekIndex(millis2Date(millis)); + } + + /** + * 获取月份中的第几周 + *

注意:国外周日才是新的一周的开始

+ *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 1...5 + */ + public static int getWeekOfMonth(final String time) { + return getWeekOfMonth(string2Date(time, DEFAULT_FORMAT)); + } + + /** + * 获取月份中的第几周 + *

注意:国外周日才是新的一周的开始

+ *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 1...5 + */ + public static int getWeekOfMonth(final String time, final DateFormat format) { + return getWeekOfMonth(string2Date(time, format)); + } + + /** + * 获取月份中的第几周 + *

注意:国外周日才是新的一周的开始

+ * + * @param date Date类型时间 + * @return 1...5 + */ + public static int getWeekOfMonth(final Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + return cal.get(Calendar.WEEK_OF_MONTH); + } + + /** + * 获取月份中的第几周 + *

注意:国外周日才是新的一周的开始

+ * + * @param millis 毫秒时间戳 + * @return 1...5 + */ + public static int getWeekOfMonth(final long millis) { + return getWeekOfMonth(millis2Date(millis)); + } + + /** + * 获取年份中的第几周 + *

注意:国外周日才是新的一周的开始

+ *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 1...54 + */ + public static int getWeekOfYear(final String time) { + return getWeekOfYear(string2Date(time, DEFAULT_FORMAT)); + } + + /** + * 获取年份中的第几周 + *

注意:国外周日才是新的一周的开始

+ *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 1...54 + */ + public static int getWeekOfYear(final String time, final DateFormat format) { + return getWeekOfYear(string2Date(time, format)); + } + + /** + * 获取年份中的第几周 + *

注意:国外周日才是新的一周的开始

+ * + * @param date Date类型时间 + * @return 1...54 + */ + public static int getWeekOfYear(final Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + return cal.get(Calendar.WEEK_OF_YEAR); + } + + /** + * 获取年份中的第几周 + *

注意:国外周日才是新的一周的开始

+ * + * @param millis 毫秒时间戳 + * @return 1...54 + */ + public static int getWeekOfYear(final long millis) { + return getWeekOfYear(millis2Date(millis)); + } + + private static final String[] CHINESE_ZODIAC = {"猴", "鸡", "狗", "猪", "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊"}; + + /** + * 获取生肖 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 生肖 + */ + public static String getChineseZodiac(final String time) { + return getChineseZodiac(string2Date(time, DEFAULT_FORMAT)); + } + + /** + * 获取生肖 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 生肖 + */ + public static String getChineseZodiac(final String time, final DateFormat format) { + return getChineseZodiac(string2Date(time, format)); + } + + /** + * 获取生肖 + * + * @param date Date类型时间 + * @return 生肖 + */ + public static String getChineseZodiac(final Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + return CHINESE_ZODIAC[cal.get(Calendar.YEAR) % 12]; + } + + /** + * 获取生肖 + * + * @param millis 毫秒时间戳 + * @return 生肖 + */ + public static String getChineseZodiac(final long millis) { + return getChineseZodiac(millis2Date(millis)); + } + + /** + * 获取生肖 + * + * @param year 年 + * @return 生肖 + */ + public static String getChineseZodiac(final int year) { + return CHINESE_ZODIAC[year % 12]; + } + + private static final String[] ZODIAC = {"水瓶座", "双鱼座", "白羊座", "金牛座", "双子座", "巨蟹座", "狮子座", "处女座", "天秤座", "天蝎座", "射手座", "魔羯座"}; + private static final int[] ZODIAC_FLAGS = {20, 19, 21, 21, 21, 22, 23, 23, 23, 24, 23, 22}; + + /** + * 获取星座 + *

time格式为yyyy-MM-dd HH:mm:ss

+ * + * @param time 时间字符串 + * @return 生肖 + */ + public static String getZodiac(final String time) { + return getZodiac(string2Date(time, DEFAULT_FORMAT)); + } + + /** + * 获取星座 + *

time格式为format

+ * + * @param time 时间字符串 + * @param format 时间格式 + * @return 生肖 + */ + public static String getZodiac(final String time, final DateFormat format) { + return getZodiac(string2Date(time, format)); + } + + /** + * 获取星座 + * + * @param date Date类型时间 + * @return 星座 + */ + public static String getZodiac(final Date date) { + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + int month = cal.get(Calendar.MONTH) + 1; + int day = cal.get(Calendar.DAY_OF_MONTH); + return getZodiac(month, day); + } + + /** + * 获取星座 + * + * @param millis 毫秒时间戳 + * @return 星座 + */ + public static String getZodiac(final long millis) { + return getZodiac(millis2Date(millis)); + } + + /** + * 获取星座 + * + * @param month 月 + * @param day 日 + * @return 星座 + */ + public static String getZodiac(final int month, final int day) { + return ZODIAC[day >= ZODIAC_FLAGS[month - 1] + ? month - 1 + : (month + 10) % 12]; + } + + private static long timeSpan2Millis(final long timeSpan, @TimeConstants.Unit final int unit) { + return timeSpan * unit; + } + + private static long millis2TimeSpan(final long millis, @TimeConstants.Unit final int unit) { + return millis / unit; + } + + public static String millis2FitTimeSpan(long millis, int precision) { + if (millis < 0 || precision <= 0) return null; + precision = Math.min(precision, 5); + String[] units = {"天", "时", "分", "秒", "毫秒"}; + if (millis == 0) return 0 + units[precision - 1]; + StringBuilder sb = new StringBuilder(); + int[] unitLen = {86400000, 3600000, 60000, 1000, 1}; + for (int i = 0; i < precision; i++) { + if (millis >= unitLen[i]) { + long mode = millis / unitLen[i]; + millis -= mode * unitLen[i]; + sb.append(mode).append(units[i]); + } + } + return sb.toString(); + } + + + /** + * 比较时间大小 + * + * @param nowDate + * @param compareDate + * @return + */ + public static boolean compareDate(String nowDate, String compareDate) { + DateFormat df = DEFAULT_FORMAT; + try { + Date now = df.parse(nowDate); + Date compare = df.parse(compareDate); + if (now.after(compare)) { + return true; + } else { + return false; + } + } catch (ParseException e) { + e.printStackTrace(); + return false; + } + } + + /** + * 比较时间大小 + * + * @param nowDate + * @param compareDate + * @return + */ + public static boolean compareDate(String nowDate, String compareDate,DateFormat format) { + DateFormat df = format; + try { + Date now = df.parse(nowDate); + Date compare = df.parse(compareDate); + if (now.after(compare)) { + return true; + } else { + return false; + } + } catch (ParseException e) { + e.printStackTrace(); + return false; + } + } +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimingX.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimingX.java new file mode 100644 index 0000000..df631dc --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimingX.java @@ -0,0 +1,145 @@ +package com.dahe.mylibrary.utils; + +import android.os.Handler; +import android.os.Message; +import android.widget.TextView; + +import java.util.ArrayList; + +import io.reactivex.rxjava3.annotations.NonNull; + +public class TimingX { + + private volatile static TimingX sTimingX; + + private static int sSecond = 0, sStatus = TimingEnum.STOP.val; + + private static final Handler sHandler = new TimingXHandler(); + + private static final ArrayList timingViews = new ArrayList<>(8); + + private static String time = ""; + + private TimingX() { + } + + public static TimingX builder(){ + if(sTimingX == null){ + synchronized (TimingX.class){ + if(sTimingX == null){ + sTimingX = new TimingX(); + } + } + } + return sTimingX; + } + + private static class TimingXHandler extends Handler { + @Override + public void handleMessage(@NonNull Message msg) { + int status = msg.what; + if (status == TimingEnum.START.val) { + sSecond += 1; + time = format(sSecond); + sHandler.sendEmptyMessageDelayed(status, 1000); + } else if (status == TimingEnum.STOP.val) { + time = format(sSecond); + } + showTime(); + } + } + + private static void showTime(){ + for (TextView timingView : timingViews) { + timingView.setText(time); + } + } + + public int getStatus(){ + return sStatus; + } + + enum TimingEnum { + STOP(0), // 停止计时 + START(1), // 开始计时 + CLEAR(-1); // 清除计时 + int val; + TimingEnum(int val){ + this.val = val; + } + } + + /** + * 添加需要计时的 view + * @param view + * @return + */ + public TimingX add(TextView view){ + if(!timingViews.contains(view)){ + timingViews.add(view); + } + return sTimingX; + } + + /** + * 移除不需要计时的 view + * @param view + * @return + */ + public TimingX remove(TextView view){ + timingViews.remove(view); + return sTimingX; + } + + /** + * 开始计时 + */ + public void start(){ + if(sStatus == TimingEnum.STOP.val){ + sStatus = TimingEnum.START.val; + sHandler.sendEmptyMessageDelayed(sStatus, 1000); + } + } + + /** + * 停止计时 + */ + public void stop(){ + if(sStatus == TimingEnum.START.val){ + sStatus = TimingEnum.STOP.val; + sHandler.removeMessages(TimingEnum.START.val); + sHandler.sendEmptyMessage(sStatus); + } + } + + /** + * 销毁 handler + */ + public void destroy(){ + sStatus = TimingEnum.STOP.val; + sSecond = 0; + sHandler.removeMessages(TimingEnum.START.val); + timingViews.clear(); + } + + /** + * 将秒转化为分秒的形式(00:00) + * @param second + * @return + */ + public static String format(int second) { + StringBuilder sb = new StringBuilder(); + int minutes = second / 60; + int sec = second % 60; + if(minutes < 10){ + sb.append(0); + } + sb.append(minutes); + sb.append(":"); + if(sec < 10){ + sb.append(0); + } + sb.append(sec); + return sb.toString(); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/ToastUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ToastUtils.java new file mode 100644 index 0000000..5b03d72 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ToastUtils.java @@ -0,0 +1,37 @@ +package com.dahe.mylibrary.utils; + +import android.content.Context; +import android.text.TextUtils; +import android.widget.Toast; + +/** + * Created by Administrator on 2017/11/28 0028. + */ + +public class ToastUtils { + public static Toast mToast = null; + + public static void showToast(Context mContext, String message) { + if (!TextUtils.isEmpty(message)) { + +// if ( mToast != null) { +// mToast.cancel(); +// } +// mToast = Toast.makeText(mContext, message, Toast.LENGTH_SHORT); +// mToast.show(); + + if (mToast == null) { + mToast = Toast.makeText(mContext, message, Toast.LENGTH_SHORT); + } else { + mToast.setText(message); + } + mToast.show(); + } + } + + public static void cancelToast(){ + if (mToast!=null) + mToast.cancel(); + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/wapper/SelectSimAdapter.java b/mylibrary/src/main/java/com/dahe/mylibrary/wapper/SelectSimAdapter.java new file mode 100644 index 0000000..6302e3e --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/wapper/SelectSimAdapter.java @@ -0,0 +1,37 @@ +package com.dahe.mylibrary.wapper; + +import android.widget.TextView; + +import androidx.annotation.Nullable; + +import com.chad.library.adapter.base.BaseQuickAdapter; +import com.chad.library.adapter.base.viewholder.BaseViewHolder; +import com.dahe.mylibrary.R; + +import java.util.List; + +public class SelectSimAdapter extends BaseQuickAdapter { + private String selectString = ""; + + + public SelectSimAdapter(int layoutResId, @Nullable List data, String selectString) { + super(R.layout.item_select, data); + this.selectString = selectString; + } + + @Override + protected void convert(BaseViewHolder helper, String item) { + helper.setText(R.id.tv_content,item); + TextView tv = helper.getView(R.id.tv_content); + if (item.equals(selectString)){ + tv.setSelected(true); + }else{ + tv.setSelected(false); + } + + } + + public void setSelect(String selectString){ + this.selectString = selectString; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/AttachButton.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/AttachButton.java new file mode 100644 index 0000000..6051134 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/AttachButton.java @@ -0,0 +1,157 @@ +package com.dahe.mylibrary.weight; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.BounceInterpolator; + +import androidx.annotation.Nullable; + +import com.dahe.mylibrary.R; +/** + * 自定义View实现拖动并自动吸边效果 + *

+ * 处理滑动和贴边 {@link #onTouchEvent(MotionEvent)} + * 处理事件分发 {@link #dispatchTouchEvent(MotionEvent)} + *

+ * + * @attr customIsAttach //是否需要自动吸边 + * @attr customIsDrag //是否可拖曳 + */ +public class AttachButton extends View { + private float mLastRawX; + private float mLastRawY; + private final String TAG = "AttachButton"; + private boolean isDrug = false; + private int mRootMeasuredWidth = 0; + private int mRootMeasuredHeight = 0; + private int mRootTopY = 0; + private boolean customIsAttach; + private boolean customIsDrag; + + public AttachButton(Context context) { + this(context, null); + } + + public AttachButton(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public AttachButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initAttrs(context, attrs); + } + + /** + * 初始化自定义属性 + */ + private void initAttrs(Context context, AttributeSet attrs) { + TypedArray mTypedAttay = context.obtainStyledAttributes(attrs, R.styleable.AttachButton); + customIsAttach = mTypedAttay.getBoolean(R.styleable.AttachButton_customIsAttach, true); + customIsDrag = mTypedAttay.getBoolean(R.styleable.AttachButton_customIsDrag, true); + mTypedAttay.recycle(); + } + + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + super.dispatchTouchEvent(event); + return true; + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + //判断是否需要滑动 + if (customIsDrag) { + //当前手指的坐标 + float mRawX = ev.getRawX(); + float mRawY = ev.getRawY(); + switch (ev.getAction()) { + case MotionEvent.ACTION_DOWN://手指按下 + isDrug = false; + //记录按下的位置 + mLastRawX = mRawX; + mLastRawY = mRawY; + ViewGroup mViewGroup = (ViewGroup) getParent(); + if (mViewGroup != null) { + int[] location = new int[2]; + mViewGroup.getLocationInWindow(location); + //获取父布局的高度 + mRootMeasuredHeight = mViewGroup.getMeasuredHeight(); + mRootMeasuredWidth = mViewGroup.getMeasuredWidth(); + //获取父布局顶点的坐标 + mRootTopY = location[1]; + } + break; + case MotionEvent.ACTION_MOVE://手指滑动 + if (mRawX >= 0 && mRawX <= mRootMeasuredWidth && mRawY >= mRootTopY && mRawY <= (mRootMeasuredHeight + mRootTopY)) { + //手指X轴滑动距离 + float differenceValueX = mRawX - mLastRawX; + //手指Y轴滑动距离 + float differenceValueY = mRawY - mLastRawY; + //判断是否为拖动操作 + if (!isDrug) { + if (Math.sqrt(differenceValueX * differenceValueX + differenceValueY * differenceValueY) < 2) { + isDrug = false; + } else { + isDrug = true; + } + } + //获取手指按下的距离与控件本身X轴的距离 + float ownX = getX(); + //获取手指按下的距离与控件本身Y轴的距离 + float ownY = getY(); + //理论中X轴拖动的距离 + float endX = ownX + differenceValueX; + //理论中Y轴拖动的距离 + float endY = ownY + differenceValueY; + //X轴可以拖动的最大距离 + float maxX = mRootMeasuredWidth - getWidth(); + //Y轴可以拖动的最大距离 + float maxY = mRootMeasuredHeight - getHeight(); + //X轴边界限制 + endX = endX < 0 ? 0 : endX > maxX ? maxX : endX; + //Y轴边界限制 + endY = endY < 0 ? 0 : endY > maxY ? maxY : endY; + //开始移动 + setX(endX); + setY(endY); + //记录位置 + mLastRawX = mRawX; + mLastRawY = mRawY; + } + + break; + case MotionEvent.ACTION_UP://手指离开 + //根据自定义属性判断是否需要贴边 + if (customIsAttach) { + //判断是否为点击事件 + if (isDrug) { + float center = mRootMeasuredWidth / 2; + //自动贴边 + if (mLastRawX <= center) { + //向左贴边 + AttachButton.this.animate() + .setInterpolator(new BounceInterpolator()) + .setDuration(500) + .x(0) + .start(); + } else { + //向右贴边 + AttachButton.this.animate() + .setInterpolator(new BounceInterpolator()) + .setDuration(500) + .x(mRootMeasuredWidth - getWidth()) + .start(); + } + } + } + break; + } + } + //是否拦截事件 + return isDrug ? isDrug : super.onTouchEvent(ev); + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/FullyGridLayoutManager.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/FullyGridLayoutManager.java new file mode 100644 index 0000000..ed6da0e --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/FullyGridLayoutManager.java @@ -0,0 +1,104 @@ +package com.dahe.mylibrary.weight; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; + +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +/** + * author:luck + * project:PictureSelector + * package:com.luck.picture.ui + * email:893855882@qq.com + * data:16/12/31 + */ + +public class FullyGridLayoutManager extends GridLayoutManager { + public FullyGridLayoutManager(Context context, int spanCount) { + super(context, spanCount); + } + + public FullyGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) { + super(context, spanCount, orientation, reverseLayout); + } + + private int[] mMeasuredDimension = new int[2]; + + @Override + public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) { + final int widthMode = View.MeasureSpec.getMode(widthSpec); + final int heightMode = View.MeasureSpec.getMode(heightSpec); + final int widthSize = View.MeasureSpec.getSize(widthSpec); + final int heightSize = View.MeasureSpec.getSize(heightSpec); + + int width = 0; + int height = 0; + int count = getItemCount(); + int span = getSpanCount(); + for (int i = 0; i < count; i++) { + measureScrapChild(recycler, i, + View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), + View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED), + mMeasuredDimension); + + if (getOrientation() == HORIZONTAL) { + if (i % span == 0) { + width = width + mMeasuredDimension[0]; + } + if (i == 0) { + height = mMeasuredDimension[1]; + } + } else { + if (i % span == 0) { + height = height + mMeasuredDimension[1]; + } + if (i == 0) { + width = mMeasuredDimension[0]; + } + } + } + + switch (widthMode) { + case View.MeasureSpec.EXACTLY: + width = widthSize; + case View.MeasureSpec.AT_MOST: + case View.MeasureSpec.UNSPECIFIED: + } + + switch (heightMode) { + case View.MeasureSpec.EXACTLY: + height = heightSize; + case View.MeasureSpec.AT_MOST: + case View.MeasureSpec.UNSPECIFIED: + } + + setMeasuredDimension(width, height); + } + + final RecyclerView.State mState = new RecyclerView.State(); + + private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec, + int heightSpec, int[] measuredDimension) { + int itemCount = mState.getItemCount(); + if (position < itemCount) { + try { + View view = recycler.getViewForPosition(0); + if (view != null) { + RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams(); + int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, + getPaddingLeft() + getPaddingRight(), p.width); + int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, + getPaddingTop() + getPaddingBottom(), p.height); + view.measure(childWidthSpec, childHeightSpec); + measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin; + measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin; + recycler.recycleView(view); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/GlideCircleWithBorder.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/GlideCircleWithBorder.java new file mode 100644 index 0000000..24f7cf3 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/GlideCircleWithBorder.java @@ -0,0 +1,67 @@ +package com.dahe.mylibrary.weight; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapShader; +import android.graphics.Canvas; +import android.graphics.Paint; + +import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool; +import com.bumptech.glide.load.resource.bitmap.BitmapTransformation; + +import java.security.MessageDigest; + +/** + * 加载圆形头像带白色边框 + */ +public class GlideCircleWithBorder extends BitmapTransformation { + private Paint mBorderPaint; + private float mBorderWidth; + + public GlideCircleWithBorder(Context context, int borderWidth, int borderColor) { + mBorderWidth = Resources.getSystem().getDisplayMetrics().density * borderWidth; + mBorderPaint = new Paint(); + mBorderPaint.setDither(true); + mBorderPaint.setAntiAlias(true); + mBorderPaint.setColor(borderColor); + mBorderPaint.setStyle(Paint.Style.STROKE); + mBorderPaint.setStrokeWidth(mBorderWidth); + } + + protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) { + return circleCrop(pool, toTransform); + } + + private Bitmap circleCrop(BitmapPool pool, Bitmap source) { + if (source == null) { + return null; + } + int size = (int) (Math.min(source.getWidth(), source.getHeight()) - (mBorderWidth / 2)); + int x = (source.getWidth() - size) / 2; + int y = (source.getHeight() - size) / 2; + Bitmap squared = Bitmap.createBitmap(source, x, y, size, size); + Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888); + if (result == null) { + result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); + } + //创建画笔 画布 手动描绘边框 + Canvas canvas = new Canvas(result); + Paint paint = new Paint(); + paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP)); + paint.setAntiAlias(true); + float r = size / 2f; + canvas.drawCircle(r, r, r, paint); + if (mBorderPaint != null) { + float borderRadius = r - mBorderWidth / 2; + canvas.drawCircle(r, r, borderRadius, mBorderPaint); + } + return result; + } + + @Override + public void updateDiskCacheKey(MessageDigest messageDigest) { + + } + +} \ No newline at end of file diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/GlideEngine.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/GlideEngine.java new file mode 100644 index 0000000..e531d35 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/GlideEngine.java @@ -0,0 +1,233 @@ +package com.dahe.mylibrary.weight; + + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.PointF; +import android.graphics.drawable.Drawable; +import android.view.View; +import android.widget.ImageView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.graphics.drawable.RoundedBitmapDrawable; +import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.RequestOptions; +import com.bumptech.glide.request.target.BitmapImageViewTarget; +import com.bumptech.glide.request.target.ImageViewTarget; +import com.dahe.mylibrary.R; +import com.luck.picture.lib.engine.ImageEngine; +import com.luck.picture.lib.listener.OnImageCompleteCallback; +import com.luck.picture.lib.tools.MediaUtils; +import com.luck.picture.lib.widget.longimage.ImageSource; +import com.luck.picture.lib.widget.longimage.ImageViewState; +import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView; + +/** + * @author:luck + * @date:2019-11-13 17:02 + * @describe:Glide加载引擎 + */ +public class GlideEngine implements ImageEngine { + + /** + * 加载图片 + * + * @param context + * @param url + * @param imageView + */ + @Override + public void loadImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView) { + Glide.with(context) + .load(url) + .into(imageView); + } + + + /** + * 加载网络图片适配长图方案 + * # 注意:此方法只有加载网络图片才会回调 + * + * @param context + * @param url + * @param imageView + * @param longImageView + * @param callback 网络图片加载回调监听 {link after version 2.5.1 Please use the #OnImageCompleteCallback#} + */ + @Override + public void loadImage(@NonNull Context context, @NonNull String url, + @NonNull final ImageView imageView, + final SubsamplingScaleImageView longImageView, final OnImageCompleteCallback callback) { + Glide.with(context) + .asBitmap() + .load(url) + .into(new ImageViewTarget(imageView) { + @Override + public void onLoadStarted(@Nullable Drawable placeholder) { + super.onLoadStarted(placeholder); + if (callback != null) { + callback.onShowLoading(); + } + } + + @Override + public void onLoadFailed(@Nullable Drawable errorDrawable) { + super.onLoadFailed(errorDrawable); + if (callback != null) { + callback.onHideLoading(); + } + } + + @Override + protected void setResource(@Nullable Bitmap resource) { + if (callback != null) { + callback.onHideLoading(); + } + if (resource != null) { + boolean eqLongImage = MediaUtils.isLongImg(resource.getWidth(), + resource.getHeight()); + longImageView.setVisibility(eqLongImage ? View.VISIBLE : View.GONE); + imageView.setVisibility(eqLongImage ? View.GONE : View.VISIBLE); + if (eqLongImage) { + // 加载长图 + longImageView.setQuickScaleEnabled(true); + longImageView.setZoomEnabled(true); + longImageView.setDoubleTapZoomDuration(100); + longImageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_CROP); + longImageView.setDoubleTapZoomDpi(SubsamplingScaleImageView.ZOOM_FOCUS_CENTER); + longImageView.setImage(ImageSource.bitmap(resource), + new ImageViewState(0, new PointF(0, 0), 0)); + } else { + // 普通图片 + imageView.setImageBitmap(resource); + } + } + } + }); + } + + /** + * 加载网络图片适配长图方案 + * # 注意:此方法只有加载网络图片才会回调 + * + * @param context + * @param url + * @param imageView + * @param longImageView + * @ 已废弃 + */ + @Override + public void loadImage(@NonNull Context context, @NonNull String url, + @NonNull final ImageView imageView, + final SubsamplingScaleImageView longImageView) { + Glide.with(context) + .asBitmap() + .load(url) + .into(new ImageViewTarget(imageView) { + @Override + protected void setResource(@Nullable Bitmap resource) { + if (resource != null) { + boolean eqLongImage = MediaUtils.isLongImg(resource.getWidth(), + resource.getHeight()); + longImageView.setVisibility(eqLongImage ? View.VISIBLE : View.GONE); + imageView.setVisibility(eqLongImage ? View.GONE : View.VISIBLE); + if (eqLongImage) { + // 加载长图 + longImageView.setQuickScaleEnabled(true); + longImageView.setZoomEnabled(true); + longImageView.setDoubleTapZoomDuration(100); + longImageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_CROP); + longImageView.setDoubleTapZoomDpi(SubsamplingScaleImageView.ZOOM_FOCUS_CENTER); + longImageView.setImage(ImageSource.bitmap(resource), + new ImageViewState(0, new PointF(0, 0), 0)); + } else { + // 普通图片 + imageView.setImageBitmap(resource); + } + } + } + }); + } + + /** + * 加载相册目录 + * + * @param context 上下文 + * @param url 图片路径 + * @param imageView 承载图片ImageView + */ + @Override + public void loadFolderImage(@NonNull final Context context, @NonNull String url, @NonNull final ImageView imageView) { + Glide.with(context) + .asBitmap() + .load(url) + .override(180, 180) + .centerCrop() + .sizeMultiplier(0.5f) + .apply(new RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(new BitmapImageViewTarget(imageView) { + @Override + protected void setResource(Bitmap resource) { + RoundedBitmapDrawable circularBitmapDrawable = + RoundedBitmapDrawableFactory. + create(context.getResources(), resource); + circularBitmapDrawable.setCornerRadius(8); + imageView.setImageDrawable(circularBitmapDrawable); + } + }); + } + + + /** + * 加载gif + * + * @param context 上下文 + * @param url 图片路径 + * @param imageView 承载图片ImageView + */ + @Override + public void loadAsGifImage(@NonNull Context context, @NonNull String url, + @NonNull ImageView imageView) { + Glide.with(context) + .asGif() + .load(url) + .into(imageView); + } + + /** + * 加载图片列表图片 + * + * @param context 上下文 + * @param url 图片路径 + * @param imageView 承载图片ImageView + */ + @Override + public void loadGridImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView) { + Glide.with(context) + .load(url) + .override(200, 200) + .centerCrop() + .apply(new RequestOptions().placeholder(R.drawable.picture_image_placeholder)) + .into(imageView); + } + + + private GlideEngine() { + } + + private static GlideEngine instance; + + public static GlideEngine createGlideEngine() { + if (null == instance) { + synchronized (GlideEngine.class) { + if (null == instance) { + instance = new GlideEngine(); + } + } + } + return instance; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/GridSectionAverageGapItemDecoration.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/GridSectionAverageGapItemDecoration.java new file mode 100644 index 0000000..6fa5c4b --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/GridSectionAverageGapItemDecoration.java @@ -0,0 +1,231 @@ +package com.dahe.mylibrary.weight; + +import android.graphics.Rect; +import android.os.Build; +import android.util.DisplayMetrics; +import android.util.TypedValue; +import android.view.View; + +import androidx.annotation.Nullable; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.chad.library.adapter.base.BaseSectionQuickAdapter; +import com.chad.library.adapter.base.entity.SectionEntity; +import com.chad.library.adapter.base.viewholder.BaseViewHolder; + +import java.util.ArrayList; +import java.util.List; + +/** + * 应用于RecyclerView的GridLayoutManager,水平方向上固定间距大小,从而使条目宽度自适应。
+ * 配合Brvah的Section使用,不对Head生效,仅对每个Head的子Grid列表生效
+ * Section Grid中Item的宽度应设为MATCH_PARAENT + * + * @author : renpeng + * @since : 2018/9/29 + */ +public class GridSectionAverageGapItemDecoration extends RecyclerView.ItemDecoration { + + private class Section { + public int startPos = 0; + public int endPos = 0; + + public int getCount() { + return endPos - startPos + 1; + } + + public boolean contains(int pos) { + return pos >= startPos && pos <= endPos; + } + + @Override + public String toString() { + return "Section{" + + "startPos=" + startPos + + ", endPos=" + endPos + + '}'; + } + } + + private float gapHorizontalDp; + private float gapVerticalDp; + private float sectionEdgeHPaddingDp; + private float sectionEdgeVPaddingDp; + private int gapHSizePx = -1; + private int gapVSizePx = -1; + private int sectionEdgeHPaddingPx; + private int eachItemHPaddingPx; //每个条目应该在水平方向上加的padding 总大小,即=paddingLeft+paddingRight + private int sectionEdgeVPaddingPx; + private List
mSectionList = new ArrayList<>(); + private BaseSectionQuickAdapter mAdapter; + private RecyclerView.AdapterDataObserver mDataObserver = new RecyclerView.AdapterDataObserver() { + @Override + public void onChanged() { + markSections(); + } + + @Override + public void onItemRangeChanged(int positionStart, int itemCount) { + markSections(); + } + + @Override + public void onItemRangeChanged(int positionStart, int itemCount, @Nullable Object payload) { + markSections(); + } + + @Override + public void onItemRangeInserted(int positionStart, int itemCount) { + markSections(); + } + + @Override + public void onItemRangeRemoved(int positionStart, int itemCount) { + markSections(); + } + + @Override + public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) { + markSections(); + } + }; + + + /** + * @param gapHorizontalDp item之间的水平间距 + * @param gapVerticalDp item之间的垂直间距 + * @param sectionEdgeHPaddingDp section左右两端的padding大小 + * @param sectionEdgeVPaddingDp section上下两端的padding大小 + */ + public GridSectionAverageGapItemDecoration(float gapHorizontalDp, float gapVerticalDp, float sectionEdgeHPaddingDp, float sectionEdgeVPaddingDp) { + this.gapHorizontalDp = gapHorizontalDp; + this.gapVerticalDp = gapVerticalDp; + this.sectionEdgeHPaddingDp = sectionEdgeHPaddingDp; + this.sectionEdgeVPaddingDp = sectionEdgeVPaddingDp; + } + + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + if (parent.getLayoutManager() instanceof GridLayoutManager && parent.getAdapter() instanceof BaseSectionQuickAdapter) { + GridLayoutManager layoutManager = (GridLayoutManager) parent.getLayoutManager(); + BaseSectionQuickAdapter adapter = (BaseSectionQuickAdapter) parent.getAdapter(); + if (mAdapter != adapter) { + setUpWithAdapter(adapter); + } + int spanCount = layoutManager.getSpanCount(); + int position = parent.getChildAdapterPosition(view) - mAdapter.getHeaderLayoutCount(); + SectionEntity entity = adapter.getItem(position); + + if (entity == null || entity.isHeader()) { + //不处理header + outRect.set(0, 0, 0, 0); +// Log.w("GridAverageGapItem", "pos=" + position + "," + outRect.toShortString()); + return; + } + + Section section = findSectionLastItemPos(position); + + if (gapHSizePx < 0 || gapVSizePx < 0) { + transformGapDefinition(parent, spanCount); + } + outRect.top = gapVSizePx; + outRect.bottom = 0; + + //下面的visualPos为单个Section内的视觉Pos + int visualPos = position + 1 - section.startPos; + if (visualPos % spanCount == 1) { + //第一列 + outRect.left = sectionEdgeHPaddingPx; + outRect.right = eachItemHPaddingPx - sectionEdgeHPaddingPx; + } else if (visualPos % spanCount == 0) { + //最后一列 + outRect.left = eachItemHPaddingPx - sectionEdgeHPaddingPx; + outRect.right = sectionEdgeHPaddingPx; + } else { + outRect.left = gapHSizePx - (eachItemHPaddingPx - sectionEdgeHPaddingPx); + outRect.right = eachItemHPaddingPx - outRect.left; + } + + if (visualPos - spanCount <= 0) { + //第一行 + outRect.top = sectionEdgeVPaddingPx; + } + + if (isLastRow(visualPos, spanCount, section.getCount())) { + //最后一行 + outRect.bottom = sectionEdgeVPaddingPx; +// Log.w("GridAverageGapItem", "last row pos=" + position); + } +// Log.w("GridAverageGapItem", "pos=" + position + ",vPos=" + visualPos + "," + outRect.toShortString()); + } else { + super.getItemOffsets(outRect, view, parent, state); + } + } + + private void setUpWithAdapter(BaseSectionQuickAdapter adapter) { + if (mAdapter != null) { + mAdapter.unregisterAdapterDataObserver(mDataObserver); + } + mAdapter = adapter; + mAdapter.registerAdapterDataObserver(mDataObserver); + markSections(); + } + + private void markSections() { + if (mAdapter != null) { + BaseSectionQuickAdapter adapter = mAdapter; + mSectionList.clear(); + SectionEntity sectionEntity = null; + Section section = new Section(); + for (int i = 0, size = adapter.getItemCount(); i < size; i++) { + sectionEntity = adapter.getItem(i); + if (sectionEntity != null && sectionEntity.isHeader()) { + //找到新Section起点 + if (section != null && i != 0) { + //已经有待添加的section + section.endPos = i - 1; + mSectionList.add(section); + } + section = new Section(); + section.startPos = i + 1; + } else { + section.endPos = i; + } + } + //处理末尾情况 + if (!mSectionList.contains(section)) { + mSectionList.add(section); + } + +// Log.w("GridAverageGapItem", "section list=" + mSectionList); + } + } + + private void transformGapDefinition(RecyclerView parent, int spanCount) { + DisplayMetrics displayMetrics = new DisplayMetrics(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + parent.getDisplay().getMetrics(displayMetrics); + } + gapHSizePx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, gapHorizontalDp, displayMetrics); + gapVSizePx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, gapVerticalDp, displayMetrics); + sectionEdgeHPaddingPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, sectionEdgeHPaddingDp, displayMetrics); + sectionEdgeVPaddingPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, sectionEdgeVPaddingDp, displayMetrics); + eachItemHPaddingPx = (sectionEdgeHPaddingPx * 2 + gapHSizePx * (spanCount - 1)) / spanCount; + } + + private Section findSectionLastItemPos(int curPos) { + for (Section section : mSectionList) { + if (section.contains(curPos)) { + return section; + } + } + return null; + } + + private boolean isLastRow(int visualPos, int spanCount, int sectionItemCount) { + int lastRowCount = sectionItemCount % spanCount; + lastRowCount = lastRowCount == 0 ? spanCount : lastRowCount; + return visualPos > sectionItemCount - lastRowCount; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/MovedImageButton.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/MovedImageButton.java new file mode 100644 index 0000000..841f073 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/MovedImageButton.java @@ -0,0 +1,93 @@ +package com.dahe.mylibrary.weight; + +import android.animation.ObjectAnimator; +import android.annotation.SuppressLint; +import android.content.Context; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.view.MotionEvent; +import android.view.animation.OvershootInterpolator; +import android.widget.ImageButton; + +import com.dahe.mylibrary.utils.BaseUtils; + +public class MovedImageButton extends androidx.appcompat.widget.AppCompatImageButton { + private int lastX; + private int lastY; + private float screenWidth; + + public MovedImageButton(Context context) { + super(context); + } + + public MovedImageButton(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public MovedImageButton(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + DisplayMetrics dm = getResources().getDisplayMetrics(); + screenWidth = dm.widthPixels; + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouchEvent(MotionEvent event) { + int x = (int) event.getX(); + int y = (int) event.getY(); + switch (event.getAction()){ + case MotionEvent.ACTION_DOWN: + lastX = x; + lastY = y; + break; + case MotionEvent.ACTION_MOVE: + int offsetX = x-lastX; + int offsetY = y-lastY; + //第一种方法 +// layout(getLeft()+offsetX, +// getTop()+offsetY, +// getRight()+offsetX, +// getBottom()+offsetY); + //第二种方法 + offsetLeftAndRight(offsetX); + offsetTopAndBottom(offsetY); + break; + case MotionEvent.ACTION_UP: + adsorbAnim(event.getRawX(), event.getRawY()); + break; + } + return super.onTouchEvent(event); + } + + private void adsorbAnim(float rawX, float rawY){ + //靠顶吸附 +// if (rawY <= BaseUtils.dip2px(getContext(),200)){//注意rawY包含了标题栏的高 +// animate().setDuration(400) +// .setInterpolator(new OvershootInterpolator()) +// .yBy(-getY()-getHeight()/2.0f) +// .start(); +// }else + + if (rawX >= screenWidth/2){//靠右吸附 + animate().setDuration(400) + .setInterpolator(new OvershootInterpolator()) + .xBy(screenWidth - getX() - getWidth()) + .start(); + }else {//靠左吸附 + ObjectAnimator animator = ObjectAnimator.ofFloat(this, "x", getX(), 0); + animator.setInterpolator(new OvershootInterpolator()); + animator.setDuration(400); + animator.start(); + } + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/MySlideBar.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/MySlideBar.java new file mode 100644 index 0000000..7bd8b59 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/MySlideBar.java @@ -0,0 +1,191 @@ +package com.dahe.mylibrary.weight; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import androidx.annotation.Nullable; + +import com.dahe.mylibrary.R; +import com.dahe.mylibrary.utils.ToastUtils; + +public class MySlideBar extends RelativeLayout implements View.OnClickListener { + + private boolean canSelect; + private TextView tvT1; + private TextView tvT2; + private TextView tvT3; + private TextView tvT4; + private TextView tvC1; + private TextView tvC2; + private TextView tvC3; + private TextView tvC4; + private View view1; + private View view2; + + public MySlideBar(Context context) { + this(context, null); + } + + public MySlideBar(Context context, @Nullable AttributeSet attrs) { + this(context, attrs, 0); + } + + public MySlideBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + this(context, attrs, 0, 0); + } + + public MySlideBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + init(context, attrs); + + + } + + private void init(Context context, AttributeSet attrs) { + View inflate = View.inflate(context, R.layout.view_slide_bar, this); + tvT1 = (TextView) findViewById(R.id.tv_title1); + tvT2 = (TextView) findViewById(R.id.tv_title2); + tvT3 = (TextView) findViewById(R.id.tv_title3); + tvT4 = (TextView) findViewById(R.id.tv_title4); + tvC1 = (TextView) findViewById(R.id.tv_conten1); + tvC2 = (TextView) findViewById(R.id.tv_content2); + tvC3 = (TextView) findViewById(R.id.tv_content3); + tvC4 = (TextView) findViewById(R.id.tv_content4); + view1 = (View) findViewById(R.id.view1); + view2 = (View) findViewById(R.id.view2); + LinearLayout ll1 = (LinearLayout) findViewById(R.id.ll1); + LinearLayout ll2 = (LinearLayout) findViewById(R.id.ll2); + LinearLayout ll3 = (LinearLayout) findViewById(R.id.ll3); + LinearLayout ll4 = (LinearLayout) findViewById(R.id.ll4); + ll1.setOnClickListener(this); + ll2.setOnClickListener(this); + ll3.setOnClickListener(this); + ll4.setOnClickListener(this); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MySlideBar); + int integer = a.getInteger(R.styleable.MySlideBar_proress, -1); + canSelect = a.getBoolean(R.styleable.MySlideBar_canSelect, false); + changeProress(integer,true); + + a.recycle(); + } + + @Override + public void onClick(View v) { + if (canSelect) { + int id = v.getId(); + if (id == R.id.ll1) { + changeProress(0,canSelect); + } else if (id == R.id.ll2) { + changeProress(1,canSelect); + } else if (id == R.id.ll3) { + changeProress(2,canSelect); + } else if (id == R.id.ll4) { + changeProress(3,canSelect); + } + } + + } + + public void setProress(int proress){ + changeProress(proress,canSelect); + } + + private void changeProress(int integer,boolean canSelect){ + if (listener!=null&&canSelect){ + listener.onChange(integer); + } + if (0 == integer) { + tvT1.setBackgroundResource(R.drawable.select_slide_title); + tvT2.setBackgroundResource(R.drawable.select_slide_title); + tvT3.setBackgroundResource(R.drawable.select_slide_title); + tvT4.setBackgroundResource(R.drawable.select_slide_title); + tvT1.setText("1"); + tvT2.setText("2"); + tvT3.setText("3"); + tvT4.setText("4"); + tvT1.setSelected(true); + tvT2.setSelected(false); + tvT3.setSelected(false); + tvT4.setSelected(false); + + view1.setBackgroundResource(R.color.color_d5); + view2.setBackgroundResource(R.color.color_d5); + + tvC1.setTextColor(getResources().getColor(R.color.mine_top_bg)); + tvC2.setTextColor(getResources().getColor(R.color.color_9)); + tvC3.setTextColor(getResources().getColor(R.color.color_9)); + tvC4.setTextColor(getResources().getColor(R.color.color_9)); + } else if (1 == integer) { + tvT1.setBackgroundResource(R.drawable.ok); + tvT2.setBackgroundResource(R.drawable.select_slide_title); + tvT3.setBackgroundResource(R.drawable.select_slide_title); + tvT4.setBackgroundResource(R.drawable.select_slide_title); + tvT1.setText(""); + tvT2.setText("2"); + tvT3.setText("3"); + tvT4.setText("4"); + tvT2.setSelected(true); + tvT3.setSelected(false); + tvT4.setSelected(false); + + view1.setBackgroundResource(R.color.mine_top_bg); + view2.setBackgroundResource(R.color.color_d5); + + tvC1.setTextColor(getResources().getColor(R.color.black)); + tvC2.setTextColor(getResources().getColor(R.color.mine_top_bg)); + tvC3.setTextColor(getResources().getColor(R.color.color_9)); + tvC4.setTextColor(getResources().getColor(R.color.color_9)); + } else if (2 == integer) { + tvT1.setBackgroundResource(R.drawable.ok); + tvT2.setBackgroundResource(R.drawable.ok); + tvT3.setBackgroundResource(R.drawable.select_slide_title); + tvT4.setBackgroundResource(R.drawable.select_slide_title); + tvT1.setText(""); + tvT2.setText(""); + tvT3.setText("3"); + tvT4.setText("4"); + tvT3.setSelected(true); + tvT4.setSelected(false); + + view1.setBackgroundResource(R.color.mine_top_bg); + view2.setBackgroundResource(R.color.mine_top_bg); + + tvC1.setTextColor(getResources().getColor(R.color.black)); + tvC2.setTextColor(getResources().getColor(R.color.black)); + tvC3.setTextColor(getResources().getColor(R.color.mine_top_bg)); + tvC4.setTextColor(getResources().getColor(R.color.color_9)); + } else if (3 == integer) { + tvT1.setBackgroundResource(R.drawable.ok); + tvT2.setBackgroundResource(R.drawable.ok); + tvT3.setBackgroundResource(R.drawable.ok); + tvT4.setBackgroundResource(R.drawable.select_slide_title); + tvT1.setText(""); + tvT2.setText(""); + tvT3.setText(""); + tvT4.setText("4"); + tvT4.setSelected(true); + + tvC1.setTextColor(getResources().getColor(R.color.black)); + tvC2.setTextColor(getResources().getColor(R.color.black)); + tvC3.setTextColor(getResources().getColor(R.color.black)); + tvC4.setTextColor(getResources().getColor(R.color.mine_top_bg)); + } + } + + + public interface OnChangeListener{ + void onChange(int progress); + } + + private OnChangeListener listener; + public void setOnChangeListener(OnChangeListener listener){ + this.listener = listener; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/SideBar.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/SideBar.java new file mode 100644 index 0000000..1b1e471 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/SideBar.java @@ -0,0 +1,130 @@ +package com.dahe.mylibrary.weight; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Typeface; +import android.graphics.drawable.ColorDrawable; +import android.os.Vibrator; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.widget.TextView; + +import com.dahe.mylibrary.R; + +public class SideBar extends View { + // 触摸事件 + private OnTouchingLetterChangedListener onTouchingLetterChangedListener; + public static String[] b = { "A", "B", "C", "D", "E", "F", "G", "H", "I", + "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", + "W", "X", "Y", "Z", "#" }; + private int choose = -1; + private Paint paint = new Paint(); + + private TextView mTextDialog; + + /** + * 为SideBar设置显示字母的TextView + * @param textDialog + */ + public void setTextView(TextView textDialog) { + this.mTextDialog = textDialog; + } + + + public SideBar(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + public SideBar(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public SideBar(Context context) { + super(context); + } + + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + int height = getHeight(); + int width = getWidth(); + int singleHeight = height / b.length;// 获取每一个字母的高度 + + for (int i = 0; i < b.length; i++) { + paint.setColor(Color.rgb(33, 65, 98)); + // paint.setColor(Color.WHITE); + paint.setTypeface(Typeface.DEFAULT_BOLD); + paint.setAntiAlias(true); + paint.setTextSize(20); + if (i == choose) {// 选中的状态 + paint.setColor(Color.parseColor("#999999")); + paint.setFakeBoldText(true); + } + // x坐标等于中间-字符串宽度的一半 + float xPos = width / 2 - paint.measureText(b[i]) / 2; + float yPos = singleHeight * i + singleHeight; + canvas.drawText(b[i], xPos, yPos, paint); + paint.reset(); + } + + } + + @Override + public boolean dispatchTouchEvent(MotionEvent event) { + final int action = event.getAction(); + final float y = event.getY(); + final int oldChoose = choose; + final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener; + final int c = (int) (y / getHeight() * b.length);// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数 + + switch (action) { + case MotionEvent.ACTION_UP: + setBackground(new ColorDrawable(0x00000000)); + choose = -1;// + invalidate(); + if (mTextDialog != null) { + mTextDialog.setVisibility(View.INVISIBLE); + } + break; + + default: +// setBackgroundResource(R.drawable.sidebar_background); + if (oldChoose != c) { + if (c >= 0 && c < b.length) { + if (listener != null) { + listener.onTouchingLetterChanged(b[c]); + } + if (mTextDialog != null) { + mTextDialog.setText(b[c]); + mTextDialog.setVisibility(View.VISIBLE); + } + + choose = c; + invalidate(); + } + } + + break; + } + return true; + } + + /** + * 触摸事件 + * @param onTouchingLetterChangedListener + */ + public void setOnTouchingLetterChangedListener( + OnTouchingLetterChangedListener onTouchingLetterChangedListener) { + this.onTouchingLetterChangedListener = onTouchingLetterChangedListener; + } + + /** + * 回调接口 + */ + public interface OnTouchingLetterChangedListener { + void onTouchingLetterChanged(String s); + } + +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/SwitchView.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/SwitchView.java new file mode 100644 index 0000000..93fbb50 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/SwitchView.java @@ -0,0 +1,508 @@ +package com.dahe.mylibrary.weight; + +import android.annotation.TargetApi; +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.RadialGradient; +import android.graphics.RectF; +import android.graphics.Shader; +import android.os.Build; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.MotionEvent; +import android.view.View; +import android.view.animation.AccelerateInterpolator; + +import com.dahe.mylibrary.R; + + +/** + * hei hei hei + */ +public class SwitchView extends View { + + private static final int STATE_SWITCH_ON = 4; + private static final int STATE_SWITCH_ON2 = 3; + private static final int STATE_SWITCH_OFF2 = 2; + private static final int STATE_SWITCH_OFF = 1; + + private final AccelerateInterpolator interpolator = new AccelerateInterpolator(2); + private final Paint paint = new Paint(); + private final Path sPath = new Path(); + private final Path bPath = new Path(); + private final RectF bRectF = new RectF(); + private float sAnim, bAnim; + private RadialGradient shadowGradient; + + protected float ratioAspect = 0.68f; // (0,1] + protected float animationSpeed = 0.1f; // (0,1] + + private int state; + private int lastState; + private boolean isCanVisibleDrawing = false; + private OnClickListener mOnClickListener; + protected int colorPrimary; + protected int colorPrimaryDark; + protected int colorOff; + protected int colorOffDark; + protected int colorShadow; + protected boolean hasShadow; + protected boolean isOpened; + protected boolean canEnable; + + private float sRight; + private float sCenterX, sCenterY; + private float sScale; + + private float bOffset; + private float bRadius, bStrokeWidth; + private float bWidth; + private float bLeft; + private float bRight; + private float bOnLeftX, bOn2LeftX, bOff2LeftX, bOffLeftX; + + private float shadowReservedHeight; + + public SwitchView(Context context) { + this(context, null); + } + + @TargetApi(Build.VERSION_CODES.HONEYCOMB) + public SwitchView(Context context, AttributeSet attrs) { + super(context, attrs); + setLayerType(LAYER_TYPE_SOFTWARE, null); + + final int DEFAULT_COLOR_PRIMARY = 0xFF4BD763; + final int DEFAULT_COLOR_PRIMARY_DARK = 0xFF3AC652; + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SwitchView); + colorPrimary = a.getColor(R.styleable.SwitchView_primaryColor, DEFAULT_COLOR_PRIMARY); + colorPrimaryDark = a.getColor(R.styleable.SwitchView_primaryColorDark, DEFAULT_COLOR_PRIMARY_DARK); + colorOff = a.getColor(R.styleable.SwitchView_offColor, 0xFFE3E3E3); + colorOffDark = a.getColor(R.styleable.SwitchView_offColorDark, 0xFFBFBFBF); + colorShadow = a.getColor(R.styleable.SwitchView_shadowColor, 0xFF333333); + ratioAspect = a.getFloat(R.styleable.SwitchView_ratioAspect, 0.68f); + hasShadow = a.getBoolean(R.styleable.SwitchView_hasShadow, true); + isOpened = a.getBoolean(R.styleable.SwitchView_isOpened, false); + canEnable = a.getBoolean(R.styleable.SwitchView_canEnable, true); + state = isOpened ? STATE_SWITCH_ON : STATE_SWITCH_OFF; + lastState = state; + a.recycle(); + + if (colorPrimary == DEFAULT_COLOR_PRIMARY && colorPrimaryDark == DEFAULT_COLOR_PRIMARY_DARK) { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + TypedValue primaryColorTypedValue = new TypedValue(); + context.getTheme().resolveAttribute(android.R.attr.colorPrimary, primaryColorTypedValue, true); + if (primaryColorTypedValue.data > 0) colorPrimary = primaryColorTypedValue.data; + TypedValue primaryColorDarkTypedValue = new TypedValue(); + context.getTheme().resolveAttribute(android.R.attr.colorPrimaryDark, primaryColorDarkTypedValue, true); + if (primaryColorDarkTypedValue.data > 0) + colorPrimaryDark = primaryColorDarkTypedValue.data; + } + } catch (Exception ignore) { + } + } + } + + public void setColor(int newColorPrimary, int newColorPrimaryDark) { + setColor(newColorPrimary, newColorPrimaryDark, colorOff, colorOffDark); + } + + public void setColor(int newColorPrimary, int newColorPrimaryDark, int newColorOff, int newColorOffDark) { + setColor(newColorPrimary, newColorPrimaryDark, newColorOff, newColorOffDark, colorShadow); + } + + public void setColor(int newColorPrimary, int newColorPrimaryDark, int newColorOff, int newColorOffDark, int newColorShadow) { + colorPrimary = newColorPrimary; + colorPrimaryDark = newColorPrimaryDark; + colorOff = newColorOff; + colorOffDark = newColorOffDark; + colorShadow = newColorShadow; + invalidate(); + } + + public void setCanEnable(boolean canEnable){ + this.canEnable = canEnable; + invalidate(); + } + + public void setShadow(boolean shadow) { + hasShadow = shadow; + invalidate(); + } + + public boolean isOpened() { + return isOpened; + } + + public void setOpened(boolean isOpened) { + int wishState = isOpened ? STATE_SWITCH_ON : STATE_SWITCH_OFF; + if (wishState == state) { + return; + } + refreshState(wishState); + } + + public void toggleSwitch(boolean isOpened) { + int wishState = isOpened ? STATE_SWITCH_ON : STATE_SWITCH_OFF; + if (wishState == state) { + return; + } + if ((wishState == STATE_SWITCH_ON && (state == STATE_SWITCH_OFF || state == STATE_SWITCH_OFF2)) + || (wishState == STATE_SWITCH_OFF && (state == STATE_SWITCH_ON || state == STATE_SWITCH_ON2))) { + sAnim = 1; + } + bAnim = 1; + refreshState(wishState); + } + + private void refreshState(int newState) { + if (!isOpened && newState == STATE_SWITCH_ON) { + isOpened = true; + } else if (isOpened && newState == STATE_SWITCH_OFF) { + isOpened = false; + } + lastState = state; + state = newState; + postInvalidate(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int widthSize = MeasureSpec.getSize(widthMeasureSpec); + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int resultWidth; + if (widthMode == MeasureSpec.EXACTLY) { + resultWidth = widthSize; + } else { + resultWidth = (int) (56 * getResources().getDisplayMetrics().density + 0.5f) + + getPaddingLeft() + getPaddingRight(); + if (widthMode == MeasureSpec.AT_MOST) { + resultWidth = Math.min(resultWidth, widthSize); + } + } + + int heightSize = MeasureSpec.getSize(heightMeasureSpec); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + int resultHeight; + if (heightMode == MeasureSpec.EXACTLY) { + resultHeight = heightSize; + } else { + resultHeight = (int) (resultWidth * ratioAspect) + getPaddingTop() + getPaddingBottom(); + if (heightMode == MeasureSpec.AT_MOST) { + resultHeight = Math.min(resultHeight, heightSize); + } + } + setMeasuredDimension(resultWidth, resultHeight); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + isCanVisibleDrawing = w > getPaddingLeft() + getPaddingRight() && h > getPaddingTop() + getPaddingBottom(); + + if (isCanVisibleDrawing) { + int actuallyDrawingAreaWidth = w - getPaddingLeft() - getPaddingRight(); + int actuallyDrawingAreaHeight = h - getPaddingTop() - getPaddingBottom(); + + int actuallyDrawingAreaLeft; + int actuallyDrawingAreaRight; + int actuallyDrawingAreaTop; + int actuallyDrawingAreaBottom; + if (actuallyDrawingAreaWidth * ratioAspect < actuallyDrawingAreaHeight) { + actuallyDrawingAreaLeft = getPaddingLeft(); + actuallyDrawingAreaRight = w - getPaddingRight(); + int heightExtraSize = (int) (actuallyDrawingAreaHeight - actuallyDrawingAreaWidth * ratioAspect); + actuallyDrawingAreaTop = getPaddingTop() + heightExtraSize / 2; + actuallyDrawingAreaBottom = getHeight() - getPaddingBottom() - heightExtraSize / 2; + } else { + int widthExtraSize = (int) (actuallyDrawingAreaWidth - actuallyDrawingAreaHeight / ratioAspect); + actuallyDrawingAreaLeft = getPaddingLeft() + widthExtraSize / 2; + actuallyDrawingAreaRight = getWidth() - getPaddingRight() - widthExtraSize / 2; + actuallyDrawingAreaTop = getPaddingTop(); + actuallyDrawingAreaBottom = getHeight() - getPaddingBottom(); + } + + shadowReservedHeight = (int) ((actuallyDrawingAreaBottom - actuallyDrawingAreaTop) * 0.07f); + float sLeft = actuallyDrawingAreaLeft; + float sTop = actuallyDrawingAreaTop + shadowReservedHeight; + sRight = actuallyDrawingAreaRight; + float sBottom = actuallyDrawingAreaBottom - shadowReservedHeight; + + float sHeight = sBottom - sTop; + sCenterX = (sRight + sLeft) / 2; + sCenterY = (sBottom + sTop) / 2; + + bLeft = sLeft; + bWidth = sBottom - sTop; + bRight = sLeft + bWidth; + final float halfHeightOfS = bWidth / 2; // OfB + bRadius = halfHeightOfS * 0.95f; + bOffset = bRadius * 0.2f; // offset of switching + bStrokeWidth = (halfHeightOfS - bRadius) * 2; + bOnLeftX = sRight - bWidth; + bOn2LeftX = bOnLeftX - bOffset; + bOffLeftX = sLeft; + bOff2LeftX = bOffLeftX + bOffset; + sScale = 1 - bStrokeWidth / sHeight; + + sPath.reset(); + RectF sRectF = new RectF(); + sRectF.top = sTop; + sRectF.bottom = sBottom; + sRectF.left = sLeft; + sRectF.right = sLeft + sHeight; + sPath.arcTo(sRectF, 90, 180); + sRectF.left = sRight - sHeight; + sRectF.right = sRight; + sPath.arcTo(sRectF, 270, 180); + sPath.close(); + + bRectF.left = bLeft; + bRectF.right = bRight; + bRectF.top = sTop + bStrokeWidth / 2; // bTop = sTop + bRectF.bottom = sBottom - bStrokeWidth / 2; // bBottom = sBottom + float bCenterX = (bRight + bLeft) / 2; + float bCenterY = (sBottom + sTop) / 2; + + int red = colorShadow >> 16 & 0xFF; + int green = colorShadow >> 8 & 0xFF; + int blue = colorShadow & 0xFF; + shadowGradient = new RadialGradient(bCenterX, bCenterY, bRadius, Color.argb(200, red, green, blue), + Color.argb(25, red, green, blue), Shader.TileMode.CLAMP); + } + } + + private void calcBPath(float percent) { + bPath.reset(); + bRectF.left = bLeft + bStrokeWidth / 2; + bRectF.right = bRight - bStrokeWidth / 2; + bPath.arcTo(bRectF, 90, 180); + bRectF.left = bLeft + percent * bOffset + bStrokeWidth / 2; + bRectF.right = bRight + percent * bOffset - bStrokeWidth / 2; + bPath.arcTo(bRectF, 270, 180); + bPath.close(); + } + + private float calcBTranslate(float percent) { + float result = 0; + switch (state - lastState) { + case 1: + if (state == STATE_SWITCH_OFF2) { + result = bOffLeftX; // off -> off2 + } else if (state == STATE_SWITCH_ON) { + result = bOnLeftX - (bOnLeftX - bOn2LeftX) * percent; // on2 -> on + } + break; + case 2: + if (state == STATE_SWITCH_ON) { + result = bOnLeftX - (bOnLeftX - bOffLeftX) * percent; // off2 -> on + } else if (state == STATE_SWITCH_ON2) { + result = bOn2LeftX - (bOn2LeftX - bOffLeftX) * percent; // off -> on2 + } + break; + case 3: + result = bOnLeftX - (bOnLeftX - bOffLeftX) * percent; // off -> on + break; + case -1: + if (state == STATE_SWITCH_ON2) { + result = bOn2LeftX + (bOnLeftX - bOn2LeftX) * percent; // on -> on2 + } else if (state == STATE_SWITCH_OFF) { + result = bOffLeftX; // off2 -> off + } + break; + case -2: + if (state == STATE_SWITCH_OFF) { + result = bOffLeftX + (bOn2LeftX - bOffLeftX) * percent; // on2 -> off + } else if (state == STATE_SWITCH_OFF2) { + result = bOff2LeftX + (bOnLeftX - bOff2LeftX) * percent; // on -> off2 + } + break; + case -3: + result = bOffLeftX + (bOnLeftX - bOffLeftX) * percent; // on -> off + break; + default: // init + case 0: + if (state == STATE_SWITCH_OFF) { + result = bOffLeftX; // off -> off + } else if (state == STATE_SWITCH_ON) { + result = bOnLeftX; // on -> on + } + break; + } + return result - bOffLeftX; + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + if (!isCanVisibleDrawing) return; + + paint.setAntiAlias(true); + final boolean isOn = (state == STATE_SWITCH_ON || state == STATE_SWITCH_ON2); + // Draw background + paint.setStyle(Paint.Style.FILL); + paint.setColor(isOn ? colorPrimary : colorOff); + canvas.drawPath(sPath, paint); + + sAnim = sAnim - animationSpeed > 0 ? sAnim - animationSpeed : 0; + bAnim = bAnim - animationSpeed > 0 ? bAnim - animationSpeed : 0; + + final float dsAnim = interpolator.getInterpolation(sAnim); + final float dbAnim = interpolator.getInterpolation(bAnim); + // Draw background animation + final float scale = sScale * (isOn ? dsAnim : 1 - dsAnim); + final float scaleOffset = (sRight - sCenterX - bRadius) * (isOn ? 1 - dsAnim : dsAnim); + canvas.save(); + canvas.scale(scale, scale, sCenterX + scaleOffset, sCenterY); + paint.setColor(0xFFFFFFFF); + canvas.drawPath(sPath, paint); + canvas.restore(); + // To prepare center bar path + canvas.save(); + canvas.translate(calcBTranslate(dbAnim), shadowReservedHeight); + final boolean isState2 = (state == STATE_SWITCH_ON2 || state == STATE_SWITCH_OFF2); + calcBPath(isState2 ? 1 - dbAnim : dbAnim); + // Use center bar path to draw shadow + if (hasShadow) { + paint.setStyle(Paint.Style.FILL); + paint.setShader(shadowGradient); + canvas.drawPath(bPath, paint); + paint.setShader(null); + } + canvas.translate(0, -shadowReservedHeight); + // draw bar + canvas.scale(0.98f, 0.98f, bWidth / 2, bWidth / 2); + paint.setStyle(Paint.Style.FILL); + paint.setColor(0xffffffff); + canvas.drawPath(bPath, paint); + paint.setStyle(Paint.Style.STROKE); + paint.setStrokeWidth(bStrokeWidth * 0.5f); + paint.setColor(isOn ? colorPrimaryDark : colorOffDark); + canvas.drawPath(bPath, paint); + canvas.restore(); + + paint.reset(); + if (sAnim > 0 || bAnim > 0) invalidate(); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (!canEnable) + return super.onTouchEvent(event); + if ((state == STATE_SWITCH_ON || state == STATE_SWITCH_OFF) && (sAnim * bAnim == 0)) { + switch (event.getAction()) { + case MotionEvent.ACTION_DOWN: + return true; + case MotionEvent.ACTION_UP: + lastState = state; + + bAnim = 1; + if (state == STATE_SWITCH_OFF) { + refreshState(STATE_SWITCH_OFF2); + listener.toggleToOn(this); + } else if (state == STATE_SWITCH_ON) { + refreshState(STATE_SWITCH_ON2); + listener.toggleToOff(this); + } + + if (mOnClickListener != null) { + mOnClickListener.onClick(this); + } + break; + } + } + return super.onTouchEvent(event); + } + + @Override + public void setOnClickListener(OnClickListener l) { + super.setOnClickListener(l); + mOnClickListener = l; + } + + public interface OnStateChangedListener { + void toggleToOn(SwitchView view); + + void toggleToOff(SwitchView view); + } + + private OnStateChangedListener listener = new OnStateChangedListener() { + @Override + public void toggleToOn(SwitchView view) { + toggleSwitch(true); + } + + @Override + public void toggleToOff(SwitchView view) { + toggleSwitch(false); + } + }; + + public void setOnStateChangedListener(OnStateChangedListener listener) { + if (listener == null) throw new IllegalArgumentException("empty listener"); + this.listener = listener; + } + + @Override + public Parcelable onSaveInstanceState() { + Parcelable superState = super.onSaveInstanceState(); + SavedState ss = new SavedState(superState); + ss.isOpened = isOpened; + return ss; + } + + @Override + public void onRestoreInstanceState(Parcelable state) { + SavedState ss = (SavedState) state; + super.onRestoreInstanceState(ss.getSuperState()); + this.isOpened = ss.isOpened; + this.state = this.isOpened ? STATE_SWITCH_ON : STATE_SWITCH_OFF; + invalidate(); + } + + private static final class SavedState extends BaseSavedState { + private boolean isOpened; + + SavedState(Parcelable superState) { + super(superState); + } + + private SavedState(Parcel in) { + super(in); + isOpened = 1 == in.readInt(); + } + + @Override + public void writeToParcel(Parcel out, int flags) { + super.writeToParcel(out, flags); + out.writeInt(isOpened ? 1 : 0); + } + + // fixed by Night99 https://github.com/g19980115 + @Override + public int describeContents() { + return 0; + } + + public static final Creator CREATOR = new Creator() { + @Override + public SavedState createFromParcel(Parcel in) { + return new SavedState(in); + } + + @Override + public SavedState[] newArray(int size) { + return new SavedState[size]; + } + }; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/segmentcontrol/RadiusDrawable.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/segmentcontrol/RadiusDrawable.java new file mode 100644 index 0000000..2569625 --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/segmentcontrol/RadiusDrawable.java @@ -0,0 +1,139 @@ +package com.dahe.mylibrary.weight.segmentcontrol; + + +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.PixelFormat; +import android.graphics.RectF; +import android.graphics.drawable.Drawable; + +// 圆角 Drawable 每个角的圆半径可以不同 (使用不同半径圆角图形的时候 使用这个类 以防止 系统提供的用 xml 实现的圆角 Drawable 在2.3 上 出现各个角位置错乱) + +/** + * Created by caifangmao on 15/4/22. + */ +public class RadiusDrawable extends Drawable { + + private int topLeftRadius; + private int topRightRadius; + private int bottomLeftRadius; + private int bottomRightRadius; + + private int left; + private int top; + private int right; + private int bottom; + + private final Paint paint; + private final boolean isStroke; + private int strokeWidth = 0; + private int strokeColor = Color.CYAN; + private int fillColor; + + private Path path; + + public RadiusDrawable(boolean isStroke) { + this(0, isStroke); + } + + public RadiusDrawable(int radius, boolean isStroke) { + setRadius(radius); + + paint = new Paint(Paint.ANTI_ALIAS_FLAG); + this.isStroke = isStroke; + } + + public void setStrokeWidth(int width) { + strokeWidth = width; + setBounds(left, top, right, bottom); + } + + public void setStrokeColor(int strokeColor) { + this.strokeColor = strokeColor; + } + + public void setFillColor(int fillColor) { + this.fillColor = fillColor; + } + + public void setRadius(int radius) { + this.topLeftRadius = this.topRightRadius = this.bottomLeftRadius = this.bottomRightRadius = radius; + } + + public void setRadius(int topLeftRadius, int topRightRadius, int bottomLeftRadius, int bottomRightRadius) { + this.topLeftRadius = topLeftRadius; + this.topRightRadius = topRightRadius; + this.bottomLeftRadius = bottomLeftRadius; + this.bottomRightRadius = bottomRightRadius; + } + + @Override + public void setBounds(int left, int top, int right, int bottom) { + super.setBounds(left, top, right, bottom); + + this.left = left; + this.top = top; + this.right = right; + this.bottom = bottom; + + if (isStroke) { + int halfStrokeWidth = strokeWidth / 2; + left += halfStrokeWidth; + top += halfStrokeWidth; + right -= halfStrokeWidth; + bottom -= halfStrokeWidth; + } + + path = new Path(); + path.moveTo(left + topLeftRadius, top); + path.lineTo(right - topRightRadius, top); + path.arcTo(new RectF(right - topRightRadius * 2, top, right, top + topRightRadius * 2), + -90, 90); + // path.quadTo(right, top, right, top + topRightRadius); + path.lineTo(right, bottom - bottomRightRadius); + path.arcTo(new RectF(right - bottomRightRadius * 2, bottom - bottomRightRadius * 2, right, + bottom), 0, 90); + // path.quadTo(right, bottom, right - bottomRightRadius, bottom); + path.lineTo(left + bottomLeftRadius, bottom); + path.arcTo(new RectF(left, bottom - bottomLeftRadius * 2, left + bottomLeftRadius * 2, + bottom), 90, 90); + // path.quadTo(left, bottom, left, bottom - bottomLeftRadius); + path.lineTo(left, top + topLeftRadius); + path.arcTo(new RectF(left, top, left + topLeftRadius * 2, top + topLeftRadius * 2), 180, 90); + // path.quadTo(left, top, left + topLeftRadius, top); + path.close(); + } + + @Override + public void draw(Canvas canvas) { + if (fillColor != 0) { + paint.setColor(fillColor); + paint.setStyle(Paint.Style.FILL); + canvas.drawPath(path, paint); + } + + if (strokeWidth > 0) { + paint.setColor(strokeColor); + paint.setStyle(Paint.Style.STROKE); + paint.setStrokeJoin(Paint.Join.MITER); + paint.setStrokeWidth(strokeWidth); + canvas.drawPath(path, paint); + } + } + + @Override + public void setAlpha(int alpha) { + } + + @Override + public void setColorFilter(ColorFilter cf) { + } + + @Override + public int getOpacity() { + return PixelFormat.TRANSLUCENT; + } +} diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/segmentcontrol/SegmentControl.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/segmentcontrol/SegmentControl.java new file mode 100644 index 0000000..a5bf65d --- /dev/null +++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/segmentcontrol/SegmentControl.java @@ -0,0 +1,526 @@ +package com.dahe.mylibrary.weight.segmentcontrol; + +import android.content.Context; +import android.content.res.ColorStateList; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.os.Build; +import android.util.AttributeSet; +import android.util.TypedValue; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; + +import com.dahe.mylibrary.R; + + +/** + * Created by 7heaven on 15/4/22. + */ +public class SegmentControl extends View { + + private String[] mTexts; + private Rect[] mCacheBounds; + private Rect[] mTextBounds; + + private RadiusDrawable mBackgroundDrawable; + private RadiusDrawable mSelectedDrawable; + + private int mCurrentIndex; + + private int mTouchSlop; + private boolean inTapRegion; + private float mStartX; + private float mStartY; + private float mCurrentX; + private float mCurrentY; + + private int mHorizonGap; + private int mVerticalGap; + + /** 外边框的width */ + private int mBoundWidth = 4; + /** 内边框的width */ + private int mSeparatorWidth = mBoundWidth / 2; + + private int mSingleChildWidth; + private int mSingleChildHeight; + + private Paint mPaint; + + private int mTextSize; + private ColorStateList mBackgroundColors; + private ColorStateList mTextColors; + private int mCornerRadius; + + private int DEFAULT_SELECTED_COLOR = 0xFF32ADFF; + private int DEFAULT_NORMAL_COLOR = 0xFFFFFFFF; + + private Paint.FontMetrics mCachedFM; + + public enum Direction { + HORIZONTAL(0), VERTICAL(1); + + int value; + + Direction(int v) { + value = v; + } + } + + private Direction mDirection; + + public SegmentControl(Context context) { + this(context, null); + } + + public SegmentControl(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public SegmentControl(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SegmentControl); + + String textArray = ta.getString(R.styleable.SegmentControl_texts); + if (textArray != null) { + mTexts = textArray.split("\\|"); + } + + mTextSize = ta.getDimensionPixelSize(R.styleable.SegmentControl_android_textSize, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 14, context.getResources().getDisplayMetrics())); + mCornerRadius = ta.getDimensionPixelSize(R.styleable.SegmentControl_cornerRadius, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, context.getResources().getDisplayMetrics())); + mDirection = Direction.values()[ta.getInt(R.styleable.SegmentControl_android_orientation, 0)]; + + mHorizonGap = ta.getDimensionPixelSize(R.styleable.SegmentControl_horizonGap, 0); + mVerticalGap = ta.getDimensionPixelSize(R.styleable.SegmentControl_verticalGap, 0); + + int gap = ta.getDimensionPixelSize(R.styleable.SegmentControl_gaps, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, context.getResources().getDisplayMetrics())); + + if(mHorizonGap == 0) { + mHorizonGap = gap; + } + if(mVerticalGap == 0) { + mVerticalGap = gap; + } + + mBackgroundDrawable = new RadiusDrawable(mCornerRadius, true); + mBackgroundDrawable.setStrokeWidth(2); + + DEFAULT_NORMAL_COLOR = ta.getColor(R.styleable.SegmentControl_normalColor, DEFAULT_NORMAL_COLOR); + DEFAULT_SELECTED_COLOR = ta.getColor(R.styleable.SegmentControl_selectedColor, DEFAULT_SELECTED_COLOR); + + mBackgroundColors = ta.getColorStateList(R.styleable.SegmentControl_backgroundColors); + mTextColors = ta.getColorStateList(R.styleable.SegmentControl_textColors); + if (mBackgroundColors == null) { + mBackgroundColors = new ColorStateList(new int[][]{{android.R.attr.state_selected}, {-android.R.attr.state_selected}}, new int[]{DEFAULT_SELECTED_COLOR, DEFAULT_NORMAL_COLOR}); + } + + if(mTextColors == null){ + mTextColors = new ColorStateList(new int[][]{{android.R.attr.state_selected}, {-android.R.attr.state_selected}}, new int[]{DEFAULT_NORMAL_COLOR, DEFAULT_SELECTED_COLOR}); + } + + mBoundWidth = ta.getDimensionPixelSize(R.styleable.SegmentControl_boundWidth, mBoundWidth); + mSeparatorWidth = ta.getDimensionPixelSize(R.styleable.SegmentControl_separatorWidth, mSeparatorWidth); + + ta.recycle(); + + mBackgroundDrawable = new RadiusDrawable(mCornerRadius, true); + mBackgroundDrawable.setStrokeWidth(mBoundWidth); + mBackgroundDrawable.setStrokeColor(getSelectedBGColor()); + mBackgroundDrawable.setFillColor(getNormalBGColor()); + + if (Build.VERSION.SDK_INT < 16) { + setBackgroundDrawable(mBackgroundDrawable); + } else { + setBackground(mBackgroundDrawable); + } + + mSelectedDrawable = new RadiusDrawable(false); + mSelectedDrawable.setFillColor(getSelectedBGColor()); + + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mPaint.setTextSize(mTextSize); + mCachedFM = mPaint.getFontMetrics(); + + int touchSlop = 0; + if (context == null) { + touchSlop = ViewConfiguration.getTouchSlop(); + } else { + final ViewConfiguration config = ViewConfiguration.get(context); + touchSlop = config.getScaledTouchSlop(); + } + mTouchSlop = touchSlop * touchSlop; + inTapRegion = false; + } + + public void setText(String... texts) { + mTexts = texts; + if (mTexts != null) { + requestLayout(); + } + } + + /** + * 设置文字颜色 + * + * @param color 需要设置的颜色 + */ + public void setSelectedTextColors(ColorStateList color) { + mTextColors = color; + invalidate(); + } + + /** + * 设置背景颜色 + * + * @param colors 颜色 + */ + public void setColors(ColorStateList colors) { + mBackgroundColors = colors; + + if (mBackgroundDrawable != null) { + mBackgroundDrawable.setStrokeColor(getSelectedBGColor()); + mBackgroundDrawable.setFillColor(getNormalBGColor()); + } + + if (mSelectedDrawable != null) { + mSelectedDrawable.setFillColor(getSelectedBGColor()); + } + + invalidate(); + } + + public void setCornerRadius(int cornerRadius) { + mCornerRadius = cornerRadius; + + if (mBackgroundDrawable != null) { + mBackgroundDrawable.setRadius(cornerRadius); + } + + invalidate(); + } + + public void setDirection(Direction direction) { + Direction tDirection = mDirection; + + mDirection = direction; + + if (tDirection != direction) { + requestLayout(); + invalidate(); + } + } + + public void setTextSize(int textSize_sp) { + setTextSize(TypedValue.COMPLEX_UNIT_SP, textSize_sp); + } + + public void setTextSize(int unit, int textSize) { + mPaint.setTextSize((int) (TypedValue.applyDimension(unit, textSize, getContext().getResources().getDisplayMetrics()))); + + if (textSize != mTextSize) { + mTextSize = textSize; + mCachedFM = mPaint.getFontMetrics(); + + requestLayout(); + } + } + + public void setSelectedIndex(int index) { + mCurrentIndex = index; + + if(mOnSegmentControlClickListener != null) { + mOnSegmentControlClickListener.onSegmentControlClick(index); + } + + invalidate(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + + int widthSize = MeasureSpec.getSize(widthMeasureSpec); + int heightSize = MeasureSpec.getSize(heightMeasureSpec); + + int width = 0; + int height = 0; + + if (mTexts != null && mTexts.length > 0) { + + mSingleChildHeight = 0; + mSingleChildWidth = 0; + + if (mCacheBounds == null || mCacheBounds.length != mTexts.length) { + mCacheBounds = new Rect[mTexts.length]; + } + + if (mTextBounds == null || mTextBounds.length != mTexts.length) { + mTextBounds = new Rect[mTexts.length]; + } + + for (int i = 0; i < mTexts.length; i++) { + String text = mTexts[i]; + + if(text != null){ + + if(mTextBounds[i] == null) { + mTextBounds[i] = new Rect(); + } + + mPaint.getTextBounds(text, 0, text.length(), mTextBounds[i]); + + if(mSingleChildWidth < mTextBounds[i].width() + mHorizonGap * 2) { + mSingleChildWidth = mTextBounds[i].width() + mHorizonGap * 2; + } + if(mSingleChildHeight < mTextBounds[i].height() + mVerticalGap * 2) { + mSingleChildHeight = mTextBounds[i].height() + mVerticalGap * 2; + } + } + } + + switch (widthMode) { + case MeasureSpec.AT_MOST: + if (mDirection == Direction.HORIZONTAL) { + if (widthSize <= mSingleChildWidth * mTexts.length) { + mSingleChildWidth = widthSize / mTexts.length; + width = widthSize; + } else { + width = mSingleChildWidth * mTexts.length; + } + } else { + width = widthSize <= mSingleChildWidth ? widthSize : mSingleChildWidth; + } + break; + case MeasureSpec.EXACTLY: + width = widthSize; + break; + case MeasureSpec.UNSPECIFIED: + default: + if (mDirection == Direction.HORIZONTAL) { + width = mSingleChildWidth * mTexts.length; + } else { + width = mSingleChildWidth; + } + break; + } + + switch (heightMode) { + case MeasureSpec.AT_MOST: + if (mDirection == Direction.VERTICAL) { + if (heightSize <= mSingleChildHeight * mTexts.length) { + mSingleChildHeight = heightSize / mTexts.length; + height = heightSize; + } else { + height = mSingleChildHeight * mTexts.length; + } + } else { + height = heightSize <= mSingleChildHeight ? heightSize : mSingleChildHeight; + } + break; + case MeasureSpec.EXACTLY: + height = heightSize; + break; + case MeasureSpec.UNSPECIFIED: + default: + if (mDirection == Direction.VERTICAL) { + height = mSingleChildHeight * mTexts.length; + } else { + height = mSingleChildHeight; + } + + break; + } + + switch (mDirection) { + case HORIZONTAL: + if (mSingleChildWidth != width / mTexts.length) { + mSingleChildWidth = width / mTexts.length; + } + mSingleChildHeight = height; + break; + case VERTICAL: + if(mSingleChildHeight != height / mTexts.length) { + mSingleChildHeight = height / mTexts.length; + } + mSingleChildWidth = width; + break; + default: + break; + } + + for (int i = 0; i < mTexts.length; i++) { + + if (mCacheBounds[i] == null) { + mCacheBounds[i] = new Rect(); + } + + if (mDirection == Direction.HORIZONTAL) { + mCacheBounds[i].left = i * mSingleChildWidth; + mCacheBounds[i].top = 0; + } else { + mCacheBounds[i].left = 0; + mCacheBounds[i].top = i * mSingleChildHeight; + } + + mCacheBounds[i].right = mCacheBounds[i].left + mSingleChildWidth; + mCacheBounds[i].bottom = mCacheBounds[i].top + mSingleChildHeight; + } + } else { + width = widthMode == MeasureSpec.UNSPECIFIED ? 0 : widthSize; + height = heightMode == MeasureSpec.UNSPECIFIED ? 0 : heightSize; + } + + setMeasuredDimension(width, height); + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + switch (event.getAction() & MotionEvent.ACTION_MASK) { + case MotionEvent.ACTION_DOWN: + inTapRegion = true; + + mStartX = event.getX(); + mStartY = event.getY(); + break; + + case MotionEvent.ACTION_MOVE: + mCurrentX = event.getX(); + mCurrentY = event.getY(); + + int dx = (int) (mCurrentX - mStartX); + int dy = (int) (mCurrentY - mStartY); + + int distance = dx * dx + dy * dy; + + if (distance > mTouchSlop) { + inTapRegion = false; + } + break; + + case MotionEvent.ACTION_UP: + if (inTapRegion) { + int index = 0; + if (mDirection == Direction.HORIZONTAL) { + index = (int) (mStartX / mSingleChildWidth); + } else { + index = (int) (mStartY / mSingleChildHeight); + } + + setSelectedIndex(index); + } + break; + default: + break; + } + return true; + } + + private int getSelectedTextColor(){ + return mTextColors.getColorForState(new int[]{android.R.attr.state_selected}, DEFAULT_NORMAL_COLOR); + } + + private int getNormalTextColor(){ + return mTextColors.getColorForState(new int[]{-android.R.attr.state_selected}, DEFAULT_SELECTED_COLOR); + } + + private int getSelectedBGColor(){ + return mBackgroundColors.getColorForState(new int[]{android.R.attr.state_selected}, DEFAULT_SELECTED_COLOR); + } + + private int getNormalBGColor(){ + return mBackgroundColors.getColorForState(new int[]{-android.R.attr.state_selected}, DEFAULT_NORMAL_COLOR); + } + + @Override + public void onDraw(Canvas canvas) { + super.onDraw(canvas); + + if (mTexts != null && mTexts.length > 0) { + + for (int i = 0; i < mTexts.length; i++) { + + //draw separate lines + if (i < mTexts.length - 1) { + mPaint.setColor(getSelectedBGColor()); + mPaint.setStrokeWidth(mSeparatorWidth); + if (mDirection == Direction.HORIZONTAL) { + canvas.drawLine(mCacheBounds[i].right, 0, mCacheBounds[i].right, getHeight(), mPaint); + } else { + canvas.drawLine(mCacheBounds[i].left, mSingleChildHeight * (i + 1), mCacheBounds[i].right, mSingleChildHeight * (i + 1), mPaint); + } + } + + //draw selected drawable + if (i == mCurrentIndex && mSelectedDrawable != null) { + int topLeftRadius = 0; + int topRightRadius = 0; + int bottomLeftRadius = 0; + int bottomRightRadius = 0; + + if(mTexts.length == 1){ + topLeftRadius = mCornerRadius; + bottomLeftRadius = mCornerRadius; + topRightRadius = mCornerRadius; + bottomRightRadius = mCornerRadius; + }else{ + if (mDirection == Direction.HORIZONTAL) { + if (i == 0) { + topLeftRadius = mCornerRadius; + bottomLeftRadius = mCornerRadius; + } else if (i == mTexts.length - 1) { + topRightRadius = mCornerRadius; + bottomRightRadius = mCornerRadius; + } + } else { + if (i == 0) { + topLeftRadius = mCornerRadius; + topRightRadius = mCornerRadius; + } else if (i == mTexts.length - 1) { + bottomLeftRadius = mCornerRadius; + bottomRightRadius = mCornerRadius; + } + } + } + + mSelectedDrawable.setRadius(topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius); + mSelectedDrawable.setBounds(mCacheBounds[i]); + mSelectedDrawable.draw(canvas); + + mPaint.setColor(getSelectedTextColor()); + } else { + mPaint.setColor(getNormalTextColor()); + } + + //draw texts + + float baseline = mCacheBounds[i].top + ((mSingleChildHeight - mCachedFM.ascent + mCachedFM.descent) / 2) - mCachedFM.descent; + canvas.drawText(mTexts[i], mCacheBounds[i].left + (mSingleChildWidth - mTextBounds[i].width()) / 2, baseline, mPaint); + + } + } + } + + // ========================================================= + // OnSegmentControlClickListener + // ========================================================= + private OnSegmentControlClickListener mOnSegmentControlClickListener; + + public void setOnSegmentControlClickListener(OnSegmentControlClickListener listener) { + mOnSegmentControlClickListener = listener; + } + + public OnSegmentControlClickListener getOnSegmentControlClicklistener() { + return mOnSegmentControlClickListener; + } + + public interface OnSegmentControlClickListener { + void onSegmentControlClick(int index); + } +} diff --git a/mylibrary/src/main/res/anim/anim_bottom_in.xml b/mylibrary/src/main/res/anim/anim_bottom_in.xml new file mode 100644 index 0000000..e1191a5 --- /dev/null +++ b/mylibrary/src/main/res/anim/anim_bottom_in.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/anim/anim_bottom_out.xml b/mylibrary/src/main/res/anim/anim_bottom_out.xml new file mode 100644 index 0000000..2c2299b --- /dev/null +++ b/mylibrary/src/main/res/anim/anim_bottom_out.xml @@ -0,0 +1,9 @@ + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/color/select_text_color.xml b/mylibrary/src/main/res/color/select_text_color.xml new file mode 100644 index 0000000..e3e3992 --- /dev/null +++ b/mylibrary/src/main/res/color/select_text_color.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable-hdpi/left.png b/mylibrary/src/main/res/drawable-hdpi/left.png new file mode 100644 index 0000000..6a9e644 Binary files /dev/null and b/mylibrary/src/main/res/drawable-hdpi/left.png differ diff --git a/mylibrary/src/main/res/drawable-xhdpi/black_back.png b/mylibrary/src/main/res/drawable-xhdpi/black_back.png new file mode 100644 index 0000000..c12c77f Binary files /dev/null and b/mylibrary/src/main/res/drawable-xhdpi/black_back.png differ diff --git a/mylibrary/src/main/res/drawable-xhdpi/fab_add.png b/mylibrary/src/main/res/drawable-xhdpi/fab_add.png new file mode 100644 index 0000000..c118072 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xhdpi/fab_add.png differ diff --git a/mylibrary/src/main/res/drawable-xhdpi/ic_add_image.png b/mylibrary/src/main/res/drawable-xhdpi/ic_add_image.png new file mode 100644 index 0000000..38e38da Binary files /dev/null and b/mylibrary/src/main/res/drawable-xhdpi/ic_add_image.png differ diff --git a/mylibrary/src/main/res/drawable-xhdpi/icon_upload.png b/mylibrary/src/main/res/drawable-xhdpi/icon_upload.png new file mode 100644 index 0000000..d8ff158 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xhdpi/icon_upload.png differ diff --git a/mylibrary/src/main/res/drawable-xhdpi/left.png b/mylibrary/src/main/res/drawable-xhdpi/left.png new file mode 100644 index 0000000..fa0ec3d Binary files /dev/null and b/mylibrary/src/main/res/drawable-xhdpi/left.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/cars.png b/mylibrary/src/main/res/drawable-xxhdpi/cars.png new file mode 100644 index 0000000..c0959a8 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/cars.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/cha.png b/mylibrary/src/main/res/drawable-xxhdpi/cha.png new file mode 100644 index 0000000..7b2ce05 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/cha.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/check_nor.png b/mylibrary/src/main/res/drawable-xxhdpi/check_nor.png new file mode 100644 index 0000000..7b92670 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/check_nor.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/check_sel.png b/mylibrary/src/main/res/drawable-xxhdpi/check_sel.png new file mode 100644 index 0000000..b88f5e3 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/check_sel.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/diss.png b/mylibrary/src/main/res/drawable-xxhdpi/diss.png new file mode 100644 index 0000000..eae77a0 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/diss.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/empty.png b/mylibrary/src/main/res/drawable-xxhdpi/empty.png new file mode 100644 index 0000000..2bc4195 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/empty.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/error.png b/mylibrary/src/main/res/drawable-xxhdpi/error.png new file mode 100644 index 0000000..771f025 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/error.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/fab_add.png b/mylibrary/src/main/res/drawable-xxhdpi/fab_add.png new file mode 100644 index 0000000..07af313 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/fab_add.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/icon_refuse.png b/mylibrary/src/main/res/drawable-xxhdpi/icon_refuse.png new file mode 100644 index 0000000..78a9c52 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/icon_refuse.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/id_select.png b/mylibrary/src/main/res/drawable-xxhdpi/id_select.png new file mode 100644 index 0000000..c2f3394 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/id_select.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/id_select_loading.png b/mylibrary/src/main/res/drawable-xxhdpi/id_select_loading.png new file mode 100644 index 0000000..fa1a413 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/id_select_loading.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/id_select_z.png b/mylibrary/src/main/res/drawable-xxhdpi/id_select_z.png new file mode 100644 index 0000000..629b84d Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/id_select_z.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/left.png b/mylibrary/src/main/res/drawable-xxhdpi/left.png new file mode 100644 index 0000000..78dfb14 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/left.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/message.png b/mylibrary/src/main/res/drawable-xxhdpi/message.png new file mode 100644 index 0000000..b976b4e Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/message.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/ok.png b/mylibrary/src/main/res/drawable-xxhdpi/ok.png new file mode 100644 index 0000000..e64bc5b Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/ok.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/update_head.png b/mylibrary/src/main/res/drawable-xxhdpi/update_head.png new file mode 100644 index 0000000..97ac15d Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/update_head.png differ diff --git a/mylibrary/src/main/res/drawable-xxhdpi/version_top_bg.png b/mylibrary/src/main/res/drawable-xxhdpi/version_top_bg.png new file mode 100644 index 0000000..8312c7c Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/version_top_bg.png differ diff --git a/mylibrary/src/main/res/drawable-xxxhdpi/left.png b/mylibrary/src/main/res/drawable-xxxhdpi/left.png new file mode 100644 index 0000000..7e9f9c5 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxxhdpi/left.png differ diff --git a/mylibrary/src/main/res/drawable-xxxhdpi/version_top_bg.png b/mylibrary/src/main/res/drawable-xxxhdpi/version_top_bg.png new file mode 100644 index 0000000..e462198 Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxxhdpi/version_top_bg.png differ diff --git a/mylibrary/src/main/res/drawable/bnav_shape_du.xml b/mylibrary/src/main/res/drawable/bnav_shape_du.xml new file mode 100644 index 0000000..28f5f8d --- /dev/null +++ b/mylibrary/src/main/res/drawable/bnav_shape_du.xml @@ -0,0 +1,13 @@ + + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/bnav_tab_background.xml b/mylibrary/src/main/res/drawable/bnav_tab_background.xml new file mode 100644 index 0000000..270a701 --- /dev/null +++ b/mylibrary/src/main/res/drawable/bnav_tab_background.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/loading.xml b/mylibrary/src/main/res/drawable/loading.xml new file mode 100644 index 0000000..0ab50a0 --- /dev/null +++ b/mylibrary/src/main/res/drawable/loading.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/select_check_node.xml b/mylibrary/src/main/res/drawable/select_check_node.xml new file mode 100644 index 0000000..1cec8b6 --- /dev/null +++ b/mylibrary/src/main/res/drawable/select_check_node.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/select_sim_text.xml b/mylibrary/src/main/res/drawable/select_sim_text.xml new file mode 100644 index 0000000..d16b429 --- /dev/null +++ b/mylibrary/src/main/res/drawable/select_sim_text.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/select_slide_title.xml b/mylibrary/src/main/res/drawable/select_slide_title.xml new file mode 100644 index 0000000..bf8e084 --- /dev/null +++ b/mylibrary/src/main/res/drawable/select_slide_title.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/select_text_c.xml b/mylibrary/src/main/res/drawable/select_text_c.xml new file mode 100644 index 0000000..5a4b510 --- /dev/null +++ b/mylibrary/src/main/res/drawable/select_text_c.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shadow_bg.9.png b/mylibrary/src/main/res/drawable/shadow_bg.9.png new file mode 100644 index 0000000..6dd4442 Binary files /dev/null and b/mylibrary/src/main/res/drawable/shadow_bg.9.png differ diff --git a/mylibrary/src/main/res/drawable/shape_bg8.xml b/mylibrary/src/main/res/drawable/shape_bg8.xml new file mode 100644 index 0000000..ba34bfb --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_bg8.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_bind_phone_background.xml b/mylibrary/src/main/res/drawable/shape_bind_phone_background.xml new file mode 100644 index 0000000..270e9f0 --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_bind_phone_background.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_blue_bg10.xml b/mylibrary/src/main/res/drawable/shape_blue_bg10.xml new file mode 100644 index 0000000..a9bae1b --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_blue_bg10.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_blue_bg25.xml b/mylibrary/src/main/res/drawable/shape_blue_bg25.xml new file mode 100644 index 0000000..cdccedf --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_blue_bg25.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_blue_bg4.xml b/mylibrary/src/main/res/drawable/shape_blue_bg4.xml new file mode 100644 index 0000000..dd388ad --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_blue_bg4.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_blue_bg8.xml b/mylibrary/src/main/res/drawable/shape_blue_bg8.xml new file mode 100644 index 0000000..6e7e086 --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_blue_bg8.xml @@ -0,0 +1,13 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_bottom_bgw16.xml b/mylibrary/src/main/res/drawable/shape_bottom_bgw16.xml new file mode 100644 index 0000000..ad939cf --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_bottom_bgw16.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_gray_bg10.xml b/mylibrary/src/main/res/drawable/shape_gray_bg10.xml new file mode 100644 index 0000000..4a9a9e5 --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_gray_bg10.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_gray_bg25.xml b/mylibrary/src/main/res/drawable/shape_gray_bg25.xml new file mode 100644 index 0000000..bb01f39 --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_gray_bg25.xml @@ -0,0 +1,15 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_gray_bg4.xml b/mylibrary/src/main/res/drawable/shape_gray_bg4.xml new file mode 100644 index 0000000..7ed2a61 --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_gray_bg4.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_log_btn_bg22.xml b/mylibrary/src/main/res/drawable/shape_log_btn_bg22.xml new file mode 100644 index 0000000..6a526c2 --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_log_btn_bg22.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_message.xml b/mylibrary/src/main/res/drawable/shape_message.xml new file mode 100644 index 0000000..f70d586 --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_message.xml @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_text_4_blue.xml b/mylibrary/src/main/res/drawable/shape_text_4_blue.xml new file mode 100644 index 0000000..9d7ac38 --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_text_4_blue.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_text_4_nor.xml b/mylibrary/src/main/res/drawable/shape_text_4_nor.xml new file mode 100644 index 0000000..9389c1b --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_text_4_nor.xml @@ -0,0 +1,17 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/shape_view_v.xml b/mylibrary/src/main/res/drawable/shape_view_v.xml new file mode 100644 index 0000000..d59ee95 --- /dev/null +++ b/mylibrary/src/main/res/drawable/shape_view_v.xml @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/drawable/white_round_corner_bg.xml b/mylibrary/src/main/res/drawable/white_round_corner_bg.xml new file mode 100644 index 0000000..d330d5b --- /dev/null +++ b/mylibrary/src/main/res/drawable/white_round_corner_bg.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/layout/common_toolbar.xml b/mylibrary/src/main/res/layout/common_toolbar.xml new file mode 100644 index 0000000..ce88b6e --- /dev/null +++ b/mylibrary/src/main/res/layout/common_toolbar.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/mylibrary/src/main/res/layout/custom_dic_popup.xml b/mylibrary/src/main/res/layout/custom_dic_popup.xml new file mode 100644 index 0000000..9f161b1 --- /dev/null +++ b/mylibrary/src/main/res/layout/custom_dic_popup.xml @@ -0,0 +1,15 @@ + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/layout/custom_part_shadow_popup.xml b/mylibrary/src/main/res/layout/custom_part_shadow_popup.xml new file mode 100644 index 0000000..bfbd9d4 --- /dev/null +++ b/mylibrary/src/main/res/layout/custom_part_shadow_popup.xml @@ -0,0 +1,10 @@ + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/layout/dialog_phone.xml b/mylibrary/src/main/res/layout/dialog_phone.xml new file mode 100644 index 0000000..1624eb3 --- /dev/null +++ b/mylibrary/src/main/res/layout/dialog_phone.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/layout/dialog_photo_select.xml b/mylibrary/src/main/res/layout/dialog_photo_select.xml new file mode 100644 index 0000000..85a4382 --- /dev/null +++ b/mylibrary/src/main/res/layout/dialog_photo_select.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/layout/empty.xml b/mylibrary/src/main/res/layout/empty.xml new file mode 100644 index 0000000..b6c7977 --- /dev/null +++ b/mylibrary/src/main/res/layout/empty.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + diff --git a/mylibrary/src/main/res/layout/empty_pic.xml b/mylibrary/src/main/res/layout/empty_pic.xml new file mode 100644 index 0000000..52b216b --- /dev/null +++ b/mylibrary/src/main/res/layout/empty_pic.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + diff --git a/mylibrary/src/main/res/layout/gv_filter_image.xml b/mylibrary/src/main/res/layout/gv_filter_image.xml new file mode 100644 index 0000000..3a5194e --- /dev/null +++ b/mylibrary/src/main/res/layout/gv_filter_image.xml @@ -0,0 +1,46 @@ + + + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/layout/item_car_select.xml b/mylibrary/src/main/res/layout/item_car_select.xml new file mode 100644 index 0000000..414e97c --- /dev/null +++ b/mylibrary/src/main/res/layout/item_car_select.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/layout/item_dic_select.xml b/mylibrary/src/main/res/layout/item_dic_select.xml new file mode 100644 index 0000000..9e94d4c --- /dev/null +++ b/mylibrary/src/main/res/layout/item_dic_select.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/layout/item_node_select.xml b/mylibrary/src/main/res/layout/item_node_select.xml new file mode 100644 index 0000000..396acb0 --- /dev/null +++ b/mylibrary/src/main/res/layout/item_node_select.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/layout/item_select.xml b/mylibrary/src/main/res/layout/item_select.xml new file mode 100644 index 0000000..56a9f34 --- /dev/null +++ b/mylibrary/src/main/res/layout/item_select.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/layout/my_confim_popup_input.xml b/mylibrary/src/main/res/layout/my_confim_popup_input.xml new file mode 100644 index 0000000..db788f2 --- /dev/null +++ b/mylibrary/src/main/res/layout/my_confim_popup_input.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/layout/my_confim_popup_tip.xml b/mylibrary/src/main/res/layout/my_confim_popup_tip.xml new file mode 100644 index 0000000..366f7cf --- /dev/null +++ b/mylibrary/src/main/res/layout/my_confim_popup_tip.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + diff --git a/mylibrary/src/main/res/layout/view_slide_bar.xml b/mylibrary/src/main/res/layout/view_slide_bar.xml new file mode 100644 index 0000000..80483e7 --- /dev/null +++ b/mylibrary/src/main/res/layout/view_slide_bar.xml @@ -0,0 +1,182 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mylibrary/src/main/res/values/attrs.xml b/mylibrary/src/main/res/values/attrs.xml new file mode 100644 index 0000000..6af9f09 --- /dev/null +++ b/mylibrary/src/main/res/values/attrs.xml @@ -0,0 +1,211 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/values/colors.xml b/mylibrary/src/main/res/values/colors.xml new file mode 100644 index 0000000..2a87706 --- /dev/null +++ b/mylibrary/src/main/res/values/colors.xml @@ -0,0 +1,30 @@ + + + #28B950 + #28B950 + #D81B60 + + #FFFFFFFF + #333333 + #666666 + #FE0606 + #ff007aff + #3C6FC6 + #88888888 + + + + + #F5F5F5 + #000000 + #E6E6E6 + #F7F7F7 + #999999 + #f6f6f6 + #D5D9DB + + + + + + diff --git a/mylibrary/src/main/res/values/dimens.xml b/mylibrary/src/main/res/values/dimens.xml new file mode 100644 index 0000000..003e401 --- /dev/null +++ b/mylibrary/src/main/res/values/dimens.xml @@ -0,0 +1,26 @@ + + + 8sp + 9sp + 10sp + 11sp + 12sp + 13sp + 14sp + 15sp + 16sp + 17sp + 18sp + 19sp + 20sp + 21sp + 22sp + 23sp + 24sp + 26sp + 28sp + 30sp + 40sp + 56dp + 40dp + diff --git a/mylibrary/src/main/res/values/ids.xml b/mylibrary/src/main/res/values/ids.xml new file mode 100644 index 0000000..efaf17b --- /dev/null +++ b/mylibrary/src/main/res/values/ids.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/mylibrary/src/main/res/values/strings.xml b/mylibrary/src/main/res/values/strings.xml new file mode 100644 index 0000000..708d45e --- /dev/null +++ b/mylibrary/src/main/res/values/strings.xml @@ -0,0 +1,7 @@ + + CommonBaseLibrary + + 拍照 + 从相册中选择 + 取消 + diff --git a/mylibrary/src/main/res/values/styles.xml b/mylibrary/src/main/res/values/styles.xml new file mode 100644 index 0000000..6c47106 --- /dev/null +++ b/mylibrary/src/main/res/values/styles.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mylibrary/src/test/java/com/dahe/mylibrary/ExampleUnitTest.kt b/mylibrary/src/test/java/com/dahe/mylibrary/ExampleUnitTest.kt new file mode 100644 index 0000000..0e4dd1d --- /dev/null +++ b/mylibrary/src/test/java/com/dahe/mylibrary/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package com.dahe.mylibrary + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 05b3c75..ad6d5be 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,3 @@ rootProject.name = "app-dhhy-cargo" include ':app' +include ':mylibrary'