date:2021-10-11 20:21:37
This commit is contained in:
@@ -218,17 +218,20 @@ android {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: "libs", include: ["*.jar"])
|
implementation fileTree(dir: "libs", include: ["*.jar"])
|
||||||
implementation project(':viewlibrary')
|
implementation project(':viewlibrary')
|
||||||
|
implementation project(path: ':niceimageview')
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||||
implementation 'androidx.core:core-ktx:1.6.0'
|
implementation 'androidx.core:core-ktx:1.6.0'
|
||||||
implementation 'androidx.appcompat:appcompat:1.3.1'
|
implementation 'androidx.appcompat:appcompat:1.3.1'
|
||||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||||
//constraintlayout:2.0.4以上在Android studio 3.6.2不能预览
|
//constraintlayout:2.0.4以上在Android studio 3.6.2不能预览
|
||||||
// implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
|
// implementation 'androidx.constraintlayout:constraintlayout:2.1.1'
|
||||||
|
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
||||||
implementation 'androidx.preference:preference:1.1.1'
|
implementation 'androidx.preference:preference:1.1.1'
|
||||||
implementation 'androidx.cardview:cardview:1.0.0'
|
implementation 'androidx.cardview:cardview:1.0.0'
|
||||||
implementation 'androidx.recyclerview:recyclerview:1.2.1'
|
implementation 'androidx.recyclerview:recyclerview:1.2.1'
|
||||||
implementation "androidx.security:security-crypto:1.1.0-alpha03"
|
implementation "androidx.security:security-crypto:1.1.0-alpha03"
|
||||||
|
implementation 'androidx.multidex:multidex:2.0.1'
|
||||||
|
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
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:retrofit:2.3.0'
|
||||||
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
|
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
|
||||||
implementation 'com.squareup.retrofit2:adapter-rxjava2: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.code.gson:gson:2.8.6'
|
||||||
|
implementation 'com.google.zxing:core:3.3.0'
|
||||||
|
implementation 'com.google.android.material:material:1.4.0'
|
||||||
//Jackson
|
//Jackson
|
||||||
implementation 'org.codehaus.jackson:jackson-mapper-asl:1.9.13'
|
implementation 'org.codehaus.jackson:jackson-mapper-asl:1.9.13'
|
||||||
implementation 'org.codehaus.jackson:jackson-core-asl:1.9.13'
|
implementation 'org.codehaus.jackson:jackson-core-asl:1.9.13'
|
||||||
//view绑定
|
//view绑定
|
||||||
implementation 'com.jakewharton:butterknife:10.1.0'
|
implementation 'com.jakewharton:butterknife:10.2.1'
|
||||||
annotationProcessor 'com.jakewharton:butterknife-compiler:10.1.0'
|
// If you are using Kotlin, replace annotationProcessor with kapt.
|
||||||
//二维码
|
// annotationProcessor rootProject.ext.dependencies["butterknife-compiler"]
|
||||||
implementation 'com.google.zxing:core:3.3.0'
|
annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.1'
|
||||||
implementation 'com.google.android.material:material:1.4.0'
|
|
||||||
//MMKV
|
//MMKV
|
||||||
implementation 'com.tencent:mmkv-static:1.2.10'
|
implementation 'com.tencent:mmkv-static:1.2.10'
|
||||||
//内存泄漏检测
|
//内存泄漏检测
|
||||||
@@ -300,4 +305,6 @@ dependencies {
|
|||||||
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
|
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
|
||||||
// kotlin扩展(可选)
|
// kotlin扩展(可选)
|
||||||
implementation 'com.gyf.immersionbar:immersionbar-ktx:3.0.0'
|
implementation 'com.gyf.immersionbar:immersionbar-ktx:3.0.0'
|
||||||
|
//网络监听
|
||||||
|
implementation 'com.github.tianma8023:NetDetector:v0.2.0'
|
||||||
}
|
}
|
||||||
@@ -44,8 +44,8 @@
|
|||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme">
|
android:theme="@style/ImmerseTheme">
|
||||||
<activity android:name="com.tt.activity.PackageActivity"></activity>
|
<activity android:name="com.tt.activity.PackageActivity" />
|
||||||
<activity android:name="com.tt.activity.JMainActivity">
|
<activity android:name="com.tt.activity.JMainActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import com.info.sn.IGetInfoInterface;
|
|||||||
import com.jiaoguanyi.appstore.IGetLicenseInterface;
|
import com.jiaoguanyi.appstore.IGetLicenseInterface;
|
||||||
import com.notepad.uiui.INoteAidlInterface;
|
import com.notepad.uiui.INoteAidlInterface;
|
||||||
import com.tt.base.BaseActivity;
|
import com.tt.base.BaseActivity;
|
||||||
|
import com.tt.base.ImmerseBaseActivity;
|
||||||
import com.tt.ttutils.R;
|
import com.tt.ttutils.R;
|
||||||
import com.tt.ttutils.java.ApkUtils;
|
import com.tt.ttutils.java.ApkUtils;
|
||||||
import com.tt.ttutils.java.ToastUtil;
|
import com.tt.ttutils.java.ToastUtil;
|
||||||
@@ -35,7 +36,7 @@ import java.util.List;
|
|||||||
import butterknife.BindView;
|
import butterknife.BindView;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
|
|
||||||
public class JMainActivity extends BaseActivity {
|
public class JMainActivity extends ImmerseBaseActivity {
|
||||||
@BindView(R.id.textView)
|
@BindView(R.id.textView)
|
||||||
TextView textView;
|
TextView textView;
|
||||||
@BindView(R.id.button)
|
@BindView(R.id.button)
|
||||||
@@ -49,13 +50,14 @@ public class JMainActivity extends BaseActivity {
|
|||||||
private IGetInfoInterface getInfoInterface;
|
private IGetInfoInterface getInfoInterface;
|
||||||
private String TAG = JMainActivity.class.getSimpleName();
|
private String TAG = JMainActivity.class.getSimpleName();
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int setLayoutResourceID() {
|
public int getLayoutId() {
|
||||||
return R.layout.activity_main;
|
return R.layout.activity_main;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initView() {
|
public void initView() {
|
||||||
ButterKnife.bind(this);
|
ButterKnife.bind(this);
|
||||||
|
|
||||||
View decorView = getWindow().getDecorView();
|
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
|
// 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
|
// a general rule, you should design your app to hide the status bar whenever you
|
||||||
// hide the navigation bar.
|
// hide the navigation bar.
|
||||||
int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION //导航栏
|
// int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION //导航栏
|
||||||
| View.SYSTEM_UI_FLAG_FULLSCREEN;//全屏
|
// | View.SYSTEM_UI_FLAG_FULLSCREEN;//全屏
|
||||||
decorView.setSystemUiVisibility(uiOptions);
|
// decorView.setSystemUiVisibility(uiOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initData() {
|
public void setListener() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initData() {
|
||||||
registHideAppReceiver();
|
registHideAppReceiver();
|
||||||
registForbidAppReceiver();
|
registForbidAppReceiver();
|
||||||
registerUserInfoReceiver();
|
registerUserInfoReceiver();
|
||||||
|
|||||||
53
app/src/main/java/com/tt/base/ImmerseBaseActivity.java
Normal file
53
app/src/main/java/com/tt/base/ImmerseBaseActivity.java
Normal file
@@ -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();
|
||||||
|
}
|
||||||
@@ -41,5 +41,13 @@ public class JMyApplication extends Application {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLowMemory() {
|
||||||
|
super.onLowMemory();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTrimMemory(int level) {
|
||||||
|
super.onTrimMemory(level);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
344
app/src/main/java/com/tt/ttutils/java/StatusBarUtil.java
Normal file
344
app/src/main/java/com/tt/ttutils/java/StatusBarUtil.java
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
tools:context="com.tt.activity.JMainActivity">
|
tools:context="com.tt.activity.JMainActivity">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:fitsSystemWindows="true"
|
||||||
tools:context="com.tt.activity.JMainActivity">
|
tools:context="com.tt.activity.JMainActivity">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<color name="colorPrimary">#6200EE</color>
|
<color name="colorPrimary">#FFFFFF</color>
|
||||||
<color name="colorPrimaryDark">#3700B3</color>
|
<color name="colorPrimaryDark">#FFFFFF</color>
|
||||||
<color name="colorAccent">#03DAC5</color>
|
<color name="colorAccent">#FFFFFF</color>
|
||||||
|
<!-- <color name="colorPrimary">#6200EE</color>-->
|
||||||
|
<!-- <color name="colorPrimaryDark">#3700B3</color>-->
|
||||||
|
<!-- <color name="colorAccent">#03DAC5</color>-->
|
||||||
</resources>
|
</resources>
|
||||||
@@ -7,4 +7,14 @@
|
|||||||
<item name="colorAccent">@color/colorAccent</item>
|
<item name="colorAccent">@color/colorAccent</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<!--沉浸状态栏需要此主题-->
|
||||||
|
<style name="ImmerseTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
||||||
|
<!-- Customize your theme here. -->
|
||||||
|
<item name="colorPrimary">@color/colorPrimary</item>
|
||||||
|
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||||
|
<item name="colorAccent">@color/colorAccent</item>
|
||||||
|
<item name="android:windowBackground">@color/colorPrimary</item>
|
||||||
|
<item name="android:fitsSystemWindows">true</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
buildscript {
|
buildscript {
|
||||||
ext.kotlin_version = "1.3.72"
|
ext.kotlin_version = "1.4.10"
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
jcenter()
|
jcenter()
|
||||||
|
|||||||
1
niceimageview/.gitignore
vendored
Normal file
1
niceimageview/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/build
|
||||||
42
niceimageview/build.gradle
Normal file
42
niceimageview/build.gradle
Normal file
@@ -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'
|
||||||
|
}
|
||||||
21
niceimageview/proguard-rules.pro
vendored
Normal file
21
niceimageview/proguard-rules.pro
vendored
Normal file
@@ -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
|
||||||
2
niceimageview/src/main/AndroidManifest.xml
Normal file
2
niceimageview/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="com.shehuan.niv" />
|
||||||
338
niceimageview/src/main/java/com/shehuan/niv/NiceImageView.java
Normal file
338
niceimageview/src/main/java/com/shehuan/niv/NiceImageView.java
Normal file
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
11
niceimageview/src/main/java/com/shehuan/niv/Utils.java
Normal file
11
niceimageview/src/main/java/com/shehuan/niv/Utils.java
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
17
niceimageview/src/main/res/values/attrs.xml
Normal file
17
niceimageview/src/main/res/values/attrs.xml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<declare-styleable name="NiceImageView">
|
||||||
|
<attr name="is_circle" format="boolean" />
|
||||||
|
<attr name="is_cover_src" format="boolean" />
|
||||||
|
<attr name="corner_radius" format="dimension" />
|
||||||
|
<attr name="corner_top_left_radius" format="dimension" />
|
||||||
|
<attr name="corner_top_right_radius" format="dimension" />
|
||||||
|
<attr name="corner_bottom_left_radius" format="dimension" />
|
||||||
|
<attr name="corner_bottom_right_radius" format="dimension" />
|
||||||
|
<attr name="border_width" format="dimension" />
|
||||||
|
<attr name="border_color" format="color" />
|
||||||
|
<attr name="inner_border_width" format="dimension" />
|
||||||
|
<attr name="inner_border_color" format="color" />
|
||||||
|
<attr name="mask_color" format="color" />
|
||||||
|
</declare-styleable>
|
||||||
|
</resources>
|
||||||
3
niceimageview/src/main/res/values/strings.xml
Normal file
3
niceimageview/src/main/res/values/strings.xml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<resources>
|
||||||
|
<string name="app_name">niceimageview</string>
|
||||||
|
</resources>
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
include ':app'
|
include ':app',':viewlibrary',':niceimageview'
|
||||||
rootProject.name = "TTUtils"
|
rootProject.name = "TTUtils"
|
||||||
include ':viewlibrary'
|
|
||||||
|
|||||||
Reference in New Issue
Block a user