From 8dfa8fa02e2285f2164c1efe83ccfd99ef189635 Mon Sep 17 00:00:00 2001
From: fanhuitong <981964879@qq.com>
Date: Mon, 11 Oct 2021 20:22:32 +0800
Subject: [PATCH] date:2021-10-11 20:21:37
---
app/build.gradle | 23 +-
app/src/main/AndroidManifest.xml | 4 +-
.../java/com/tt/activity/JMainActivity.java | 21 +-
.../java/com/tt/base/ImmerseBaseActivity.java | 53 +++
.../main/java/com/tt/base/JMyApplication.java | 8 +
.../com/tt/ttutils/java/StatusBarUtil.java | 344 ++++++++++++++++++
.../main/res/layout-land/activity_main.xml | 1 +
.../main/res/layout-port/activity_main.xml | 1 +
app/src/main/res/values/colors.xml | 9 +-
app/src/main/res/values/styles.xml | 10 +
build.gradle | 2 +-
niceimageview/.gitignore | 1 +
niceimageview/build.gradle | 42 +++
niceimageview/proguard-rules.pro | 21 ++
niceimageview/src/main/AndroidManifest.xml | 2 +
.../java/com/shehuan/niv/NiceImageView.java | 338 +++++++++++++++++
.../src/main/java/com/shehuan/niv/Utils.java | 11 +
niceimageview/src/main/res/values/attrs.xml | 17 +
niceimageview/src/main/res/values/strings.xml | 3 +
settings.gradle | 4 +-
20 files changed, 892 insertions(+), 23 deletions(-)
create mode 100644 app/src/main/java/com/tt/base/ImmerseBaseActivity.java
create mode 100644 app/src/main/java/com/tt/ttutils/java/StatusBarUtil.java
create mode 100644 niceimageview/.gitignore
create mode 100644 niceimageview/build.gradle
create mode 100644 niceimageview/proguard-rules.pro
create mode 100644 niceimageview/src/main/AndroidManifest.xml
create mode 100644 niceimageview/src/main/java/com/shehuan/niv/NiceImageView.java
create mode 100644 niceimageview/src/main/java/com/shehuan/niv/Utils.java
create mode 100644 niceimageview/src/main/res/values/attrs.xml
create mode 100644 niceimageview/src/main/res/values/strings.xml
diff --git a/app/build.gradle b/app/build.gradle
index f02f316..42f23df 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -218,17 +218,20 @@ android {
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation project(':viewlibrary')
+ implementation project(path: ':niceimageview')
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.6.0'
implementation 'androidx.appcompat:appcompat:1.3.1'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
//constraintlayout:2.0.4以上在Android studio 3.6.2不能预览
-// implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
- implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
+ implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
+// implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
+ implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation 'androidx.preference:preference:1.1.1'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation "androidx.security:security-crypto:1.1.0-alpha03"
+ implementation 'androidx.multidex:multidex:2.0.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
@@ -246,17 +249,19 @@ dependencies {
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
- //Gson
+ //Google
implementation 'com.google.code.gson:gson:2.8.6'
+ implementation 'com.google.zxing:core:3.3.0'
+ implementation 'com.google.android.material:material:1.4.0'
//Jackson
implementation 'org.codehaus.jackson:jackson-mapper-asl:1.9.13'
implementation 'org.codehaus.jackson:jackson-core-asl:1.9.13'
//view绑定
- implementation 'com.jakewharton:butterknife:10.1.0'
- annotationProcessor 'com.jakewharton:butterknife-compiler:10.1.0'
- //二维码
- implementation 'com.google.zxing:core:3.3.0'
- implementation 'com.google.android.material:material:1.4.0'
+ implementation 'com.jakewharton:butterknife:10.2.1'
+// If you are using Kotlin, replace annotationProcessor with kapt.
+// annotationProcessor rootProject.ext.dependencies["butterknife-compiler"]
+ annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.1'
+
//MMKV
implementation 'com.tencent:mmkv-static:1.2.10'
//内存泄漏检测
@@ -300,4 +305,6 @@ dependencies {
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
// kotlin扩展(可选)
implementation 'com.gyf.immersionbar:immersionbar-ktx:3.0.0'
+ //网络监听
+ implementation 'com.github.tianma8023:NetDetector:v0.2.0'
}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index b75e851..312d54c 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -44,8 +44,8 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
- android:theme="@style/AppTheme">
-
+ android:theme="@style/ImmerseTheme">
+
diff --git a/app/src/main/java/com/tt/activity/JMainActivity.java b/app/src/main/java/com/tt/activity/JMainActivity.java
index f1b594a..b64b0d2 100644
--- a/app/src/main/java/com/tt/activity/JMainActivity.java
+++ b/app/src/main/java/com/tt/activity/JMainActivity.java
@@ -24,6 +24,7 @@ import com.info.sn.IGetInfoInterface;
import com.jiaoguanyi.appstore.IGetLicenseInterface;
import com.notepad.uiui.INoteAidlInterface;
import com.tt.base.BaseActivity;
+import com.tt.base.ImmerseBaseActivity;
import com.tt.ttutils.R;
import com.tt.ttutils.java.ApkUtils;
import com.tt.ttutils.java.ToastUtil;
@@ -35,7 +36,7 @@ import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
-public class JMainActivity extends BaseActivity {
+public class JMainActivity extends ImmerseBaseActivity {
@BindView(R.id.textView)
TextView textView;
@BindView(R.id.button)
@@ -49,13 +50,14 @@ public class JMainActivity extends BaseActivity {
private IGetInfoInterface getInfoInterface;
private String TAG = JMainActivity.class.getSimpleName();
+
@Override
- protected int setLayoutResourceID() {
+ public int getLayoutId() {
return R.layout.activity_main;
}
@Override
- protected void initView() {
+ public void initView() {
ButterKnife.bind(this);
View decorView = getWindow().getDecorView();
@@ -63,13 +65,18 @@ public class JMainActivity extends BaseActivity {
// SYSTEM_UI_FLAG_FULLSCREEN is only available on Android 4.1 and higher, but as
// a general rule, you should design your app to hide the status bar whenever you
// hide the navigation bar.
- int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION //导航栏
- | View.SYSTEM_UI_FLAG_FULLSCREEN;//全屏
- decorView.setSystemUiVisibility(uiOptions);
+// int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION //导航栏
+// | View.SYSTEM_UI_FLAG_FULLSCREEN;//全屏
+// decorView.setSystemUiVisibility(uiOptions);
}
@Override
- protected void initData() {
+ public void setListener() {
+
+ }
+
+ @Override
+ public void initData() {
registHideAppReceiver();
registForbidAppReceiver();
registerUserInfoReceiver();
diff --git a/app/src/main/java/com/tt/base/ImmerseBaseActivity.java b/app/src/main/java/com/tt/base/ImmerseBaseActivity.java
new file mode 100644
index 0000000..04f7bbd
--- /dev/null
+++ b/app/src/main/java/com/tt/base/ImmerseBaseActivity.java
@@ -0,0 +1,53 @@
+package com.tt.base;
+
+import android.os.Bundle;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+
+import com.tt.ttutils.R;
+import com.zackratos.ultimatebarx.ultimatebarx.java.UltimateBarX;
+
+public abstract class ImmerseBaseActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+// StatusBarUtil.init(this);
+ UltimateBarX.statusBar(this)
+ .transparent()
+ .colorRes(R.color.colorPrimaryDark)
+ .light(true)
+ .apply();
+ UltimateBarX.navigationBar(this)
+ .transparent()
+ .colorRes(R.color.colorPrimaryDark)
+ .light(true)
+ .apply();
+ //状态栏改变放在setContentView前后有所不同
+ setContentView(this.getLayoutId());
+ initView();
+ setListener();
+ initData();
+ }
+
+ /**
+ * 设置布局
+ */
+ public abstract int getLayoutId();
+
+ /**
+ * 初始化视图
+ */
+ public abstract void initView();
+
+ /**
+ *
+ */
+ public abstract void setListener();
+
+ /**
+ * 初始化数据
+ */
+ public abstract void initData();
+}
diff --git a/app/src/main/java/com/tt/base/JMyApplication.java b/app/src/main/java/com/tt/base/JMyApplication.java
index ba30f39..1bab3b3 100644
--- a/app/src/main/java/com/tt/base/JMyApplication.java
+++ b/app/src/main/java/com/tt/base/JMyApplication.java
@@ -41,5 +41,13 @@ public class JMyApplication extends Application {
});
}
+ @Override
+ public void onLowMemory() {
+ super.onLowMemory();
+ }
+ @Override
+ public void onTrimMemory(int level) {
+ super.onTrimMemory(level);
+ }
}
diff --git a/app/src/main/java/com/tt/ttutils/java/StatusBarUtil.java b/app/src/main/java/com/tt/ttutils/java/StatusBarUtil.java
new file mode 100644
index 0000000..3fca479
--- /dev/null
+++ b/app/src/main/java/com/tt/ttutils/java/StatusBarUtil.java
@@ -0,0 +1,344 @@
+package com.tt.ttutils.java;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.os.Build;
+import android.os.Environment;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Properties;
+
+public class StatusBarUtil {
+ public static int screenWidth;
+ public static int screenHeight;
+ public static int navigationHeight = 0;
+
+ private static DisplayMetrics mMetrics;
+ public static final String HOME_CURRENT_TAB_POSITION = "HOME_CURRENT_TAB_POSITION";
+
+ public static final String SYS_EMUI = "sys_emui";
+ public static final String SYS_MIUI = "sys_miui";
+ public static final String SYS_FLYME = "sys_flyme";
+ private static final String KEY_MIUI_VERSION_CODE = "ro.miui.ui.version.code";
+ private static final String KEY_MIUI_VERSION_NAME = "ro.miui.ui.version.name";
+ private static final String KEY_MIUI_INTERNAL_STORAGE = "ro.miui.internal.storage";
+ private static final String KEY_EMUI_API_LEVEL = "ro.build.hw_emui_api_level";
+ private static final String KEY_EMUI_VERSION = "ro.build.version.emui";
+ private static final String KEY_EMUI_CONFIG_HW_SYS_VERSION = "ro.confg.hw_systemversion";
+
+ public static void init(Activity activity) {
+ ViewGroup contentLayout = activity.getWindow().getDecorView().findViewById(Window.ID_ANDROID_CONTENT);
+ StatusBarUtil.setStatusBar(activity, false, true);
+ StatusBarUtil.setStatusTextColor(true, activity);
+ StatusBarUtil.setStatusBarPadding(activity, contentLayout);
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ activity.getWindow().setStatusBarColor(activity.getResources().getColor(android.R.color.transparent));
+ }
+ }
+
+ /**
+ * 通过反射的方式获取状态栏高度
+ *
+ * @return
+ */
+ public static int getStatusBarHeight(Context context) {
+ try {
+ Class> c = Class.forName("com.android.internal.R$dimen");
+ Object obj = c.newInstance();
+ Field field = c.getField("status_bar_height");
+ int x = Integer.parseInt(field.get(obj).toString());
+ return context.getResources().getDimensionPixelSize(x);
+ } catch (Exception e) {
+ }
+ return 0;
+ }
+
+ /**
+ * 获取底部导航栏高度
+ *
+ * @return
+ */
+ public static int getNavigationBarHeight(Context context) {
+ Resources resources = context.getResources();
+ int resourceId = resources.getIdentifier("navigation_bar_height", "dimen", "android");
+ //获取NavigationBar的高度
+ navigationHeight = resources.getDimensionPixelSize(resourceId);
+ return navigationHeight;
+ }
+
+ //获取是否存在NavigationBar
+ public static boolean checkDeviceHasNavigationBar(Context context) {
+ boolean hasNavigationBar = false;
+ Resources rs = context.getResources();
+ int id = rs.getIdentifier("config_showNavigationBar", "bool", "android");
+ if (id > 0) {
+ hasNavigationBar = rs.getBoolean(id);
+ }
+ try {
+ Class systemPropertiesClass = Class.forName("android.os.SystemProperties");
+ Method m = systemPropertiesClass.getMethod("get", String.class);
+ String navBarOverride = (String) m.invoke(systemPropertiesClass, "qemu.hw.mainkeys");
+ if ("1".equals(navBarOverride)) {
+ hasNavigationBar = false;
+ } else if ("0".equals(navBarOverride)) {
+ hasNavigationBar = true;
+ }
+ } catch (Exception e) {
+
+ }
+ return hasNavigationBar;
+
+ }
+
+ /**
+ * @param activity
+ * @param useThemestatusBarColor 是否要状态栏的颜色,不设置则为透明色
+ * @param withoutUseStatusBarColor 是否不需要使用状态栏为暗色调
+ */
+ public static void setStatusBar(Activity activity, boolean useThemestatusBarColor, boolean withoutUseStatusBarColor) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {//5.0及以上
+ View decorView = activity.getWindow().getDecorView();
+ int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
+ decorView.setSystemUiVisibility(option);
+ if (useThemestatusBarColor) {
+ activity.getWindow().setStatusBarColor(activity.getResources().getColor(android.R.color.white));
+ } else {
+ activity.getWindow().setStatusBarColor(Color.TRANSPARENT);
+ }
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {//4.4到5.0
+ WindowManager.LayoutParams localLayoutParams = activity.getWindow().getAttributes();
+ localLayoutParams.flags = (WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | localLayoutParams.flags);
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !withoutUseStatusBarColor) {
+ activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+ }
+ }
+
+ public static void reMeasure(Activity activity) {
+ Display display = activity.getWindowManager().getDefaultDisplay();
+ mMetrics = new DisplayMetrics();
+
+ if (Build.VERSION.SDK_INT >= 17) {
+ display.getRealMetrics(mMetrics);
+ } else {
+ display.getMetrics(mMetrics);
+ }
+
+ screenWidth = mMetrics.widthPixels;
+ screenHeight = mMetrics.heightPixels;
+ }
+
+ /**
+ * 改变魅族的状态栏字体为黑色,要求FlyMe4以上
+ */
+ private static void processFlyMe(boolean isLightStatusBar, Activity activity) {
+ WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
+ try {
+ Class> instance = Class.forName("android.view.WindowManager$LayoutParams");
+ int value = instance.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON").getInt(lp);
+ Field field = instance.getDeclaredField("meizuFlags");
+ field.setAccessible(true);
+ int origin = field.getInt(lp);
+ if (isLightStatusBar) {
+ field.set(lp, origin | value);
+ } else {
+ field.set(lp, (~value) & origin);
+ }
+ } catch (Exception e) {
+ }
+ }
+
+ /**
+ * 改变小米的状态栏字体颜色为黑色, 要求MIUI6以上 lightStatusBar为真时表示黑色字体
+ */
+ private static void processMIUI(boolean lightStatusBar, Activity activity) {
+ Class extends Window> clazz = activity.getWindow().getClass();
+ try {
+ int darkModeFlag;
+ Class> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
+ Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
+ darkModeFlag = field.getInt(layoutParams);
+ Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class);
+ extraFlagField.invoke(activity.getWindow(), lightStatusBar ? darkModeFlag : 0, darkModeFlag);
+ } catch (Exception e) {
+ }
+ }
+
+ /**
+ * 设置OPPO手机状态栏字体为黑色(colorOS3.0,6.0以下部分手机)
+ *
+ * @param lightStatusBar
+ * @param activity
+ */
+ private static final int SYSTEM_UI_FLAG_OP_STATUS_BAR_TINT = 0x00000010;
+
+ private static void setOPPOStatusTextColor(boolean lightStatusBar, Activity activity) {
+ Window window = activity.getWindow();
+ window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+ int vis = window.getDecorView().getSystemUiVisibility();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (lightStatusBar) {
+ vis |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+ } else {
+ vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+ }
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ if (lightStatusBar) {
+ vis |= SYSTEM_UI_FLAG_OP_STATUS_BAR_TINT;
+ } else {
+ vis &= ~SYSTEM_UI_FLAG_OP_STATUS_BAR_TINT;
+ }
+ }
+ window.getDecorView().setSystemUiVisibility(vis);
+ }
+
+
+ /**
+ * 判断手机是否是小米
+ *
+ * @return
+ */
+ public static boolean isMIUI() {
+ return SYS_MIUI.equals(getSystem());
+ }
+
+ /**
+ * 判断手机是否是魅族
+ *
+ * @return
+ */
+ public static boolean isFlyme() {
+ try {
+ // Invoke Build.hasSmartBar()
+ final Method method = Build.class.getMethod("hasSmartBar");
+ return method != null;
+ } catch (final Exception e) {
+ return false;
+ }
+ }
+
+ /**
+ * 设置状态栏文字色值为深色调
+ *
+ * @param useDart 是否使用深色调
+ * @param activity
+ */
+ public static void setStatusTextColor(boolean useDart, Activity activity) {
+ if (isFlyme()) {
+ processFlyMe(useDart, activity);
+ } else if (isMIUI()) {
+ processMIUI(useDart, activity);
+ } else if (Build.MANUFACTURER.equalsIgnoreCase("OPPO")) {
+ //OPPO
+ setOPPOStatusTextColor(useDart, activity);
+ } else {
+ if (useDart) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+ }
+ } else {
+ activity.getWindow().getDecorView().setSystemUiVisibility(
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
+ }
+ activity.getWindow().getDecorView().findViewById(android.R.id.content).setPadding(0, 0, 0, navigationHeight);
+ }
+ }
+
+ /**
+ * 作者:Loyea
+ * 链接:https://www.jianshu.com/p/abd021c22728
+ * 來源:简书
+ * 简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
+ */
+ public static void setAndroidNativeLightStatusBar(Activity activity, boolean dark) {
+ View decor = activity.getWindow().getDecorView();
+ if (dark) {
+ decor.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+ } else {
+ // We want to change tint color to white again.
+ // You can also record the flags in advance so that you can turn UI back completely if
+ // you have set other flags before, such as translucent or full screen.
+ decor.setSystemUiVisibility(0);
+ }
+ }
+
+ public static String getSystem() {
+ String SYS = "";
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) {
+ if (!TextUtils.isEmpty(getSystemProperty(KEY_MIUI_VERSION_CODE, ""))
+ || !TextUtils.isEmpty(getSystemProperty(KEY_MIUI_VERSION_NAME, ""))
+ || !TextUtils.isEmpty(getSystemProperty(KEY_MIUI_INTERNAL_STORAGE, ""))) {
+ SYS = SYS_MIUI;//小米
+ } else if (!TextUtils.isEmpty(getSystemProperty(KEY_EMUI_API_LEVEL, ""))
+ || !TextUtils.isEmpty(getSystemProperty(KEY_EMUI_VERSION, ""))
+ || !TextUtils.isEmpty(getSystemProperty(KEY_EMUI_CONFIG_HW_SYS_VERSION, ""))) {
+ SYS = SYS_EMUI;//华为
+ } else if (getMeizuFlymeOSFlag().toLowerCase().contains("flyme")) {
+ SYS = SYS_FLYME;//魅族
+ }
+ return SYS;
+ } else {
+ try {
+ Properties prop = new Properties();
+ prop.load(new FileInputStream(new File(Environment.getRootDirectory(), "build.prop")));
+ if (prop.getProperty(KEY_MIUI_VERSION_CODE, null) != null
+ || prop.getProperty(KEY_MIUI_VERSION_NAME, null) != null
+ || prop.getProperty(KEY_MIUI_INTERNAL_STORAGE, null) != null) {
+ SYS = SYS_MIUI;//小米
+ } else if (prop.getProperty(KEY_EMUI_API_LEVEL, null) != null
+ || prop.getProperty(KEY_EMUI_VERSION, null) != null
+ || prop.getProperty(KEY_EMUI_CONFIG_HW_SYS_VERSION, null) != null) {
+ SYS = SYS_EMUI;//华为
+ } else if (getMeizuFlymeOSFlag().toLowerCase().contains("flyme")) {
+ SYS = SYS_FLYME;//魅族
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ return SYS;
+ } finally {
+ return SYS;
+ }
+ }
+ }
+
+ private static String getSystemProperty(String key, String defaultValue) {
+ try {
+ Class> clz = Class.forName("android.os.SystemProperties");
+ Method get = clz.getMethod("get", String.class, String.class);
+ return (String) get.invoke(clz, key, defaultValue);
+ } catch (Exception e) {
+ }
+ return defaultValue;
+ }
+
+ public static String getMeizuFlymeOSFlag() {
+ return getSystemProperty("ro.build.display.id", "");
+ }
+
+ /**
+ * 全屏模式下 针对刘海屏向下移动view
+ *
+ * @param context
+ * @param view 需要设置padding的view
+ */
+ public static void setStatusBarPadding(Context context, View view) {
+ if (view != null) {
+ view.setPadding(0, getStatusBarHeight(context), 0, 0);
+ }
+ }
+}
diff --git a/app/src/main/res/layout-land/activity_main.xml b/app/src/main/res/layout-land/activity_main.xml
index 9b2e58a..24982db 100644
--- a/app/src/main/res/layout-land/activity_main.xml
+++ b/app/src/main/res/layout-land/activity_main.xml
@@ -4,6 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:fitsSystemWindows="true"
tools:context="com.tt.activity.JMainActivity">
- #6200EE
- #3700B3
- #03DAC5
+ #FFFFFF
+ #FFFFFF
+ #FFFFFF
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index fac9291..8c47132 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -7,4 +7,14 @@
- @color/colorAccent
+
+
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 0b103e4..e17269d 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,6 +1,6 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
- ext.kotlin_version = "1.3.72"
+ ext.kotlin_version = "1.4.10"
repositories {
google()
jcenter()
diff --git a/niceimageview/.gitignore b/niceimageview/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/niceimageview/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/niceimageview/build.gradle b/niceimageview/build.gradle
new file mode 100644
index 0000000..381745a
--- /dev/null
+++ b/niceimageview/build.gradle
@@ -0,0 +1,42 @@
+apply plugin: 'com.android.library'
+
+android {
+ compileSdkVersion 28
+
+ defaultConfig {
+ minSdkVersion 14
+ targetSdkVersion 28
+ versionCode 1
+ versionName "1.0"
+ }
+
+ buildTypes {
+ zhanRuiRelease {
+
+ }
+
+ zhanRuiDebug {
+
+ }
+
+ zhanRuiUserdebug {
+
+ }
+
+ debug {
+
+ }
+
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+
+}
+
+dependencies {
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
+
+ implementation 'com.android.support:appcompat-v7:28.0.0'
+}
diff --git a/niceimageview/proguard-rules.pro b/niceimageview/proguard-rules.pro
new file mode 100644
index 0000000..f1b4245
--- /dev/null
+++ b/niceimageview/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
diff --git a/niceimageview/src/main/AndroidManifest.xml b/niceimageview/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..6dab987
--- /dev/null
+++ b/niceimageview/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
diff --git a/niceimageview/src/main/java/com/shehuan/niv/NiceImageView.java b/niceimageview/src/main/java/com/shehuan/niv/NiceImageView.java
new file mode 100644
index 0000000..2d31326
--- /dev/null
+++ b/niceimageview/src/main/java/com/shehuan/niv/NiceImageView.java
@@ -0,0 +1,338 @@
+package com.shehuan.niv;
+
+
+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.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.RectF;
+import android.graphics.Xfermode;
+import android.os.Build;
+import android.util.AttributeSet;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.Nullable;
+import androidx.appcompat.widget.AppCompatImageView;
+
+public class NiceImageView extends AppCompatImageView {
+ private Context context;
+
+ private boolean isCircle; // 是否显示为圆形,如果为圆形则设置的corner无效
+ private boolean isCoverSrc; // border、inner_border是否覆盖图片
+ private int borderWidth; // 边框宽度
+ private int borderColor = Color.WHITE; // 边框颜色
+ private int innerBorderWidth; // 内层边框宽度
+ private int innerBorderColor = Color.WHITE; // 内层边框充色
+
+ private int cornerRadius; // 统一设置圆角半径,优先级高于单独设置每个角的半径
+ private int cornerTopLeftRadius; // 左上角圆角半径
+ private int cornerTopRightRadius; // 右上角圆角半径
+ private int cornerBottomLeftRadius; // 左下角圆角半径
+ private int cornerBottomRightRadius; // 右下角圆角半径
+
+ private int maskColor; // 遮罩颜色
+
+ private Xfermode xfermode;
+
+ private int width;
+ private int height;
+ private float radius;
+
+ private float[] borderRadii;
+ private float[] srcRadii;
+
+ private RectF srcRectF; // 图片占的矩形区域
+ private RectF borderRectF; // 边框的矩形区域
+
+ private Paint paint;
+ private Path path; // 用来裁剪图片的ptah
+ private Path srcPath; // 图片区域大小的path
+
+ public NiceImageView(Context context) {
+ this(context, null);
+ }
+
+ public NiceImageView(Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public NiceImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+
+ this.context = context;
+
+ TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.NiceImageView, 0, 0);
+ for (int i = 0; i < ta.getIndexCount(); i++) {
+ int attr = ta.getIndex(i);
+ if (attr == R.styleable.NiceImageView_is_cover_src) {
+ isCoverSrc = ta.getBoolean(attr, isCoverSrc);
+ } else if (attr == R.styleable.NiceImageView_is_circle) {
+ isCircle = ta.getBoolean(attr, isCircle);
+ } else if (attr == R.styleable.NiceImageView_border_width) {
+ borderWidth = ta.getDimensionPixelSize(attr, borderWidth);
+ } else if (attr == R.styleable.NiceImageView_border_color) {
+ borderColor = ta.getColor(attr, borderColor);
+ } else if (attr == R.styleable.NiceImageView_inner_border_width) {
+ innerBorderWidth = ta.getDimensionPixelSize(attr, innerBorderWidth);
+ } else if (attr == R.styleable.NiceImageView_inner_border_color) {
+ innerBorderColor = ta.getColor(attr, innerBorderColor);
+ } else if (attr == R.styleable.NiceImageView_corner_radius) {
+ cornerRadius = ta.getDimensionPixelSize(attr, cornerRadius);
+ } else if (attr == R.styleable.NiceImageView_corner_top_left_radius) {
+ cornerTopLeftRadius = ta.getDimensionPixelSize(attr, cornerTopLeftRadius);
+ } else if (attr == R.styleable.NiceImageView_corner_top_right_radius) {
+ cornerTopRightRadius = ta.getDimensionPixelSize(attr, cornerTopRightRadius);
+ } else if (attr == R.styleable.NiceImageView_corner_bottom_left_radius) {
+ cornerBottomLeftRadius = ta.getDimensionPixelSize(attr, cornerBottomLeftRadius);
+ } else if (attr == R.styleable.NiceImageView_corner_bottom_right_radius) {
+ cornerBottomRightRadius = ta.getDimensionPixelSize(attr, cornerBottomRightRadius);
+ } else if (attr == R.styleable.NiceImageView_mask_color) {
+ maskColor = ta.getColor(attr, maskColor);
+ }
+ }
+ ta.recycle();
+
+ borderRadii = new float[8];
+ srcRadii = new float[8];
+
+ borderRectF = new RectF();
+ srcRectF = new RectF();
+
+ paint = new Paint();
+ path = new Path();
+
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) {
+ xfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
+ } else {
+ xfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
+ srcPath = new Path();
+ }
+
+ calculateRadii();
+ clearInnerBorderWidth();
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+ width = w;
+ height = h;
+
+ initBorderRectF();
+ initSrcRectF();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ // 使用图形混合模式来显示指定区域的图片
+ canvas.saveLayer(srcRectF, null, Canvas.ALL_SAVE_FLAG);
+ if (!isCoverSrc) {
+ float sx = 1.0f * (width - 2 * borderWidth - 2 * innerBorderWidth) / width;
+ float sy = 1.0f * (height - 2 * borderWidth - 2 * innerBorderWidth) / height;
+ // 缩小画布,使图片内容不被borders覆盖
+ canvas.scale(sx, sy, width / 2.0f, height / 2.0f);
+ }
+ super.onDraw(canvas);
+ paint.reset();
+ path.reset();
+ if (isCircle) {
+ path.addCircle(width / 2.0f, height / 2.0f, radius, Path.Direction.CCW);
+ } else {
+ path.addRoundRect(srcRectF, srcRadii, Path.Direction.CCW);
+ }
+
+ paint.setAntiAlias(true);
+ paint.setStyle(Paint.Style.FILL);
+ paint.setXfermode(xfermode);
+ //9.0及以上系统图片一次圆一次方的解决办法
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) {
+ canvas.drawPath(path, paint);
+ } else {
+ srcPath.addRect(srcRectF, Path.Direction.CCW);
+ // 计算tempPath和path的差集
+ srcPath.op(path, Path.Op.DIFFERENCE);
+ canvas.drawPath(srcPath, paint);
+ srcPath.reset();//1
+ }
+ paint.setXfermode(null);
+
+ // 绘制遮罩
+ if (maskColor != 0) {
+ paint.setColor(maskColor);
+ canvas.drawPath(path, paint);
+ }
+ // 恢复画布
+ canvas.restore();
+ // 绘制边框
+ drawBorders(canvas);
+ }
+
+ private void drawBorders(Canvas canvas) {
+ if (isCircle) {
+ if (borderWidth > 0) {
+ drawCircleBorder(canvas, borderWidth, borderColor, radius - borderWidth / 2.0f);
+ }
+ if (innerBorderWidth > 0) {
+ drawCircleBorder(canvas, innerBorderWidth, innerBorderColor, radius - borderWidth - innerBorderWidth / 2.0f);
+ }
+ } else {
+ if (borderWidth > 0) {
+ drawRectFBorder(canvas, borderWidth, borderColor, borderRectF, borderRadii);
+ }
+ }
+ }
+
+ private void drawCircleBorder(Canvas canvas, int borderWidth, int borderColor, float radius) {
+ initBorderPaint(borderWidth, borderColor);
+ path.addCircle(width / 2.0f, height / 2.0f, radius, Path.Direction.CCW);
+ canvas.drawPath(path, paint);
+ }
+
+ private void drawRectFBorder(Canvas canvas, int borderWidth, int borderColor, RectF rectF, float[] radii) {
+ initBorderPaint(borderWidth, borderColor);
+ path.addRoundRect(rectF, radii, Path.Direction.CCW);
+ canvas.drawPath(path, paint);
+ }
+
+ private void initBorderPaint(int borderWidth, int borderColor) {
+ path.reset();
+ paint.setStrokeWidth(borderWidth);
+ paint.setColor(borderColor);
+ paint.setStyle(Paint.Style.STROKE);
+ }
+
+ /**
+ * 计算外边框的RectF
+ */
+ private void initBorderRectF() {
+ if (!isCircle) {
+ borderRectF.set(borderWidth / 2.0f, borderWidth / 2.0f, width - borderWidth / 2.0f, height - borderWidth / 2.0f);
+ }
+ }
+
+ /**
+ * 计算图片原始区域的RectF
+ */
+ private void initSrcRectF() {
+ if (isCircle) {
+ radius = Math.min(width, height) / 2.0f;
+ srcRectF.set(width / 2.0f - radius, height / 2.0f - radius, width / 2.0f + radius, height / 2.0f + radius);
+ } else {
+ srcRectF.set(0, 0, width, height);
+ if (isCoverSrc) {
+ srcRectF = borderRectF;
+ }
+ }
+ }
+
+ /**
+ * 计算RectF的圆角半径
+ */
+ private void calculateRadii() {
+ if (isCircle) {
+ return;
+ }
+ if (cornerRadius > 0) {
+ for (int i = 0; i < borderRadii.length; i++) {
+ borderRadii[i] = cornerRadius;
+ srcRadii[i] = cornerRadius - borderWidth / 2.0f;
+ }
+ } else {
+ borderRadii[0] = borderRadii[1] = cornerTopLeftRadius;
+ borderRadii[2] = borderRadii[3] = cornerTopRightRadius;
+ borderRadii[4] = borderRadii[5] = cornerBottomRightRadius;
+ borderRadii[6] = borderRadii[7] = cornerBottomLeftRadius;
+
+ srcRadii[0] = srcRadii[1] = cornerTopLeftRadius - borderWidth / 2.0f;
+ srcRadii[2] = srcRadii[3] = cornerTopRightRadius - borderWidth / 2.0f;
+ srcRadii[4] = srcRadii[5] = cornerBottomRightRadius - borderWidth / 2.0f;
+ srcRadii[6] = srcRadii[7] = cornerBottomLeftRadius - borderWidth / 2.0f;
+ }
+ }
+
+ private void calculateRadiiAndRectF(boolean reset) {
+ if (reset) {
+ cornerRadius = 0;
+ }
+ calculateRadii();
+ initBorderRectF();
+ invalidate();
+ }
+
+ /**
+ * 目前圆角矩形情况下不支持inner_border,需要将其置0
+ */
+ private void clearInnerBorderWidth() {
+ if (!isCircle) {
+ this.innerBorderWidth = 0;
+ }
+ }
+
+ public void isCoverSrc(boolean isCoverSrc) {
+ this.isCoverSrc = isCoverSrc;
+ initSrcRectF();
+ invalidate();
+ }
+
+ public void isCircle(boolean isCircle) {
+ this.isCircle = isCircle;
+ clearInnerBorderWidth();
+ initSrcRectF();
+ invalidate();
+ }
+
+ public void setBorderWidth(int borderWidth) {
+ this.borderWidth = Utils.dp2px(context, borderWidth);
+ calculateRadiiAndRectF(false);
+ }
+
+ public void setBorderColor(@ColorInt int borderColor) {
+ this.borderColor = borderColor;
+ invalidate();
+ }
+
+ public void setInnerBorderWidth(int innerBorderWidth) {
+ this.innerBorderWidth = Utils.dp2px(context, innerBorderWidth);
+ clearInnerBorderWidth();
+ invalidate();
+ }
+
+ public void setInnerBorderColor(@ColorInt int innerBorderColor) {
+ this.innerBorderColor = innerBorderColor;
+ invalidate();
+ }
+
+ public void setCornerRadius(int cornerRadius) {
+ this.cornerRadius = Utils.dp2px(context, cornerRadius);
+ calculateRadiiAndRectF(false);
+ }
+
+ public void setCornerTopLeftRadius(int cornerTopLeftRadius) {
+ this.cornerTopLeftRadius = Utils.dp2px(context, cornerTopLeftRadius);
+ calculateRadiiAndRectF(true);
+ }
+
+ public void setCornerTopRightRadius(int cornerTopRightRadius) {
+ this.cornerTopRightRadius = Utils.dp2px(context, cornerTopRightRadius);
+ calculateRadiiAndRectF(true);
+ }
+
+ public void setCornerBottomLeftRadius(int cornerBottomLeftRadius) {
+ this.cornerBottomLeftRadius = Utils.dp2px(context, cornerBottomLeftRadius);
+ calculateRadiiAndRectF(true);
+ }
+
+ public void setCornerBottomRightRadius(int cornerBottomRightRadius) {
+ this.cornerBottomRightRadius = Utils.dp2px(context, cornerBottomRightRadius);
+ calculateRadiiAndRectF(true);
+ }
+
+ public void setMaskColor(@ColorInt int maskColor) {
+ this.maskColor = maskColor;
+ invalidate();
+ }
+}
diff --git a/niceimageview/src/main/java/com/shehuan/niv/Utils.java b/niceimageview/src/main/java/com/shehuan/niv/Utils.java
new file mode 100644
index 0000000..f9958ad
--- /dev/null
+++ b/niceimageview/src/main/java/com/shehuan/niv/Utils.java
@@ -0,0 +1,11 @@
+package com.shehuan.niv;
+
+
+import android.content.Context;
+
+public class Utils {
+ public static int dp2px(Context context, float dipValue) {
+ final float scale = context.getResources().getDisplayMetrics().density;
+ return (int) (dipValue * scale + 0.5f);
+ }
+}
diff --git a/niceimageview/src/main/res/values/attrs.xml b/niceimageview/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..c7c51cd
--- /dev/null
+++ b/niceimageview/src/main/res/values/attrs.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/niceimageview/src/main/res/values/strings.xml b/niceimageview/src/main/res/values/strings.xml
new file mode 100644
index 0000000..1a1d942
--- /dev/null
+++ b/niceimageview/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ niceimageview
+
diff --git a/settings.gradle b/settings.gradle
index f900a8b..9c18986 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,3 +1,3 @@
-include ':app'
+include ':app',':viewlibrary',':niceimageview'
rootProject.name = "TTUtils"
-include ':viewlibrary'
+