parent
f1e3d4d735
commit
c9c1f80d72
61 changed files with 12660 additions and 4548 deletions
@ -0,0 +1,90 @@ |
||||
package com.project.survey.activity |
||||
|
||||
import android.text.method.HideReturnsTransformationMethod |
||||
import android.text.method.PasswordTransformationMethod |
||||
import android.view.View |
||||
import com.project.survey.R |
||||
import com.project.survey.activity.base.BaseBindingActivity |
||||
import com.project.survey.databinding.ActivityLoginBinding |
||||
import com.project.survey.util.Tools |
||||
|
||||
class LoginActivity : BaseBindingActivity<ActivityLoginBinding>() { |
||||
|
||||
private var isOutLogin = false//默认集团登录 |
||||
|
||||
override fun getBinding(): ActivityLoginBinding { |
||||
return ActivityLoginBinding.inflate(layoutInflater) |
||||
} |
||||
|
||||
override fun initView() { |
||||
mBinding.pwdShowHide.setOnClickListener { |
||||
mBinding.ivPwdShowHide.isSelected = !mBinding.ivPwdShowHide.isSelected |
||||
if (mBinding.ivPwdShowHide.isSelected) { |
||||
mBinding.etPwd.transformationMethod = HideReturnsTransformationMethod.getInstance() |
||||
} else { |
||||
mBinding.etPwd.transformationMethod = PasswordTransformationMethod.getInstance() |
||||
} |
||||
mBinding.etPwd.setSelection(mBinding.etPwd.text?.length ?: 0) |
||||
} |
||||
|
||||
mBinding.tvShowOutLogin.setOnClickListener { |
||||
//切换到外部登录 |
||||
isOutLogin = true |
||||
refreshInnerOutUi() |
||||
} |
||||
|
||||
mBinding.tvShowInnerLogin.setOnClickListener { |
||||
//切换到内部集团登录 |
||||
isOutLogin = false |
||||
refreshInnerOutUi() |
||||
} |
||||
|
||||
mBinding.btnLogin.setOnClickListener { |
||||
if (isOutLogin) { |
||||
loginByOut() |
||||
} else { |
||||
loginByInner() |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 内部登录 |
||||
*/ |
||||
private fun loginByInner() { |
||||
|
||||
|
||||
} |
||||
|
||||
/** |
||||
* 外部登录 |
||||
*/ |
||||
private fun loginByOut() { |
||||
|
||||
|
||||
} |
||||
|
||||
private fun refreshInnerOutUi() { |
||||
if (isOutLogin) { |
||||
//当前外部登录 |
||||
mBinding.tvAccountDesc.text = Tools.getString(R.string.external_account_login) |
||||
|
||||
mBinding.llShowOutLogin.visibility = View.GONE |
||||
mBinding.llShowInnerLogin.visibility = View.VISIBLE |
||||
} else { |
||||
mBinding.tvAccountDesc.text = Tools.getString(R.string.group_account_login) |
||||
|
||||
mBinding.llShowOutLogin.visibility = View.VISIBLE |
||||
mBinding.llShowInnerLogin.visibility = View.GONE |
||||
} |
||||
|
||||
mBinding.etAccount.text = null |
||||
mBinding.etPwd.text = null |
||||
} |
||||
|
||||
override fun initData() { |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,237 @@ |
||||
/* |
||||
* Copyright (C) 2018 xuexiangjys(xuexiangjys@163.com) |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.project.survey.util; |
||||
|
||||
import android.graphics.Color; |
||||
|
||||
import androidx.annotation.ColorInt; |
||||
|
||||
import java.util.Random; |
||||
|
||||
/** |
||||
* 颜色辅助工具 |
||||
* |
||||
* @author xuexiang |
||||
* @since 2018/12/27 下午3:00 |
||||
*/ |
||||
public final class ColorUtils { |
||||
|
||||
private ColorUtils() { |
||||
throw new UnsupportedOperationException("u can't instantiate me..."); |
||||
} |
||||
|
||||
public static int setColorAlpha(@ColorInt int color, float alpha) { |
||||
return setColorAlpha(color, alpha, true); |
||||
} |
||||
|
||||
/** |
||||
* 设置颜色的alpha值 |
||||
* |
||||
* @param color 需要被设置的颜色值 |
||||
* @param alpha 取值为[0,1],0表示全透明,1表示不透明 |
||||
* @param override 覆盖原本的 alpha |
||||
* @return 返回改变了 alpha 值的颜色值 |
||||
*/ |
||||
public static int setColorAlpha(@ColorInt int color, float alpha, boolean override) { |
||||
int origin = override ? 0xff : (color >> 24) & 0xff; |
||||
return color & 0x00ffffff | (int) (alpha * origin) << 24; |
||||
} |
||||
|
||||
/** |
||||
* 根据比例,在两个color值之间计算出一个color值 |
||||
* <b>注意该方法是ARGB通道分开计算比例的</b> |
||||
* |
||||
* @param fromColor 开始的color值 |
||||
* @param toColor 最终的color值 |
||||
* @param fraction 比例,取值为[0,1],为0时返回 fromColor, 为1时返回 toColor |
||||
* @return 计算出的color值 |
||||
*/ |
||||
public static int computeColor(@ColorInt int fromColor, @ColorInt int toColor, float fraction) { |
||||
fraction = Math.max(Math.min(fraction, 1), 0); |
||||
|
||||
int minColorA = Color.alpha(fromColor); |
||||
int maxColorA = Color.alpha(toColor); |
||||
int resultA = (int) ((maxColorA - minColorA) * fraction) + minColorA; |
||||
|
||||
int minColorR = Color.red(fromColor); |
||||
int maxColorR = Color.red(toColor); |
||||
int resultR = (int) ((maxColorR - minColorR) * fraction) + minColorR; |
||||
|
||||
int minColorG = Color.green(fromColor); |
||||
int maxColorG = Color.green(toColor); |
||||
int resultG = (int) ((maxColorG - minColorG) * fraction) + minColorG; |
||||
|
||||
int minColorB = Color.blue(fromColor); |
||||
int maxColorB = Color.blue(toColor); |
||||
int resultB = (int) ((maxColorB - minColorB) * fraction) + minColorB; |
||||
|
||||
return Color.argb(resultA, resultR, resultG, resultB); |
||||
} |
||||
|
||||
/** |
||||
* 将 color 颜色值转换为十六进制字符串 |
||||
* |
||||
* @param color 颜色值 |
||||
* @return 转换后的字符串 |
||||
*/ |
||||
public static String colorToString(@ColorInt int color) { |
||||
return String.format("#%08X", color); |
||||
} |
||||
|
||||
/** |
||||
* 加深颜色 |
||||
* |
||||
* @param color 需要加深的颜色 |
||||
*/ |
||||
public static int darker(int color) { |
||||
return darker(color, 0.8F); |
||||
} |
||||
|
||||
/** |
||||
* 加深颜色 |
||||
* |
||||
* @param color 需要加深的颜色 |
||||
* @param factor The factor to darken the color. |
||||
* @return darker version of specified color. |
||||
*/ |
||||
public static int darker(int color, float factor) { |
||||
return Color.argb(Color.alpha(color), Math.max((int) (Color.red(color) * factor), 0), |
||||
Math.max((int) (Color.green(color) * factor), 0), |
||||
Math.max((int) (Color.blue(color) * factor), 0)); |
||||
} |
||||
|
||||
/** |
||||
* 变浅颜色 |
||||
* |
||||
* @param color 需要变浅的颜色 |
||||
*/ |
||||
public static int lighter(int color) { |
||||
return lighter(color, 0.8F); |
||||
} |
||||
|
||||
/** |
||||
* 变浅颜色 |
||||
* |
||||
* @param color 需要变浅的颜色 |
||||
* @param factor The factor to lighten the color. 0 will make the color unchanged. 1 will make the |
||||
* color white. |
||||
* @return lighter version of the specified color. |
||||
*/ |
||||
public static int lighter(int color, float factor) { |
||||
int red = (int) ((Color.red(color) * (1 - factor) / 255 + factor) * 255); |
||||
int green = (int) ((Color.green(color) * (1 - factor) / 255 + factor) * 255); |
||||
int blue = (int) ((Color.blue(color) * (1 - factor) / 255 + factor) * 255); |
||||
return Color.argb(Color.alpha(color), red, green, blue); |
||||
} |
||||
|
||||
/** |
||||
* 是否是深色的颜色 |
||||
* |
||||
* @param color |
||||
* @return |
||||
*/ |
||||
public static boolean isColorDark(@ColorInt int color) { |
||||
return isColorDark(color, 0.5F); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 是否是深色的颜色 |
||||
* |
||||
* @param color 颜色 |
||||
* @param factor 比例 |
||||
* @return |
||||
*/ |
||||
public static boolean isColorDark(@ColorInt int color, double factor) { |
||||
double darkness = |
||||
1 |
||||
- (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) |
||||
/ 255; |
||||
return darkness >= factor; |
||||
} |
||||
|
||||
/** |
||||
* @return 获取随机色 |
||||
*/ |
||||
public static int getRandomColor() { |
||||
return new RandomColor(255, 0, 255).getColor(); |
||||
} |
||||
|
||||
/** |
||||
* 随机颜色 |
||||
*/ |
||||
public static class RandomColor { |
||||
int alpha; |
||||
int lower; |
||||
int upper; |
||||
|
||||
RandomColor(int alpha, int lower, int upper) { |
||||
if (upper <= lower) { |
||||
throw new IllegalArgumentException("must be lower < upper"); |
||||
} |
||||
setAlpha(alpha); |
||||
setLower(lower); |
||||
setUpper(upper); |
||||
} |
||||
|
||||
public int getColor() { |
||||
//随机数是前闭 后开
|
||||
int red = getLower() + new Random().nextInt(getUpper() - getLower() + 1); |
||||
int green = getLower() + new Random().nextInt(getUpper() - getLower() + 1); |
||||
int blue = getLower() + new Random().nextInt(getUpper() - getLower() + 1); |
||||
return Color.argb(getAlpha(), red, green, blue); |
||||
} |
||||
|
||||
public int getAlpha() { |
||||
return alpha; |
||||
} |
||||
|
||||
public void setAlpha(int alpha) { |
||||
if (alpha > 255) { |
||||
alpha = 255; |
||||
} |
||||
if (alpha < 0) { |
||||
alpha = 0; |
||||
} |
||||
this.alpha = alpha; |
||||
} |
||||
|
||||
int getLower() { |
||||
return lower; |
||||
} |
||||
|
||||
void setLower(int lower) { |
||||
if (lower < 0) { |
||||
lower = 0; |
||||
} |
||||
this.lower = lower; |
||||
} |
||||
|
||||
int getUpper() { |
||||
return upper; |
||||
} |
||||
|
||||
void setUpper(int upper) { |
||||
if (upper > 255) { |
||||
upper = 255; |
||||
} |
||||
this.upper = upper; |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,343 @@ |
||||
package com.project.survey.util; |
||||
|
||||
import android.app.Activity; |
||||
import android.content.Context; |
||||
import android.graphics.Point; |
||||
import android.os.Build; |
||||
import android.util.DisplayMetrics; |
||||
import android.view.Display; |
||||
import android.view.WindowManager; |
||||
|
||||
import androidx.annotation.NonNull; |
||||
|
||||
import com.project.survey.App; |
||||
|
||||
|
||||
/** |
||||
* 屏幕密度工具类 |
||||
* |
||||
* @author xuexiang |
||||
* @since 2018/12/18 上午12:15 |
||||
*/ |
||||
public final class DensityUtils { |
||||
|
||||
private DensityUtils() { |
||||
throw new UnsupportedOperationException("u can't instantiate me..."); |
||||
} |
||||
|
||||
/** |
||||
* DisplayMetrics |
||||
* |
||||
* @return 屏幕密度 |
||||
*/ |
||||
@Deprecated |
||||
public static DisplayMetrics getDisplayMetrics() { |
||||
return ResUtils.getResources().getDisplayMetrics(); |
||||
} |
||||
|
||||
/** |
||||
* DisplayMetrics |
||||
* |
||||
* @return 屏幕密度 |
||||
*/ |
||||
public static DisplayMetrics getDisplayMetrics(@NonNull Context context) { |
||||
return context.getResources().getDisplayMetrics(); |
||||
} |
||||
|
||||
/** |
||||
* 根据手机的分辨率从 dp 的单位 转成为 px(像素) |
||||
* |
||||
* @param dpValue 尺寸dip |
||||
* @return 像素值 |
||||
*/ |
||||
@Deprecated |
||||
public static int dp2px(float dpValue) { |
||||
final float scale = ResUtils.getResources().getDisplayMetrics().density; |
||||
return (int) (dpValue * scale + 0.5f); |
||||
} |
||||
|
||||
/** |
||||
* 根据手机的分辨率从 dp 的单位 转成为 px(像素) |
||||
* |
||||
* @param context 上下文 |
||||
* @param dpValue 尺寸dip |
||||
* @return 像素值 |
||||
*/ |
||||
public static int dp2px(Context context, float dpValue) { |
||||
final float scale = context.getResources().getDisplayMetrics().density; |
||||
return (int) (dpValue * scale + 0.5f); |
||||
} |
||||
|
||||
/** |
||||
* 根据手机的分辨率从 px(像素) 的单位 转成为 dp |
||||
* |
||||
* @param pxValue 尺寸像素 |
||||
* @return DIP值 |
||||
*/ |
||||
@Deprecated |
||||
public static int px2dp(float pxValue) { |
||||
final float scale = ResUtils.getResources().getDisplayMetrics().density; |
||||
return (int) (pxValue / scale + 0.5f); |
||||
} |
||||
|
||||
/** |
||||
* 根据手机的分辨率从 px(像素) 的单位 转成为 dp |
||||
* |
||||
* @param context 上下文 |
||||
* @param pxValue 尺寸像素 |
||||
* @return DIP值 |
||||
*/ |
||||
public static int px2dp(Context context, float pxValue) { |
||||
final float scale = context.getResources().getDisplayMetrics().density; |
||||
return (int) (pxValue / scale + 0.5f); |
||||
} |
||||
|
||||
/** |
||||
* 根据手机的分辨率从 px(像素) 的单位 转成为 sp |
||||
* |
||||
* @param pxValue 尺寸像素 |
||||
* @return SP值 |
||||
*/ |
||||
@Deprecated |
||||
public static int px2sp(float pxValue) { |
||||
float fontScale = ResUtils.getResources().getDisplayMetrics().scaledDensity; |
||||
return (int) (pxValue / fontScale + 0.5f); |
||||
} |
||||
|
||||
/** |
||||
* 根据手机的分辨率从 px(像素) 的单位 转成为 sp |
||||
* |
||||
* @param pxValue 尺寸像素 |
||||
* @return SP值 |
||||
*/ |
||||
public static int px2sp(Context context, float pxValue) { |
||||
float fontScale = context.getResources().getDisplayMetrics().scaledDensity; |
||||
return (int) (pxValue / fontScale + 0.5f); |
||||
} |
||||
|
||||
/** |
||||
* 根据手机的分辨率从 sp 的单位 转成为 px |
||||
* |
||||
* @param spValue SP值 |
||||
* @return 像素值 |
||||
*/ |
||||
@Deprecated |
||||
public static int sp2px(float spValue) { |
||||
float fontScale = ResUtils.getResources().getDisplayMetrics().scaledDensity; |
||||
return (int) (spValue * fontScale + 0.5f); |
||||
} |
||||
|
||||
/** |
||||
* 根据手机的分辨率从 sp 的单位 转成为 px |
||||
* |
||||
* @param spValue SP值 |
||||
* @return 像素值 |
||||
*/ |
||||
public static int sp2px(Context context, float spValue) { |
||||
float fontScale = context.getResources().getDisplayMetrics().scaledDensity; |
||||
return (int) (spValue * fontScale + 0.5f); |
||||
} |
||||
|
||||
/** |
||||
* 获取屏幕分辨率 |
||||
* |
||||
* @return 屏幕分辨率幕高度 |
||||
*/ |
||||
@Deprecated |
||||
public static int getScreenDpi() { |
||||
return getDisplayMetrics().densityDpi; |
||||
} |
||||
|
||||
/** |
||||
* 获取屏幕分辨率 |
||||
* |
||||
* @param context 上下文 |
||||
* @return 屏幕分辨率幕高度 |
||||
*/ |
||||
public static int getScreenDpi(@NonNull Context context) { |
||||
return getDisplayMetrics(context).densityDpi; |
||||
} |
||||
|
||||
/** |
||||
* 获取真实屏幕密度 |
||||
* |
||||
* @param context 上下文【注意,Application和Activity的屏幕密度是不一样的】 |
||||
* @return |
||||
*/ |
||||
public static int getRealDpi(Context context) { |
||||
DisplayMetrics metric = context.getResources().getDisplayMetrics(); |
||||
float xdpi = metric.xdpi; |
||||
float ydpi = metric.ydpi; |
||||
|
||||
return (int) (((xdpi + ydpi) / 2.0F) + 0.5F); |
||||
} |
||||
|
||||
/** |
||||
* 获取应用窗口的尺寸 |
||||
* |
||||
* @param activity 应用窗口 |
||||
* @param isReal 是否是真实的尺寸 |
||||
* @return 应用窗口的尺寸 |
||||
*/ |
||||
public static Point getAppSize(Activity activity, boolean isReal) { |
||||
return getDisplaySize(activity, isReal); |
||||
} |
||||
|
||||
/** |
||||
* 获取屏幕的尺寸 |
||||
* |
||||
* @param isReal 是否是真实的尺寸 |
||||
* @return 屏幕的尺寸 |
||||
*/ |
||||
public static Point getScreenSize(boolean isReal) { |
||||
return getDisplaySize(App.getApp(), isReal); |
||||
} |
||||
|
||||
/** |
||||
* 获取上下文所在的尺寸 |
||||
* |
||||
* @param context 上下文 |
||||
* @param isReal 是否是真实的尺寸 |
||||
* @return 上下文所在的尺寸 |
||||
*/ |
||||
public static Point getDisplaySize(Context context, boolean isReal) { |
||||
WindowManager windowManager; |
||||
if (context instanceof Activity) { |
||||
windowManager = ((Activity) context).getWindowManager(); |
||||
} else { |
||||
windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); |
||||
} |
||||
if (windowManager == null) { |
||||
return null; |
||||
} |
||||
Display display = windowManager.getDefaultDisplay(); |
||||
Point point = new Point(); |
||||
if (isReal) { |
||||
display.getRealSize(point); |
||||
} else { |
||||
display.getSize(point); |
||||
} |
||||
return point; |
||||
} |
||||
|
||||
/** |
||||
* 获取上下文所在的宽度 |
||||
* |
||||
* @param context 上下文 |
||||
* @param isReal 是否是真实的尺寸 |
||||
* @return 上下文所在的宽度 |
||||
*/ |
||||
public static int getDisplayWidth(Context context, boolean isReal) { |
||||
Point point = getDisplaySize(context, isReal); |
||||
return point != null ? point.x : 0; |
||||
} |
||||
|
||||
/** |
||||
* 获取上下文所在的高度 |
||||
* |
||||
* @param context 上下文 |
||||
* @param isReal 是否是真实的尺寸 |
||||
* @return 上下文所在的高度 |
||||
*/ |
||||
public static int getDisplayHeight(Context context, boolean isReal) { |
||||
Point point = getDisplaySize(context, isReal); |
||||
return point != null ? point.y : 0; |
||||
} |
||||
|
||||
/** |
||||
* 获取应用窗口的度量信息 |
||||
* |
||||
* @param activity 应用窗口 |
||||
* @param isReal 是否是真实的度量信息 |
||||
* @return 应用窗口的度量信息 |
||||
*/ |
||||
public static DisplayMetrics getAppMetrics(Activity activity, boolean isReal) { |
||||
return getDisplayMetrics(activity, isReal); |
||||
} |
||||
|
||||
/** |
||||
* 获取屏幕的度量信息 |
||||
* |
||||
* @param isReal 是否是真实的度量信息 |
||||
* @return 屏幕的度量信息 |
||||
*/ |
||||
public static DisplayMetrics getScreenMetrics(boolean isReal) { |
||||
return getDisplayMetrics(App.getApp(), isReal); |
||||
} |
||||
|
||||
/** |
||||
* 获取上下文所在的度量信息 |
||||
* |
||||
* @param context 上下文 |
||||
* @param isReal 是否是真实的度量信息 |
||||
* @return 上下文所在的度量信息 |
||||
*/ |
||||
public static DisplayMetrics getDisplayMetrics(Context context, boolean isReal) { |
||||
WindowManager windowManager; |
||||
if (context instanceof Activity) { |
||||
windowManager = ((Activity) context).getWindowManager(); |
||||
} else { |
||||
windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); |
||||
} |
||||
if (windowManager == null) { |
||||
return null; |
||||
} |
||||
Display display = windowManager.getDefaultDisplay(); |
||||
DisplayMetrics metrics = new DisplayMetrics(); |
||||
if (isReal) { |
||||
display.getRealMetrics(metrics); |
||||
} else { |
||||
display.getMetrics(metrics); |
||||
} |
||||
return metrics; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 底部导航条是否开启 |
||||
* |
||||
* @param context 上下文 |
||||
* @return 底部导航条是否显示 |
||||
*/ |
||||
public static boolean isNavigationBarExist(Context context) { |
||||
return getNavigationBarHeight(context) > 0; |
||||
} |
||||
|
||||
/** |
||||
* 获取系统底部导航栏的高度 |
||||
* |
||||
* @param context 上下文 |
||||
* @return 系统状态栏的高度 |
||||
*/ |
||||
public static int getNavigationBarHeight(Context context) { |
||||
WindowManager windowManager; |
||||
if (context instanceof Activity) { |
||||
windowManager = ((Activity) context).getWindowManager(); |
||||
} else { |
||||
windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); |
||||
} |
||||
if (windowManager == null) { |
||||
return 0; |
||||
} |
||||
Display defaultDisplay = windowManager.getDefaultDisplay(); |
||||
DisplayMetrics realDisplayMetrics = new DisplayMetrics(); |
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { |
||||
defaultDisplay.getRealMetrics(realDisplayMetrics); |
||||
} |
||||
int realHeight = realDisplayMetrics.heightPixels; |
||||
int realWidth = realDisplayMetrics.widthPixels; |
||||
|
||||
DisplayMetrics displayMetrics = new DisplayMetrics(); |
||||
defaultDisplay.getMetrics(displayMetrics); |
||||
|
||||
int displayHeight = displayMetrics.heightPixels; |
||||
int displayWidth = displayMetrics.widthPixels; |
||||
|
||||
if (realHeight - displayHeight > 0) { |
||||
return realHeight - displayHeight; |
||||
} |
||||
return Math.max(realWidth - displayWidth, 0); |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,271 @@ |
||||
package com.project.survey.util; |
||||
|
||||
import android.annotation.SuppressLint; |
||||
import android.annotation.TargetApi; |
||||
import android.app.AppOpsManager; |
||||
import android.content.Context; |
||||
import android.content.res.Configuration; |
||||
import android.os.Binder; |
||||
import android.os.Build; |
||||
import android.os.Environment; |
||||
import android.text.TextUtils; |
||||
|
||||
import androidx.annotation.Nullable; |
||||
|
||||
import com.project.survey.widget.util.Utils; |
||||
|
||||
import java.io.File; |
||||
import java.io.FileInputStream; |
||||
import java.lang.reflect.Method; |
||||
import java.util.Properties; |
||||
import java.util.regex.Matcher; |
||||
import java.util.regex.Pattern; |
||||
|
||||
/** |
||||
* 设备类型工具类 |
||||
* |
||||
* @author XUE |
||||
* @since 2019/3/22 10:56 |
||||
*/ |
||||
@SuppressLint("PrivateApi") |
||||
public class DeviceUtils { |
||||
private final static String KEY_MIUI_VERSION_NAME = "ro.miui.ui.version.name"; |
||||
private static final String KEY_FLYME_VERSION_NAME = "ro.build.display.id"; |
||||
private final static String FLYME = "flyme"; |
||||
private final static String ZTEC2016 = "zte c2016"; |
||||
private final static String ZUKZ1 = "zuk z1"; |
||||
private final static String ESSENTIAL = "essential"; |
||||
private final static String[] MEIZUBOARD = {"m9", "M9", "mx", "MX"}; |
||||
private static String sMiuiVersionName; |
||||
private static String sFlymeVersionName; |
||||
private static boolean sIsTabletChecked = false; |
||||
private static boolean sIsTabletValue = false; |
||||
private static final String BRAND = Build.BRAND.toLowerCase(); |
||||
|
||||
private DeviceUtils() { |
||||
throw new UnsupportedOperationException("u can't instantiate me..."); |
||||
} |
||||
|
||||
static { |
||||
Properties properties = new Properties(); |
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { |
||||
// android 8.0,读取 /system/uild.prop 会报 permission denied
|
||||
FileInputStream fileInputStream = null; |
||||
try { |
||||
fileInputStream = new FileInputStream(new File(Environment.getRootDirectory(), "build.prop")); |
||||
properties.load(fileInputStream); |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
} finally { |
||||
Utils.closeIOQuietly(fileInputStream); |
||||
} |
||||
} |
||||
|
||||
Class<?> clzSystemProperties = null; |
||||
try { |
||||
clzSystemProperties = Class.forName("android.os.SystemProperties"); |
||||
Method getMethod = clzSystemProperties.getDeclaredMethod("get", String.class); |
||||
// miui
|
||||
sMiuiVersionName = getLowerCaseName(properties, getMethod, KEY_MIUI_VERSION_NAME); |
||||
//flyme
|
||||
sFlymeVersionName = getLowerCaseName(properties, getMethod, KEY_FLYME_VERSION_NAME); |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
|
||||
private static boolean _isTablet(Context context) { |
||||
return (context.getResources().getConfiguration().screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK) >= |
||||
Configuration.SCREENLAYOUT_SIZE_LARGE; |
||||
} |
||||
|
||||
/** |
||||
* 判断是否为平板设备 |
||||
*/ |
||||
public static boolean isTablet(Context context) { |
||||
if (sIsTabletChecked) { |
||||
return sIsTabletValue; |
||||
} |
||||
sIsTabletValue = _isTablet(context); |
||||
sIsTabletChecked = true; |
||||
return sIsTabletValue; |
||||
} |
||||
|
||||
/** |
||||
* 判断是否是flyme系统 |
||||
*/ |
||||
public static boolean isFlyme() { |
||||
return !TextUtils.isEmpty(sFlymeVersionName) && sFlymeVersionName.contains(FLYME); |
||||
} |
||||
|
||||
/** |
||||
* 判断是否是MIUI系统 |
||||
*/ |
||||
public static boolean isMIUI() { |
||||
return !TextUtils.isEmpty(sMiuiVersionName); |
||||
} |
||||
|
||||
public static boolean isMIUIV5() { |
||||
return "v5".equals(sMiuiVersionName); |
||||
} |
||||
|
||||
public static boolean isMIUIV6() { |
||||
return "v6".equals(sMiuiVersionName); |
||||
} |
||||
|
||||
public static boolean isMIUIV7() { |
||||
return "v7".equals(sMiuiVersionName); |
||||
} |
||||
|
||||
public static boolean isMIUIV8() { |
||||
return "v8".equals(sMiuiVersionName); |
||||
} |
||||
|
||||
public static boolean isMIUIV9() { |
||||
return "v9".equals(sMiuiVersionName); |
||||
} |
||||
|
||||
public static boolean isFlymeVersionHigher5_2_4() { |
||||
//查不到默认高于5.2.4
|
||||
boolean isHigher = true; |
||||
if (sFlymeVersionName != null && !"".equals(sFlymeVersionName)) { |
||||
Pattern pattern = Pattern.compile("(\\d+\\.){2}\\d"); |
||||
Matcher matcher = pattern.matcher(sFlymeVersionName); |
||||
if (matcher.find()) { |
||||
String versionString = matcher.group(); |
||||
if (versionString != null && !"".equals(versionString)) { |
||||
String[] version = versionString.split("\\."); |
||||
if (version.length == 3) { |
||||
if (Integer.parseInt(version[0]) < 5) { |
||||
isHigher = false; |
||||
} else if (Integer.parseInt(version[0]) > 5) { |
||||
isHigher = true; |
||||
} else { |
||||
if (Integer.parseInt(version[1]) < 2) { |
||||
isHigher = false; |
||||
} else if (Integer.parseInt(version[1]) > 2) { |
||||
isHigher = true; |
||||
} else { |
||||
if (Integer.parseInt(version[2]) < 4) { |
||||
isHigher = false; |
||||
} else if (Integer.parseInt(version[2]) >= 5) { |
||||
isHigher = true; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
} |
||||
} |
||||
return isMeizu() && isHigher; |
||||
} |
||||
|
||||
public static boolean isMeizu() { |
||||
return isPhone(MEIZUBOARD) || isFlyme(); |
||||
} |
||||
|
||||
/** |
||||
* 判断是否为小米 |
||||
* https://dev.mi.com/doc/?p=254
|
||||
*/ |
||||
public static boolean isXiaomi() { |
||||
return "xiaomi".equals(Build.MANUFACTURER.toLowerCase()); |
||||
} |
||||
|
||||
public static boolean isVivo() { |
||||
return BRAND.contains("vivo") || BRAND.contains("bbk"); |
||||
} |
||||
|
||||
public static boolean isOppo() { |
||||
return BRAND.contains("oppo"); |
||||
} |
||||
|
||||
public static boolean isHuawei() { |
||||
return BRAND.contains("huawei") || BRAND.contains("honor"); |
||||
} |
||||
|
||||
public static boolean isEssentialPhone() { |
||||
return BRAND.contains("essential"); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 判断是否为 ZUK Z1 和 ZTK C2016。 |
||||
* 两台设备的系统虽然为 android 6.0,但不支持状态栏icon颜色改变,因此经常需要对它们进行额外判断。 |
||||
*/ |
||||
public static boolean isZUKZ1() { |
||||
final String board = Build.MODEL; |
||||
return board != null && board.toLowerCase().contains(ZUKZ1); |
||||
} |
||||
|
||||
public static boolean isZTKC2016() { |
||||
final String board = Build.MODEL; |
||||
return board != null && board.toLowerCase().contains(ZTEC2016); |
||||
} |
||||
|
||||
private static boolean isPhone(String[] boards) { |
||||
final String board = Build.BOARD; |
||||
if (board == null) { |
||||
return false; |
||||
} |
||||
for (String board1 : boards) { |
||||
if (board.equals(board1)) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* 判断悬浮窗权限(目前主要用户魅族与小米的检测)。 |
||||
*/ |
||||
public static boolean isFloatWindowOpAllowed(Context context) { |
||||
final int version = Build.VERSION.SDK_INT; |
||||
if (version >= 19) { |
||||
return checkOp(context, 24); // 24 是AppOpsManager.OP_SYSTEM_ALERT_WINDOW 的值,该值无法直接访问
|
||||
} else { |
||||
try { |
||||
return (context.getApplicationInfo().flags & 1 << 27) == 1 << 27; |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
return false; |
||||
} |
||||
} |
||||
} |
||||
|
||||
@TargetApi(19) |
||||
private static boolean checkOp(Context context, int op) { |
||||
final int version = Build.VERSION.SDK_INT; |
||||
if (version >= Build.VERSION_CODES.KITKAT) { |
||||
AppOpsManager manager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); |
||||
try { |
||||
Method method = manager.getClass().getDeclaredMethod("checkOp", int.class, int.class, String.class); |
||||
int property = (Integer) method.invoke(manager, op, |
||||
Binder.getCallingUid(), context.getPackageName()); |
||||
return AppOpsManager.MODE_ALLOWED == property; |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
@Nullable |
||||
private static String getLowerCaseName(Properties p, Method get, String key) { |
||||
String name = p.getProperty(key); |
||||
if (name == null) { |
||||
try { |
||||
name = (String) get.invoke(null, key); |
||||
} catch (Exception ignored) { |
||||
} |
||||
} |
||||
if (name != null) { |
||||
name = name.toLowerCase(); |
||||
} |
||||
return name; |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,640 @@ |
||||
/* |
||||
* Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
*/ |
||||
|
||||
package com.project.survey.util; |
||||
|
||||
import android.content.Context; |
||||
import android.content.res.ColorStateList; |
||||
import android.content.res.Resources; |
||||
import android.graphics.Bitmap; |
||||
import android.graphics.Canvas; |
||||
import android.graphics.Color; |
||||
import android.graphics.ColorFilter; |
||||
import android.graphics.LightingColorFilter; |
||||
import android.graphics.Matrix; |
||||
import android.graphics.Paint; |
||||
import android.graphics.PixelFormat; |
||||
import android.graphics.Rect; |
||||
import android.graphics.RectF; |
||||
import android.graphics.drawable.BitmapDrawable; |
||||
import android.graphics.drawable.Drawable; |
||||
import android.graphics.drawable.GradientDrawable; |
||||
import android.graphics.drawable.LayerDrawable; |
||||
import android.graphics.drawable.ShapeDrawable; |
||||
import android.graphics.drawable.StateListDrawable; |
||||
import android.view.View; |
||||
import android.webkit.WebView; |
||||
import android.widget.ImageView; |
||||
import android.widget.ScrollView; |
||||
|
||||
import androidx.annotation.ColorInt; |
||||
import androidx.annotation.DrawableRes; |
||||
import androidx.annotation.FloatRange; |
||||
import androidx.annotation.NonNull; |
||||
import androidx.annotation.Nullable; |
||||
import androidx.appcompat.content.res.AppCompatResources; |
||||
import androidx.core.graphics.drawable.DrawableCompat; |
||||
import androidx.core.widget.NestedScrollView; |
||||
|
||||
import java.security.InvalidParameterException; |
||||
|
||||
/** |
||||
* Drawable工具类 |
||||
* |
||||
* @author xuexiang |
||||
* @since 2019/1/3 下午3:47 |
||||
*/ |
||||
public final class DrawableUtils { |
||||
|
||||
private DrawableUtils() { |
||||
throw new UnsupportedOperationException("u can't instantiate me..."); |
||||
} |
||||
|
||||
private static final String TAG = DrawableUtils.class.getSimpleName(); |
||||
|
||||
/** |
||||
* 节省每次创建时产生的开销,但要注意多线程操作synchronized |
||||
*/ |
||||
private static final Canvas CANVAS = new Canvas(); |
||||
|
||||
/** |
||||
* 从一个view创建Bitmap。 |
||||
* 注意点:绘制之前要清掉 View 的焦点,因为焦点可能会改变一个 View 的 UI 状态。 |
||||
* 来源:https://github.com/tyrantgit/ExplosionField
|
||||
* |
||||
* @param view 传入一个 View,会获取这个 View 的内容创建 Bitmap。 |
||||
* @param scale 缩放比例,对创建的 Bitmap 进行缩放,数值支持从 0 到 1。 |
||||
*/ |
||||
public static Bitmap createBitmapFromView(View view, float scale) { |
||||
if (view instanceof ImageView) { |
||||
Drawable drawable = ((ImageView) view).getDrawable(); |
||||
if (drawable != null && drawable instanceof BitmapDrawable) { |
||||
return ((BitmapDrawable) drawable).getBitmap(); |
||||
} |
||||
} |
||||
view.clearFocus(); |
||||
int viewHeight = 0; |
||||
if (view instanceof ScrollView) { |
||||
for (int i = 0; i < ((ScrollView) view).getChildCount(); i++) { |
||||
viewHeight += ((ScrollView) view).getChildAt(i).getHeight(); |
||||
} |
||||
} else if (view instanceof NestedScrollView) { |
||||
for (int i = 0; i < ((NestedScrollView) view).getChildCount(); i++) { |
||||
viewHeight += ((NestedScrollView) view).getChildAt(i).getHeight(); |
||||
} |
||||
} else { |
||||
viewHeight = view.getHeight(); |
||||
} |
||||
|
||||
Bitmap bitmap = createBitmapSafely((int) (view.getWidth() * scale), |
||||
(int) (viewHeight * scale), Bitmap.Config.ARGB_8888, 1); |
||||
if (bitmap != null) { |
||||
synchronized (CANVAS) { |
||||
Canvas canvas = CANVAS; |
||||
canvas.setBitmap(bitmap); |
||||
canvas.save(); |
||||
// 防止 View 上面有些区域空白导致最终 Bitmap 上有些区域变黑
|
||||
canvas.drawColor(Color.WHITE); |
||||
canvas.scale(scale, scale); |
||||
view.draw(canvas); |
||||
canvas.restore(); |
||||
canvas.setBitmap(null); |
||||
} |
||||
} |
||||
return bitmap; |
||||
} |
||||
|
||||
|
||||
public static Bitmap createBitmapFromWebView(WebView view) { |
||||
return createBitmapFromWebView(view, 1f); |
||||
} |
||||
|
||||
public static Bitmap createBitmapFromWebView(WebView view, float scale) { |
||||
view.clearFocus(); |
||||
int viewHeight = (int) (view.getContentHeight() * view.getScale()); |
||||
Bitmap bitmap = createBitmapSafely((int) (view.getWidth() * scale), (int) (viewHeight * scale), Bitmap.Config.ARGB_8888, 1); |
||||
|
||||
int unitHeight = view.getHeight(); |
||||
int bottom = viewHeight; |
||||
|
||||
if (bitmap != null) { |
||||
synchronized (CANVAS) { |
||||
Canvas canvas = CANVAS; |
||||
canvas.setBitmap(bitmap); |
||||
// 防止 View 上面有些区域空白导致最终 Bitmap 上有些区域变黑
|
||||
canvas.drawColor(Color.WHITE); |
||||
canvas.scale(scale, scale); |
||||
while (bottom > 0) { |
||||
if (bottom < unitHeight) { |
||||
bottom = 0; |
||||
} else { |
||||
bottom -= unitHeight; |
||||
} |
||||
canvas.save(); |
||||
canvas.clipRect(0, bottom, canvas.getWidth(), bottom + unitHeight); |
||||
view.scrollTo(0, bottom); |
||||
view.draw(canvas); |
||||
canvas.restore(); |
||||
} |
||||
canvas.setBitmap(null); |
||||
} |
||||
} |
||||
return bitmap; |
||||
} |
||||
|
||||
|
||||
public static Bitmap createBitmapFromView(View view) { |
||||
return createBitmapFromView(view, 1f); |
||||
} |
||||
|
||||
/** |
||||
* 从一个view创建Bitmap。把view的区域截掉leftCrop/topCrop/rightCrop/bottomCrop |
||||
*/ |
||||
public static Bitmap createBitmapFromView(View view, int leftCrop, int topCrop, int rightCrop, int bottomCrop) { |
||||
Bitmap originBitmap = DrawableUtils.createBitmapFromView(view); |
||||
if (originBitmap == null) { |
||||
return null; |
||||
} |
||||
Bitmap cutBitmap = createBitmapSafely(view.getWidth() - rightCrop - leftCrop, view.getHeight() - topCrop - bottomCrop, Bitmap.Config.ARGB_8888, 1); |
||||
if (cutBitmap == null) { |
||||
return null; |
||||
} |
||||
Canvas canvas = new Canvas(cutBitmap); |
||||
Rect src = new Rect(leftCrop, topCrop, view.getWidth() - rightCrop, view.getHeight() - bottomCrop); |
||||
Rect dest = new Rect(0, 0, view.getWidth() - rightCrop - leftCrop, view.getHeight() - topCrop - bottomCrop); |
||||
// 防止 View 上面有些区域空白导致最终 Bitmap 上有些区域变黑
|
||||
canvas.drawColor(Color.WHITE); |
||||
canvas.drawBitmap(originBitmap, src, dest, null); |
||||
originBitmap.recycle(); |
||||
return cutBitmap; |
||||
} |
||||
|
||||
/** |
||||
* 安全的创建bitmap。 |
||||
* 如果新建 Bitmap 时产生了 OOM,可以主动进行一次 GC - System.gc(),然后再次尝试创建。 |
||||
* |
||||
* @param width Bitmap 宽度。 |
||||
* @param height Bitmap 高度。 |
||||
* @param config 传入一个 Bitmap.Config。 |
||||
* @param retryCount 创建 Bitmap 时产生 OOM 后,主动重试的次数。 |
||||
* @return 返回创建的 Bitmap。 |
||||
*/ |
||||
public static Bitmap createBitmapSafely(int width, int height, Bitmap.Config config, int retryCount) { |
||||
//width and height must be > 0
|
||||
if (width <= 0 || height <= 0) { |
||||
return null; |
||||
} |
||||
try { |
||||
return Bitmap.createBitmap(width, height, config); |
||||
} catch (OutOfMemoryError e) { |
||||
e.printStackTrace(); |
||||
if (retryCount > 0) { |
||||
System.gc(); |
||||
return createBitmapSafely(width, height, config, retryCount - 1); |
||||
} |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 安全的创建bitmap。 |
||||
* 如果新建 Bitmap 时产生了 OOM,可以主动进行一次 GC - System.gc(),然后再次尝试创建。 |
||||
* |
||||
* @param source 原图片 |
||||
* @param x 源中第一个像素的x坐标 |
||||
* @param y 源中第一个像素的y坐标 |
||||
* @param width 一行像素点的数量 |
||||
* @param height 行数 |
||||
* @param retryCount 创建 Bitmap 时产生 OOM 后,主动重试的次数。 |
||||
* @return 返回创建的 Bitmap。 |
||||
*/ |
||||
public static Bitmap createBitmapSafely(@NonNull Bitmap source, int x, int y, int width, int height, int retryCount) { |
||||
if (x < 0 || y < 0 || width <= 0 || height <= 0) { |
||||
return null; |
||||
} |
||||
try { |
||||
return Bitmap.createBitmap(source, x, y, width, height); |
||||
} catch (IllegalArgumentException e) { |
||||
e.printStackTrace(); |
||||
return null; |
||||
} catch (OutOfMemoryError e) { |
||||
e.printStackTrace(); |
||||
if (retryCount > 0) { |
||||
System.gc(); |
||||
return createBitmapSafely(source, x, y, width, height, retryCount - 1); |
||||
} |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 创建一张指定大小的纯色图片,支持圆角 |
||||
* |
||||
* @param resources Resources对象,用于创建BitmapDrawable |
||||
* @param width 图片的宽度 |
||||
* @param height 图片的高度 |
||||
* @param cornerRadius 图片的圆角,不需要则传0 |
||||
* @param filledColor 图片的填充色 |
||||
* @return 指定大小的纯色图片 |
||||
*/ |
||||
public static BitmapDrawable createDrawableWithSize(Resources resources, int width, int height, int cornerRadius, @ColorInt int filledColor) { |
||||
Bitmap output = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); |
||||
Canvas canvas = new Canvas(output); |
||||
|
||||
if (filledColor == 0) { |
||||
filledColor = Color.TRANSPARENT; |
||||
} |
||||
if (cornerRadius > 0) { |
||||
Paint paint = new Paint(); |
||||
paint.setAntiAlias(true); |
||||
paint.setStyle(Paint.Style.FILL); |
||||
paint.setColor(filledColor); |
||||
canvas.drawRoundRect(new RectF(0, 0, width, height), cornerRadius, cornerRadius, paint); |
||||
} else { |
||||
canvas.drawColor(filledColor); |
||||
} |
||||
return new BitmapDrawable(resources, output); |
||||
} |
||||
|
||||
/** |
||||
* 设置Drawable的颜色 |
||||
* <b>这里不对Drawable进行mutate(),会影响到所有用到这个Drawable的地方,如果要避免,请先自行mutate()</b> |
||||
*/ |
||||
public static ColorFilter setDrawableTintColor(Drawable drawable, @ColorInt int tintColor) { |
||||
LightingColorFilter colorFilter = new LightingColorFilter(Color.argb(255, 0, 0, 0), tintColor); |
||||
if (drawable != null) { |
||||
drawable.setColorFilter(colorFilter); |
||||
} |
||||
return colorFilter; |
||||
} |
||||
|
||||
/** |
||||
* 创建一张渐变图片,支持韵脚。 |
||||
* |
||||
* @param startColor 渐变开始色 |
||||
* @param endColor 渐变结束色 |
||||
* @param radius 圆角大小 |
||||
* @param centerX 渐变中心点 X 轴坐标 |
||||
* @param centerY 渐变中心点 Y 轴坐标 |
||||
* @return 返回所创建的渐变图片。 |
||||
*/ |
||||
public static GradientDrawable createCircleGradientDrawable(@ColorInt int startColor, |
||||
@ColorInt int endColor, int radius, |
||||
@FloatRange(from = 0f, to = 1f) float centerX, |
||||
@FloatRange(from = 0f, to = 1f) float centerY) { |
||||
GradientDrawable gradientDrawable = new GradientDrawable(); |
||||
gradientDrawable.setColors(new int[]{ |
||||
startColor, |
||||
endColor |
||||
}); |
||||
gradientDrawable.setGradientType(GradientDrawable.RADIAL_GRADIENT); |
||||
gradientDrawable.setGradientRadius(radius); |
||||
gradientDrawable.setGradientCenter(centerX, centerY); |
||||
return gradientDrawable; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 动态创建带上分隔线或下分隔线的Drawable。 |
||||
* |
||||
* @param separatorColor 分割线颜色。 |
||||
* @param bgColor Drawable 的背景色。 |
||||
* @param top true 则分割线为上分割线,false 则为下分割线。 |
||||
* @return 返回所创建的 Drawable。 |
||||
*/ |
||||
public static LayerDrawable createItemSeparatorBg(@ColorInt int separatorColor, @ColorInt int bgColor, int separatorHeight, boolean top) { |
||||
|
||||
ShapeDrawable separator = new ShapeDrawable(); |
||||
separator.getPaint().setStyle(Paint.Style.FILL); |
||||
separator.getPaint().setColor(separatorColor); |
||||
|
||||
ShapeDrawable bg = new ShapeDrawable(); |
||||
bg.getPaint().setStyle(Paint.Style.FILL); |
||||
bg.getPaint().setColor(bgColor); |
||||
|
||||
Drawable[] layers = {separator, bg}; |
||||
LayerDrawable layerDrawable = new LayerDrawable(layers); |
||||
|
||||
layerDrawable.setLayerInset(1, 0, top ? separatorHeight : 0, 0, top ? 0 : separatorHeight); |
||||
return layerDrawable; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 创建一张指定大小的圆形图片,并附带文字 |
||||
* |
||||
* @param resources Resources对象,用于创建BitmapDrawable |
||||
* @param size 图片的宽度 |
||||
* @param filledColor 图片的填充色 |
||||
* @param text 文字 |
||||
* @param textSize 文字大小(px) |
||||
* @param textColor 文字颜色 |
||||
* @return 指定大小的纯色图片 |
||||
*/ |
||||
public static BitmapDrawable createCircleDrawableWithText(Resources resources, int size, @ColorInt int filledColor, String text, float textSize, @ColorInt int textColor) { |
||||
if (size <= 0) { |
||||
throw new InvalidParameterException("bitmap size must be > 0!"); |
||||
} |
||||
if (textSize <= 0) { |
||||
throw new InvalidParameterException("text size must be > 0!"); |
||||
} |
||||
Bitmap output = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); |
||||
Canvas canvas = new Canvas(output); |
||||
canvas.drawColor(Color.TRANSPARENT); |
||||
// 画圆
|
||||
int radius = size / 2; |
||||
Paint paint = new Paint(); |
||||
paint.setAntiAlias(true); |
||||
paint.setStyle(Paint.Style.FILL); |
||||
paint.setColor(filledColor); |
||||
canvas.drawCircle(radius, radius, radius, paint); |
||||
// 画文字
|
||||
paint.setColor(textColor); |
||||
paint.setTextSize(textSize); |
||||
paint.setTextAlign(Paint.Align.CENTER); |
||||
float baseline = radius + getBaselineDistance(paint); |
||||
canvas.drawText(text, radius, baseline, paint); |
||||
return new BitmapDrawable(resources, output); |
||||
} |
||||
|
||||
/** |
||||
* 获取画笔的基线距离 |
||||
* |
||||
* @param paint 画笔 |
||||
* @return 基线距离 |
||||
*/ |
||||
public static float getBaselineDistance(@NonNull Paint paint) { |
||||
Paint.FontMetrics fontMetrics = paint.getFontMetrics(); |
||||
return (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom; |
||||
} |
||||
|
||||
/////////////// StateListDrawable /////////////////////
|
||||
|
||||
/** |
||||
* 实体 得到随机色 状态选择器 |
||||
* |
||||
* @param cornerRadius 圆角半径 |
||||
* @return 状态选择器 |
||||
*/ |
||||
public static StateListDrawable getDrawable(int cornerRadius) { |
||||
return getDrawable(cornerRadius, ColorUtils.getRandomColor()); |
||||
} |
||||
|
||||
/** |
||||
* 实体 按下的颜色加深 |
||||
* |
||||
* @param cornerRadius 圆角半径 |
||||
* @param normalColor 正常的颜色 |
||||
* @return 状态选择器 |
||||
*/ |
||||
|
||||
public static StateListDrawable getDrawable(int cornerRadius, int normalColor) { |
||||
return getDrawable(cornerRadius, ColorUtils.darker(normalColor, 0.8F), normalColor); |
||||
} |
||||
|
||||
/** |
||||
* 实体 状态选择器 |
||||
* |
||||
* @param cornerRadius 圆角半径 |
||||
* @param pressedColor 按下颜色 |
||||
* @param normalColor 正常的颜色 |
||||
* @return 状态选择器 |
||||
*/ |
||||
public static StateListDrawable getDrawable(int cornerRadius, int pressedColor, int normalColor) { |
||||
return getStateListDrawable(getSolidRectDrawable(cornerRadius, pressedColor), getSolidRectDrawable(cornerRadius, normalColor)); |
||||
} |
||||
|
||||
/** |
||||
* 背景选择器 |
||||
* |
||||
* @param pressedDrawable 按下状态的Drawable |
||||
* @param normalDrawable 正常状态的Drawable |
||||
* @return 状态选择器 |
||||
*/ |
||||
public static StateListDrawable getStateListDrawable(Drawable pressedDrawable, Drawable normalDrawable) { |
||||
StateListDrawable stateListDrawable = new StateListDrawable(); |
||||
stateListDrawable.addState(new int[]{android.R.attr.state_enabled, android.R.attr.state_pressed}, pressedDrawable); |
||||
stateListDrawable.addState(new int[]{android.R.attr.state_enabled}, normalDrawable); |
||||
//设置不能用的状态
|
||||
//默认其他状态背景
|
||||
GradientDrawable gray = getSolidRectDrawable(10, Color.GRAY); |
||||
stateListDrawable.addState(new int[]{}, gray); |
||||
return stateListDrawable; |
||||
} |
||||
|
||||
/** |
||||
* 得到实心的drawable, 一般作为选中,点中的效果 |
||||
* |
||||
* @param cornerRadius 圆角半径 |
||||
* @param solidColor 实心颜色 |
||||
* @return 得到实心效果 |
||||
*/ |
||||
public static GradientDrawable getSolidRectDrawable(int cornerRadius, int solidColor) { |
||||
GradientDrawable gradientDrawable = new GradientDrawable(); |
||||
// 设置矩形的圆角半径
|
||||
gradientDrawable.setCornerRadius(cornerRadius); |
||||
// 设置绘画图片色值
|
||||
gradientDrawable.setColor(solidColor); |
||||
// 绘画的是矩形
|
||||
gradientDrawable.setGradientType(GradientDrawable.RADIAL_GRADIENT); |
||||
return gradientDrawable; |
||||
} |
||||
|
||||
/** |
||||
* 给drawable上色 |
||||
* |
||||
* @param drawable 图像 |
||||
* @param tint 颜色 |
||||
* @return drawable |
||||
*/ |
||||
public static Drawable setTint(final Drawable drawable, @ColorInt int tint) { |
||||
if (drawable != null) { |
||||
DrawableCompat.setTint(drawable, tint); |
||||
} |
||||
return drawable; |
||||
} |
||||
|
||||
/** |
||||
* 给drawable上色 |
||||
* |
||||
* @param drawable 图像 |
||||
* @param tint 颜色 |
||||
* @return drawable |
||||
*/ |
||||
public static Drawable setTintList(final Drawable drawable, @Nullable ColorStateList tint) { |
||||
if (drawable != null) { |
||||
DrawableCompat.setTintList(drawable, tint); |
||||
} |
||||
return drawable; |
||||
} |
||||
|
||||
/////////////// VectorDrawable /////////////////////
|
||||
|
||||
@Nullable |
||||
public static Drawable getVectorDrawable(Context context, @DrawableRes int resVector) { |
||||
try { |
||||
return AppCompatResources.getDrawable(context, resVector); |
||||
} catch (Exception e) { |
||||
return null; |
||||
} |
||||
} |
||||
|
||||
public static Bitmap vectorDrawableToBitmap(Context context, @DrawableRes int resVector) { |
||||
Drawable drawable = getVectorDrawable(context, resVector); |
||||
if (drawable != null) { |
||||
return drawable2Bitmap(drawable); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/////////////// VectorDrawable /////////////////////
|
||||
|
||||
/** |
||||
* 获取支持RTL布局的drawable【如果是RTL布局就旋转180度】 |
||||
* |
||||
* @param src 原drawable |
||||
* @return |
||||
*/ |
||||
public static Drawable getSupportRTLDrawable(@NonNull Context context, Drawable src) { |
||||
return getSupportRTLDrawable(context, src, false); |
||||
} |
||||
|
||||
/** |
||||
* 获取支持RTL布局的drawable【如果是RTL布局就旋转180度】 |
||||
* |
||||
* @param context |
||||
* @param src 原drawable |
||||
* @return |
||||
*/ |
||||
public static Drawable getSupportRTLDrawable(@NonNull Context context, Drawable src, boolean recycle) { |
||||
if (ResUtils.isRtl(context)) { |
||||
return rotate(src, 180, 0, 0, recycle); |
||||
} |
||||
return src; |
||||
} |
||||
|
||||
/** |
||||
* Return the rotated drawable. |
||||
* |
||||
* @param src The source of drawable. |
||||
* @param degrees The number of degrees. |
||||
* @param px The x coordinate of the pivot point. |
||||
* @param py The y coordinate of the pivot point. |
||||
* @param recycle True to recycle the source of drawable, false otherwise. |
||||
* @return the rotated drawable |
||||
*/ |
||||
public static Drawable rotate(final Drawable src, |
||||
final int degrees, |
||||
final float px, |
||||
final float py, |
||||
final boolean recycle) { |
||||
return bitmap2Drawable(rotate(drawable2Bitmap(src), degrees, px, py, recycle)); |
||||
} |
||||
|
||||
/** |
||||
* Return the rotated bitmap. |
||||
* |
||||
* @param src The source of bitmap. |
||||
* @param degrees The number of degrees. |
||||
* @param px The x coordinate of the pivot point. |
||||
* @param py The y coordinate of the pivot point. |
||||
* @param recycle True to recycle the source of bitmap, false otherwise. |
||||
* @return the rotated bitmap |
||||
*/ |
||||
public static Bitmap rotate(final Bitmap src, |
||||
final int degrees, |
||||
final float px, |
||||
final float py, |
||||
final boolean recycle) { |
||||
if (isEmptyBitmap(src)) { |
||||
return null; |
||||
} |
||||
if (src.isRecycled()) { |
||||
return null; |
||||
} |
||||
if (degrees == 0) { |
||||
return src; |
||||
} |
||||
Matrix matrix = new Matrix(); |
||||
matrix.setRotate(degrees, px, py); |
||||
Bitmap ret = Bitmap.createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), matrix, true); |
||||
if (recycle && !src.isRecycled()) { |
||||
src.recycle(); |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
private static boolean isEmptyBitmap(final Bitmap src) { |
||||
return src == null || src.getWidth() == 0 || src.getHeight() == 0; |
||||
} |
||||
|
||||
/** |
||||
* 获取图片 |
||||
* |
||||
* @param context 上下文 |
||||
* @param resId 图片资源 |
||||
* @return 图片 |
||||
*/ |
||||
public static Bitmap getBitmapByDrawableId(Context context, @DrawableRes int resId) { |
||||
return drawable2Bitmap(ResUtils.getDrawable(context, resId)); |
||||
} |
||||
|
||||
/** |
||||
* Drawable to bitmap. |
||||
* |
||||
* @param drawable The drawable. |
||||
* @return bitmap |
||||
*/ |
||||
public static Bitmap drawable2Bitmap(final Drawable drawable) { |
||||
if (drawable == null) { |
||||
return null; |
||||
} |
||||
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(ResUtils.getResources(), bitmap); |
||||
} |
||||
} |
@ -0,0 +1,525 @@ |
||||
/* |
||||
* Copyright (C) 2018 xuexiangjys(xuexiangjys@163.com) |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
package com.project.survey.util; |
||||
|
||||
import android.app.Activity; |
||||
import android.app.Dialog; |
||||
import android.content.Context; |
||||
import android.content.DialogInterface; |
||||
import android.graphics.Rect; |
||||
import android.os.Build; |
||||
import android.view.KeyEvent; |
||||
import android.view.MotionEvent; |
||||
import android.view.View; |
||||
import android.view.ViewGroup; |
||||
import android.view.ViewTreeObserver; |
||||
import android.view.Window; |
||||
import android.view.WindowManager; |
||||
import android.view.inputmethod.InputMethodManager; |
||||
import android.widget.EditText; |
||||
|
||||
import androidx.annotation.NonNull; |
||||
|
||||
import com.project.survey.App; |
||||
|
||||
import java.lang.reflect.Field; |
||||
import java.util.HashMap; |
||||
|
||||
/** |
||||
* 软键盘工具 |
||||
* |
||||
* @author xuexiang |
||||
* @since 2019/1/14 下午10:04 |
||||
*/ |
||||
public class KeyboardUtils implements ViewTreeObserver.OnGlobalLayoutListener { |
||||
|
||||
private SoftKeyboardToggleListener mCallback; |
||||
private ViewGroup mRootView; |
||||
private Boolean prevValue = null; |
||||
private static HashMap<SoftKeyboardToggleListener, KeyboardUtils> sListenerMap = new HashMap<>(); |
||||
|
||||
public interface SoftKeyboardToggleListener { |
||||
/** |
||||
* 键盘显示状态监听回调 |
||||
* |
||||
* @param isVisible 键盘是否显示 |
||||
*/ |
||||
void onToggleSoftKeyboard(boolean isVisible); |
||||
} |
||||
|
||||
@Override |
||||
public void onGlobalLayout() { |
||||
boolean isVisible = isSoftInputShow(mRootView); |
||||
if (mCallback != null && (prevValue == null || isVisible != prevValue)) { |
||||
prevValue = isVisible; |
||||
mCallback.onToggleSoftKeyboard(isVisible); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Add a new keyboard listener |
||||
* |
||||
* @param act calling activity |
||||
* @param listener callback |
||||
*/ |
||||
public static void addKeyboardToggleListener(Activity act, SoftKeyboardToggleListener listener) { |
||||
removeKeyboardToggleListener(listener); |
||||
sListenerMap.put(listener, new KeyboardUtils(act, listener)); |
||||
} |
||||
|
||||
/** |
||||
* Add a new keyboard listener |
||||
* |
||||
* @param act calling activity |
||||
* @param listener callback |
||||
*/ |
||||
public static void addKeyboardToggleListener(ViewGroup act, SoftKeyboardToggleListener listener) { |
||||
removeKeyboardToggleListener(listener); |
||||
sListenerMap.put(listener, new KeyboardUtils(act, listener)); |
||||
} |
||||
|
||||
/** |
||||
* Remove a registered listener |
||||
* |
||||
* @param listener {@link SoftKeyboardToggleListener} |
||||
*/ |
||||
public static void removeKeyboardToggleListener(SoftKeyboardToggleListener listener) { |
||||
if (sListenerMap.containsKey(listener)) { |
||||
KeyboardUtils k = sListenerMap.get(listener); |
||||
if (k != null) { |
||||
k.removeListener(); |
||||
} |
||||
sListenerMap.remove(listener); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Remove all registered keyboard listeners |
||||
*/ |
||||
public static void removeAllKeyboardToggleListeners() { |
||||
for (SoftKeyboardToggleListener l : sListenerMap.keySet()) { |
||||
KeyboardUtils k = sListenerMap.get(l); |
||||
if (k != null) { |
||||
k.removeListener(); |
||||
} |
||||
} |
||||
sListenerMap.clear(); |
||||
} |
||||
|
||||
/** |
||||
* Manually toggle soft keyboard visibility |
||||
* |
||||
* @param context calling context |
||||
*/ |
||||
public static void toggleKeyboardVisibility(Context context) { |
||||
InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); |
||||
inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); |
||||
} |
||||
|
||||
/** |
||||
* Force closes the soft keyboard |
||||
* |
||||
* @param activeView the view with the keyboard focus |
||||
*/ |
||||
public static void forceCloseKeyboard(View activeView) { |
||||
InputMethodManager inputMethodManager = (InputMethodManager) activeView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); |
||||
inputMethodManager.hideSoftInputFromWindow(activeView.getWindowToken(), 0); |
||||
} |
||||
|
||||
private void removeListener() { |
||||
mCallback = null; |
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { |
||||
mRootView.getViewTreeObserver().removeOnGlobalLayoutListener(this); |
||||
} else { |
||||
mRootView.getViewTreeObserver().removeGlobalOnLayoutListener(this); |
||||
} |
||||
} |
||||
|
||||
private KeyboardUtils(Activity activity, SoftKeyboardToggleListener listener) { |
||||
mCallback = listener; |
||||
mRootView = (ViewGroup) activity.getWindow().getDecorView(); |
||||
mRootView.getViewTreeObserver().addOnGlobalLayoutListener(this); |
||||
} |
||||
|
||||
private KeyboardUtils(ViewGroup viewGroup, SoftKeyboardToggleListener listener) { |
||||
mCallback = listener; |
||||
mRootView = viewGroup; |
||||
mRootView.getViewTreeObserver().addOnGlobalLayoutListener(this); |
||||
} |
||||
|
||||
/** |
||||
* 软键盘以覆盖当前界面的形式出现 |
||||
* |
||||
* @param activity |
||||
*/ |
||||
public static void setSoftInputAdjustNothing(@NonNull Activity activity) { |
||||
activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING |
||||
| WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); |
||||
} |
||||
|
||||
/** |
||||
* 软键盘以顶起当前界面的形式出现, 注意这种方式会使得当前布局的高度发生变化,触发当前布局onSizeChanged方法回调,这里前后高度差就是软键盘的高度了 |
||||
* |
||||
* @param activity |
||||
*/ |
||||
public static void setSoftInputAdjustResize(@NonNull Activity activity) { |
||||
activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE |
||||
| WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); |
||||
} |
||||
|
||||
/** |
||||
* 软键盘以上推当前界面的形式出现, 注意这种方式不会改变布局的高度 |
||||
* |
||||
* @param activity |
||||
*/ |
||||
public static void setSoftInputAdjustPan(@NonNull Activity activity) { |
||||
activity.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN |
||||
| WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 输入键盘是否在显示 |
||||
* |
||||
* @param activity 应用窗口 |
||||
*/ |
||||
public static boolean isSoftInputShow(Activity activity) { |
||||
return activity != null && isSoftInputShow(activity.getWindow()); |
||||
} |
||||
|
||||
/** |
||||
* 输入键盘是否在显示 |
||||
* |
||||
* @param window 应用窗口 |
||||
*/ |
||||
public static boolean isSoftInputShow(Window window) { |
||||
if (window != null && window.getDecorView() instanceof ViewGroup) { |
||||
return isSoftInputShow((ViewGroup) window.getDecorView()); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* 输入键盘是否在显示 |
||||
* |
||||
* @param rootView 根布局 |
||||
*/ |
||||
public static boolean isSoftInputShow(ViewGroup rootView) { |
||||
if (rootView == null) { |
||||
return false; |
||||
} |
||||
int viewHeight = rootView.getHeight(); |
||||
//获取View可见区域的bottom
|
||||
Rect rect = new Rect(); |
||||
rootView.getWindowVisibleDisplayFrame(rect); |
||||
int space = viewHeight - rect.bottom - DensityUtils.getNavigationBarHeight(rootView.getContext()); |
||||
return space > 0; |
||||
} |
||||
|
||||
/** |
||||
* 禁用物理返回键 |
||||
* <p> |
||||
* 使用方法: |
||||
* <p>需重写 onKeyDown</p> |
||||
* |
||||
* @param keyCode |
||||
* @return 是否拦截事件 |
||||
* <p> |
||||
* @Override public boolean onKeyDown(int keyCode, KeyEvent event) { |
||||
* return KeyboardUtils.onDisableBackKeyDown(keyCode) && super.onKeyDown(keyCode, event); |
||||
* } |
||||
* </p> |
||||
*/ |
||||
public static boolean onDisableBackKeyDown(int keyCode) { |
||||
switch (keyCode) { |
||||
case KeyEvent.KEYCODE_BACK: |
||||
case KeyEvent.KEYCODE_HOME: |
||||
return false; |
||||
default: |
||||
break; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 点击屏幕空白区域隐藏软键盘 |
||||
* <p>根据 EditText 所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘</p> |
||||
* <p>需重写 dispatchTouchEvent</p> |
||||
* |
||||
* @param ev 点击事件 |
||||
* @param activity 窗口 |
||||
*/ |
||||
public static void dispatchTouchEvent(MotionEvent ev, @NonNull Activity activity) { |
||||
dispatchTouchEvent(ev, activity.getWindow()); |
||||
} |
||||
|
||||
/** |
||||
* 点击屏幕空白区域隐藏软键盘 |
||||
* <p>根据 EditText 所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘</p> |
||||
* <p>需重写 dispatchTouchEvent</p> |
||||
* |
||||
* @param ev 点击事件 |
||||
* @param dialog 窗口 |
||||
*/ |
||||
public static void dispatchTouchEvent(MotionEvent ev, @NonNull Dialog dialog) { |
||||
dispatchTouchEvent(ev, dialog.getWindow()); |
||||
} |
||||
|
||||
/** |
||||
* 点击屏幕空白区域隐藏软键盘 |
||||
* <p>根据 EditText 所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘</p> |
||||
* <p>需重写 dispatchTouchEvent</p> |
||||
* |
||||
* @param ev 点击事件 |
||||
* @param window 窗口 |
||||
*/ |
||||
public static void dispatchTouchEvent(MotionEvent ev, Window window) { |
||||
if (ev == null || window == null) { |
||||
return; |
||||
} |
||||
if (ev.getAction() == MotionEvent.ACTION_DOWN) { |
||||
if (isShouldHideKeyboard(window, ev)) { |
||||
hideSoftInputClearFocus(window.getCurrentFocus()); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 根据 EditText 所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘 |
||||
* |
||||
* @param view 窗口 |
||||
* @param event 用户点击事件 |
||||
* @return 是否隐藏键盘 |
||||
*/ |
||||
public static boolean isShouldHideKeyboard(View view, MotionEvent event) { |
||||
if ((view instanceof EditText) && event != null) { |
||||
return !isTouchView(view, event); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* 根据用户点击的坐标获取用户在窗口上触摸到的View,判断这个View是否是EditText来判断是否隐藏键盘 |
||||
* |
||||
* @param window 窗口 |
||||
* @param event 用户点击事件 |
||||
* @return 是否隐藏键盘 |
||||
*/ |
||||
public static boolean isShouldHideKeyboard(Window window, MotionEvent event) { |
||||
if (window == null || event == null) { |
||||
return false; |
||||
} |
||||
if (!isSoftInputShow(window)) { |
||||
return false; |
||||
} |
||||
if (!(window.getCurrentFocus() instanceof EditText)) { |
||||
return false; |
||||
} |
||||
View decorView = window.getDecorView(); |
||||
if (decorView instanceof ViewGroup) { |
||||
return findTouchEditText((ViewGroup) decorView, event) == null; |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
private static View findTouchEditText(ViewGroup viewGroup, MotionEvent event) { |
||||
if (viewGroup == null) { |
||||
return null; |
||||
} |
||||
for (int i = 0; i < viewGroup.getChildCount(); i++) { |
||||
View child = viewGroup.getChildAt(i); |
||||
if (child == null || !child.isShown()) { |
||||
continue; |
||||
} |
||||
if (!isTouchView(child, event)) { |
||||
continue; |
||||
} |
||||
if (child instanceof EditText) { |
||||
return child; |
||||
} else if (child instanceof ViewGroup) { |
||||
return findTouchEditText((ViewGroup) child, event); |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* 判断view是否在触摸区域内 |
||||
* |
||||
* @param view view |
||||
* @param event 点击事件 |
||||
* @return view是否在触摸区域内 |
||||
*/ |
||||
private static boolean isTouchView(View view, MotionEvent event) { |
||||
if (view == null || event == null) { |
||||
return false; |
||||
} |
||||
int[] location = new int[2]; |
||||
view.getLocationOnScreen(location); |
||||
int left = location[0]; |
||||
int top = location[1]; |
||||
int right = left + view.getMeasuredWidth(); |
||||
int bottom = top + view.getMeasuredHeight(); |
||||
return event.getY() >= top && event.getY() <= bottom && event.getX() >= left |
||||
&& event.getX() <= right; |
||||
} |
||||
|
||||
/** |
||||
* 动态隐藏软键盘 |
||||
* |
||||
* @param view 视图 |
||||
*/ |
||||
public static void hideSoftInput(final View view) { |
||||
if (view == null) { |
||||
return; |
||||
} |
||||
InputMethodManager imm = |
||||
(InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); |
||||
if (imm == null) { |
||||
return; |
||||
} |
||||
imm.hideSoftInputFromWindow(view.getWindowToken(), 0); |
||||
} |
||||
|
||||
/** |
||||
* 动态隐藏弹窗弹出的软键盘【注意:一定要在dialog.dismiss之前调用】 |
||||
* |
||||
* @param dialog 对话框 |
||||
*/ |
||||
public static void hideSoftInput(@NonNull DialogInterface dialog) { |
||||
if (dialog instanceof Dialog) { |
||||
hideSoftInput((Dialog) dialog); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 动态隐藏弹窗弹出的软键盘【注意:一定要在dialog.dismiss之前调用】 |
||||
* |
||||
* @param dialog 对话框 |
||||
*/ |
||||
public static void hideSoftInput(@NonNull Dialog dialog) { |
||||
View view = dialog.getCurrentFocus(); |
||||
if (view == null && dialog.getWindow() != null) { |
||||
view = dialog.getWindow().getDecorView(); |
||||
} |
||||
hideSoftInput(view); |
||||
} |
||||
|
||||
/** |
||||
* 动态隐藏软键盘并且清除当前view的焦点【记住,要在xml的父布局加上android:focusable="true" 和 android:focusableInTouchMode="true"】 |
||||
* |
||||
* @param view 视图 |
||||
*/ |
||||
public static void hideSoftInputClearFocus(final View view) { |
||||
if (view == null) { |
||||
return; |
||||
} |
||||
InputMethodManager imm = |
||||
(InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); |
||||
if (imm == null) { |
||||
return; |
||||
} |
||||
imm.hideSoftInputFromWindow(view.getWindowToken(), 0); |
||||
if (view instanceof EditText) { |
||||
view.clearFocus(); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 切换软键盘显示与否状态 |
||||
*/ |
||||
public static void toggleSoftInput() { |
||||
InputMethodManager imm = |
||||
(InputMethodManager) App.getApp().getSystemService(Context.INPUT_METHOD_SERVICE); |
||||
if (imm == null) { |
||||
return; |
||||
} |
||||
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 强制显示软键盘 |
||||
* |
||||
* @param activity 活动窗口 |
||||
*/ |
||||
public static void showSoftInputForce(Activity activity) { |
||||
if (!isSoftInputShow(activity)) { |
||||
toggleSoftInput(); |
||||
} |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 显示软键盘 |
||||
* |
||||
* @param view 可输入控件,并且在焦点上方可显示 |
||||
*/ |
||||
public static void showSoftInput(final EditText view) { |
||||
if (view == null) { |
||||
return; |
||||
} |
||||
InputMethodManager imm = |
||||
(InputMethodManager) view.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); |
||||
if (imm == null) { |
||||
return; |
||||
} |
||||
imm.showSoftInput(view, InputMethodManager.SHOW_FORCED); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 修复软键盘内存泄漏 |
||||
* |
||||
* @param context context |
||||
*/ |
||||
public static void fixSoftInputLeaks(final Context context) { |
||||
if (context == null) { |
||||
return; |
||||
} |
||||
InputMethodManager imm = |
||||
(InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); |
||||
if (imm == null) { |
||||
return; |
||||
} |
||||
String[] strArr = new String[]{"mCurRootView", "mServedView", "mNextServedView"}; |
||||
for (String s : strArr) { |
||||
try { |
||||
Field declaredField = imm.getClass().getDeclaredField(s); |
||||
if (!declaredField.isAccessible()) { |
||||
declaredField.setAccessible(true); |
||||
} |
||||
Object obj = declaredField.get(imm); |
||||
if (!(obj instanceof View)) { |
||||
continue; |
||||
} |
||||
View view = (View) obj; |
||||
if (view.getContext() == context) { |
||||
declaredField.set(imm, null); |
||||
} else { |
||||
return; |
||||
} |
||||
} catch (Throwable th) { |
||||
th.printStackTrace(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,447 @@ |
||||
package com.project.survey.util; |
||||
|
||||
import android.content.Context; |
||||
import android.content.res.ColorStateList; |
||||
import android.content.res.Resources; |
||||
import android.content.res.TypedArray; |
||||
import android.graphics.Color; |
||||
import android.graphics.drawable.Drawable; |
||||
import android.os.Build; |
||||
import android.view.View; |
||||
import android.view.animation.Animation; |
||||
import android.view.animation.AnimationUtils; |
||||
|
||||
import androidx.annotation.AnimRes; |
||||
import androidx.annotation.ArrayRes; |
||||
import androidx.annotation.ColorRes; |
||||
import androidx.annotation.DimenRes; |
||||
import androidx.annotation.DrawableRes; |
||||
import androidx.annotation.NonNull; |
||||
import androidx.annotation.StringRes; |
||||
import androidx.annotation.StyleableRes; |
||||
import androidx.appcompat.content.res.AppCompatResources; |
||||
import androidx.core.content.ContextCompat; |
||||
|
||||
import com.project.survey.App; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Arrays; |
||||
import java.util.List; |
||||
|
||||
/** |
||||
* 获取res中的资源 |
||||
* |
||||
* @author xuexiang |
||||
* @since 2018/12/18 上午12:14 |
||||
*/ |
||||
public final class ResUtils { |
||||
|
||||
private ResUtils() { |
||||
throw new UnsupportedOperationException("u can't instantiate me..."); |
||||
} |
||||
|
||||
/** |
||||
* 获取resources对象 |
||||
* |
||||
* @return resources对象 |
||||
*/ |
||||
@Deprecated |
||||
public static Resources getResources() { |
||||
return App.getApp().getResources(); |
||||
} |
||||
|
||||
/** |
||||
* 获取resources对象 |
||||
* |
||||
* @param context 上下文 |
||||
* @return resources对象 |
||||
*/ |
||||
public static Resources getResources(@NonNull Context context) { |
||||
return context.getResources(); |
||||
} |
||||
|
||||
/** |
||||
* 获取字符串 |
||||
* |
||||
* @param resId 资源id |
||||
* @return 字符串 |
||||
*/ |
||||
@Deprecated |
||||
public static String getString(@StringRes int resId) { |
||||
return getResources().getString(resId); |
||||
} |
||||
|
||||
/** |
||||
* 获取字符串 |
||||
* |
||||
* @param context 上下文 |
||||
* @param resId 资源id |
||||
* @return 字符串 |
||||
*/ |
||||
public static String getString(@NonNull Context context, @StringRes int resId) { |
||||
return context.getResources().getString(resId); |
||||
} |
||||
|
||||
/** |
||||
* 获取资源图片 |
||||
* |
||||
* @param resId 图片资源id |
||||
* @return 资源图片 |
||||
*/ |
||||
@Deprecated |
||||
public static Drawable getDrawable(@DrawableRes int resId) { |
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
||||
return App.getApp().getDrawable(resId); |
||||
} |
||||
return getResources().getDrawable(resId); |
||||
} |
||||
|
||||
/** |
||||
* 获取资源图片【和主题有关】 |
||||
* |
||||
* @param resId 图片资源id |
||||
* @return 资源图片 |
||||
*/ |
||||
public static Drawable getDrawable(Context context, @DrawableRes int resId) { |
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
||||
return context.getDrawable(resId); |
||||
} |
||||
return AppCompatResources.getDrawable(context, resId); |
||||
} |
||||
|
||||
/** |
||||
* 获取svg资源图片 |
||||
* |
||||
* @param context 上下文 |
||||
* @param resId 图片资源id |
||||
* @return svg资源图片 |
||||
*/ |
||||
public static Drawable getVectorDrawable(Context context, @DrawableRes int resId) { |
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
||||
return context.getDrawable(resId); |
||||
} |
||||
return AppCompatResources.getDrawable(context, resId); |
||||
} |
||||
|
||||
/** |
||||
* 获取Drawable属性(兼容VectorDrawable) |
||||
* |
||||
* @param context 上下文 |
||||
* @param typedArray 样式属性数组 |
||||
* @param styleableResId 样式资源ID |
||||
* @return Drawable |
||||
*/ |
||||
public static Drawable getDrawableAttrRes(Context context, TypedArray typedArray, @StyleableRes int styleableResId) { |
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
||||
return typedArray.getDrawable(styleableResId); |
||||
} else { |
||||
int resourceId = typedArray.getResourceId(styleableResId, -1); |
||||
if (resourceId != -1) { |
||||
return AppCompatResources.getDrawable(context, resourceId); |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* 获取ColorStateList属性(兼容?attr属性) |
||||
* |
||||
* @param context 上下文 |
||||
* @param typedArray 样式属性数组 |
||||
* @param styleableResId 样式资源ID |
||||
* @return ColorStateList |
||||
*/ |
||||
public static ColorStateList getColorStateListAttrRes(Context context, TypedArray typedArray, @StyleableRes int styleableResId) { |
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { |
||||
return typedArray.getColorStateList(styleableResId); |
||||
} else { |
||||
int resourceId = typedArray.getResourceId(styleableResId, -1); |
||||
if (resourceId != -1) { |
||||
return AppCompatResources.getColorStateList(context, resourceId); |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* 获取dimes值,返回的是精确的值 |
||||
* |
||||
* @param resId 资源id |
||||
* @return dimes值,返回的是精确的值 |
||||
*/ |
||||
@Deprecated |
||||
public static float getDimens(@DimenRes int resId) { |
||||
return getResources().getDimension(resId); |
||||
} |
||||
|
||||
/** |
||||
* 获取dimes值,返回的是精确的值 |
||||
* |
||||
* @param context 上下文 |
||||
* @param resId 资源id |
||||
* @return dimes值,返回的是精确的值 |
||||
*/ |
||||
public static float getDimens(@NonNull Context context, @DimenRes int resId) { |
||||
return context.getResources().getDimension(resId); |
||||
} |
||||
|
||||
/** |
||||
* 获取Color值 |
||||
* |
||||
* @param resId 资源id |
||||
* @return Color值 |
||||
*/ |
||||
@Deprecated |
||||
public static int getColor(@ColorRes int resId) { |
||||
return getResources().getColor(resId); |
||||
} |
||||
|
||||
/** |
||||
* 获取Color值 |
||||
* |
||||
* @param context 上下文 |
||||
* @param resId 资源id |
||||
* @return Color值 |
||||
*/ |
||||
public static int getColor(@NonNull Context context, @ColorRes int resId) { |
||||
return ContextCompat.getColor(context, resId); |
||||
} |
||||
|
||||
/** |
||||
* 获取ColorStateList值 |
||||
* |
||||
* @param resId 资源id |
||||
* @return ColorStateList值 |
||||
*/ |
||||
@Deprecated |
||||
public static ColorStateList getColors(@ColorRes int resId) { |
||||
return getResources().getColorStateList(resId); |
||||
} |
||||
|
||||
/** |
||||
* 获取ColorStateList值 |
||||
* |
||||
* @param context 上下文 |
||||
* @param resId 资源id |
||||
* @return ColorStateList值 |
||||
*/ |
||||
public static ColorStateList getColors(@NonNull Context context, @ColorRes int resId) { |
||||
return ContextCompat.getColorStateList(context, resId); |
||||
} |
||||
|
||||
/** |
||||
* 获取dimes值,返回的是【去余取整】的值 |
||||
* |
||||
* @param resId 资源id |
||||
* @return dimes值【去余取整】 |
||||
*/ |
||||
@Deprecated |
||||
public static int getDimensionPixelOffset(@DimenRes int resId) { |
||||
return getResources().getDimensionPixelOffset(resId); |
||||
} |
||||
|
||||
/** |
||||
* 获取dimes值,返回的是【去余取整】的值 |
||||
* |
||||
* @param context 上下文 |
||||
* @param resId 资源id |
||||
* @return dimes值【去余取整】 |
||||
*/ |
||||
public static int getDimensionPixelOffset(@NonNull Context context, @DimenRes int resId) { |
||||
return context.getResources().getDimensionPixelOffset(resId); |
||||
} |
||||
|
||||
/** |
||||
* 获取dimes值,返回的是【4舍5入取整】的值 |
||||
* |
||||
* @param resId 资源id |
||||
* @return dimes值【4舍5入取整】 |
||||
*/ |
||||
@Deprecated |
||||
public static int getDimensionPixelSize(@DimenRes int resId) { |
||||
return getResources().getDimensionPixelSize(resId); |
||||
} |
||||
|
||||
/** |
||||
* 获取dimes值,返回的是【4舍5入取整】的值 |
||||
* |
||||
* @param context 上下文 |
||||
* @param resId 资源id |
||||
* @return dimes值【4舍5入取整】 |
||||
*/ |
||||
public static int getDimensionPixelSize(@NonNull Context context, @DimenRes int resId) { |
||||
return context.getResources().getDimensionPixelSize(resId); |
||||
} |
||||
|
||||
/** |
||||
* 获取字符串的数组 |
||||
* |
||||
* @param resId 资源id |
||||
* @return 字符串的数组 |
||||
*/ |
||||
@Deprecated |
||||
public static String[] getStringArray(@ArrayRes int resId) { |
||||
return getResources().getStringArray(resId); |
||||
} |
||||
|
||||
/** |
||||
* 获取字符串的数组 |
||||
* |
||||
* @param context 上下文 |
||||
* @param resId 资源id |
||||
* @return 字符串的数组 |
||||
*/ |
||||
public static String[] getStringArray(Context context, @ArrayRes int resId) { |
||||
return context.getResources().getStringArray(resId); |
||||
} |
||||
|
||||
/** |
||||
* 获取字符串的集合 |
||||
* |
||||
* @param context 上下文 |
||||
* @param resId 资源id |
||||
* @return 字符串的集合 |
||||
*/ |
||||
@NonNull |
||||
public static List<String> getStringList(@NonNull Context context, int resId) { |
||||
return getStringList(context, resId, 0); |
||||
} |
||||
|
||||
/** |
||||
* 获取字符串的集合 |
||||
* |
||||
* @param context 上下文 |
||||
* @param resId 资源id |
||||
* @param emptyId 空资源id |
||||
* @return 字符串的集合 |
||||
*/ |
||||
@NonNull |
||||
public static List<String> getStringList(@NonNull Context context, int resId, int emptyId) { |
||||
List<String> data = new ArrayList<>(); |
||||
if (resId == emptyId) { |
||||
return data; |
||||
} |
||||
String[] array = context.getResources().getStringArray(resId); |
||||
if (array.length > 0) { |
||||
data.addAll(Arrays.asList(array)); |
||||
} |
||||
return data; |
||||
} |
||||
|
||||
/** |
||||
* 获取Drawable的数组 |
||||
* |
||||
* @param context context |
||||
* @param resId 资源id |
||||
* @return Drawable的数组 |
||||
*/ |
||||
public static Drawable[] getDrawableArray(Context context, @ArrayRes int resId) { |
||||
TypedArray ta = getResources().obtainTypedArray(resId); |
||||
Drawable[] icons = new Drawable[ta.length()]; |
||||
for (int i = 0; i < ta.length(); i++) { |
||||
int id = ta.getResourceId(i, 0); |
||||
if (id != 0) { |
||||
icons[i] = ContextCompat.getDrawable(context, id); |
||||
} |
||||
} |
||||
ta.recycle(); |
||||
return icons; |
||||
} |
||||
|
||||
/** |
||||
* 获取数字的数组 |
||||
* |
||||
* @param resId 数组资源id |
||||
* @return 数字的数组 |
||||
*/ |
||||
@Deprecated |
||||
public static int[] getIntArray(@ArrayRes int resId) { |
||||
return getResources().getIntArray(resId); |
||||
} |
||||
|
||||
/** |
||||
* 获取数字的数组 |
||||
* |
||||
* @param context 上下文 |
||||
* @param resId 数组资源id |
||||
* @return 数字的数组 |
||||
*/ |
||||
public static int[] getIntArray(@NonNull Context context, @ArrayRes int resId) { |
||||
return context.getResources().getIntArray(resId); |
||||
} |
||||
|
||||
/** |
||||
* 获取动画 |
||||
* |
||||
* @param resId 动画资源id |
||||
* @return 动画 |
||||
*/ |
||||
@Deprecated |
||||
public static Animation getAnim(@AnimRes int resId) { |
||||
return AnimationUtils.loadAnimation(App.getApp(), resId); |
||||
} |
||||
|
||||
/** |
||||
* 获取动画 |
||||
* |
||||
* @param context 上下文 |
||||
* @param resId 动画资源id |
||||
* @return 动画 |
||||
*/ |
||||
public static Animation getAnim(@NonNull Context context, @AnimRes int resId) { |
||||
return AnimationUtils.loadAnimation(context, resId); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Check if layout direction is RTL |
||||
* |
||||
* @return {@code true} if the layout direction is right-to-left |
||||
*/ |
||||
@Deprecated |
||||
public static boolean isRtl() { |
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && |
||||
getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Check if layout direction is RTL |
||||
* |
||||
* @param context context |
||||
* @return {@code true} if the layout direction is right-to-left |
||||
*/ |
||||
public static boolean isRtl(@NonNull Context context) { |
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && |
||||
context.getResources().getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; |
||||
} |
||||
|
||||
/** |
||||
* Darkens a color by a given factor. |
||||
* |
||||
* @param color the color to darken |
||||
* @param factor The factor to darken the color. |
||||
* @return darker version of specified color. |
||||
*/ |
||||
public static int darker(int color, float factor) { |
||||
return Color.argb(Color.alpha(color), Math.max((int) (Color.red(color) * factor), 0), |
||||
Math.max((int) (Color.green(color) * factor), 0), |
||||
Math.max((int) (Color.blue(color) * factor), 0)); |
||||
} |
||||
|
||||
/** |
||||
* Lightens a color by a given factor. |
||||
* |
||||
* @param color The color to lighten |
||||
* @param factor The factor to lighten the color. 0 will make the color unchanged. 1 will make the |
||||
* color white. |
||||
* @return lighter version of the specified color. |
||||
*/ |
||||
public static int lighter(int color, float factor) { |
||||
int red = (int) ((Color.red(color) * (1 - factor) / 255 + factor) * 255); |
||||
int green = (int) ((Color.green(color) * (1 - factor) / 255 + factor) * 255); |
||||
int blue = (int) ((Color.blue(color) * (1 - factor) / 255 + factor) * 255); |
||||
return Color.argb(Color.alpha(color), red, green, blue); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,734 @@ |
||||
package com.project.survey.util; |
||||
|
||||
import static android.os.Build.VERSION_CODES.HONEYCOMB; |
||||
import static android.os.Build.VERSION_CODES.KITKAT; |
||||
|
||||
import android.annotation.TargetApi; |
||||
import android.app.Activity; |
||||
import android.app.Dialog; |
||||
import android.content.Context; |
||||
import android.graphics.Color; |
||||
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.annotation.ColorInt; |
||||
import androidx.annotation.IntDef; |
||||
import androidx.core.view.ViewCompat; |
||||
|
||||
import com.project.survey.widget.util.Utils; |
||||
|
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
import java.lang.reflect.Field; |
||||
import java.lang.reflect.Method; |
||||
|
||||
/** |
||||
* 状态栏工具 |
||||
* |
||||
* @author XUE |
||||
* @since 2019/3/22 10:50 |
||||
*/ |
||||
public class StatusBarUtils { |
||||
|
||||
private final static int STATUSBAR_TYPE_DEFAULT = 0; |
||||
private final static int STATUSBAR_TYPE_MIUI = 1; |
||||
private final static int STATUSBAR_TYPE_FLYME = 2; |
||||
private final static int STATUSBAR_TYPE_ANDROID6 = 3; // Android 6.0
|
||||
private final static int STATUS_BAR_DEFAULT_HEIGHT_DP = 25; // 大部分状态栏都是25dp
|
||||
// 在某些机子上存在不同的density值,所以增加两个虚拟值
|
||||
public static float sVirtualDensity = -1; |
||||
public static float sVirtualDensityDpi = -1; |
||||
private static int sStatusbarHeight = -1; |
||||
private static @StatusBarType |
||||
int mStatusBarType = STATUSBAR_TYPE_DEFAULT; |
||||
private static Integer sTransparentValue; |
||||
|
||||
public static void translucent(Activity activity) { |
||||
translucent(activity.getWindow()); |
||||
} |
||||
|
||||
public static void translucent(Window window) { |
||||
translucent(window, 0x40000000); |
||||
} |
||||
|
||||
private static boolean supportTranslucent() { |
||||
return Build.VERSION.SDK_INT >= KITKAT |
||||
// Essential Phone 在 Android 8 之前沉浸式做得不全,系统不从状态栏顶部开始布局却会下发 WindowInsets
|
||||
&& !(DeviceUtils.isEssentialPhone() && Build.VERSION.SDK_INT < 26); |
||||
} |
||||
|
||||
private StatusBarUtils() { |
||||
throw new UnsupportedOperationException("u can't instantiate me..."); |
||||
} |
||||
|
||||
/** |
||||
* 设置沉浸式状态栏样式 |
||||
* |
||||
* @param activity |
||||
* @param isDark 是否是深色的状态栏 |
||||
*/ |
||||
public static void initStatusBarStyle(Activity activity, boolean isDark) { |
||||
initStatusBarStyle(activity, isDark, Color.TRANSPARENT); |
||||
} |
||||
|
||||
/** |
||||
* 设置沉浸式状态栏样式 |
||||
* |
||||
* @param activity |
||||
* @param isDark 是否是深色的状态栏 |
||||
* @param colorOn5x 颜色 |
||||
*/ |
||||
public static void initStatusBarStyle(Activity activity, boolean isDark, @ColorInt int colorOn5x) { |
||||
//设置沉浸式状态栏的颜色
|
||||
translucent(activity, colorOn5x); |
||||
//修改状态栏的字体颜色
|
||||
if (isDark) { |
||||
setStatusBarDarkMode(activity); |
||||
} else { |
||||
setStatusBarLightMode(activity); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 沉浸式状态栏。 |
||||
* 支持 4.4 以上版本的 MIUI 和 Flyme,以及 5.0 以上版本的其他 Android。 |
||||
* |
||||
* @param activity 需要被设置沉浸式状态栏的 Activity。 |
||||
*/ |
||||
public static void translucent(Activity activity, @ColorInt int colorOn5x) { |
||||
Window window = activity.getWindow(); |
||||
translucent(window, colorOn5x); |
||||
} |
||||
|
||||
@TargetApi(Build.VERSION_CODES.KITKAT) |
||||
public static void translucent(Window window, @ColorInt int colorOn5x) { |
||||
if (!supportTranslucent()) { |
||||
// 版本小于4.4,绝对不考虑沉浸式
|
||||
return; |
||||
} |
||||
|
||||
if (isNotchOfficialSupport()) { |
||||
handleDisplayCutoutMode(window); |
||||
} |
||||
|
||||
// 小米和魅族4.4 以上版本支持沉浸式
|
||||
// 小米 Android 6.0 ,开发版 7.7.13 及以后版本设置黑色字体又需要 clear FLAG_TRANSLUCENT_STATUS, 因此还原为官方模式
|
||||
if (DeviceUtils.isMeizu() || (DeviceUtils.isMIUI() && Build.VERSION.SDK_INT < Build.VERSION_CODES.M)) { |
||||
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, |
||||
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); |
||||
return; |
||||
} |
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
||||
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
||||
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE); |
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && supportTransclentStatusBar6()) { |
||||
// android 6以后可以改状态栏字体颜色,因此可以自行设置为透明
|
||||
// ZUK Z1是个另类,自家应用可以实现字体颜色变色,但没开放接口
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); |
||||
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); |
||||
window.setStatusBarColor(Color.TRANSPARENT); |
||||
} else { |
||||
// android 5不能修改状态栏字体颜色,因此直接用FLAG_TRANSLUCENT_STATUS,nexus表现为半透明
|
||||
// 魅族和小米的表现如何?
|
||||
// update: 部分手机运用FLAG_TRANSLUCENT_STATUS时背景不是半透明而是没有背景了。。。。。
|
||||
// window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
|
||||
|
||||
// 采取setStatusBarColor的方式,部分机型不支持,那就纯黑了,保证状态栏图标可见
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); |
||||
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); |
||||
window.setStatusBarColor(colorOn5x); |
||||
} |
||||
// } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
// // android4.4的默认是从上到下黑到透明,我们的背景是白色,很难看,因此只做魅族和小米的
|
||||
// } else if(Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR1){
|
||||
// // 如果app 为白色,需要更改状态栏颜色,因此不能让19一下支持透明状态栏
|
||||
// Window window = activity.getWindow();
|
||||
// Integer transparentValue = getStatusBarAPITransparentValue(activity);
|
||||
// if(transparentValue != null) {
|
||||
// window.getDecorView().setSystemUiVisibility(transparentValue);
|
||||
// }
|
||||
} |
||||
} |
||||
|
||||
public static boolean isNotchOfficialSupport() { |
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.P; |
||||
} |
||||
|
||||
@TargetApi(Build.VERSION_CODES.P) |
||||
private static void handleDisplayCutoutMode(final Window window) { |
||||
View decorView = window.getDecorView(); |
||||
if (decorView != null) { |
||||
if (ViewCompat.isAttachedToWindow(decorView)) { |
||||
realHandleDisplayCutoutMode(window, decorView); |
||||
} else { |
||||
decorView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() { |
||||
@Override |
||||
public void onViewAttachedToWindow(View v) { |
||||
v.removeOnAttachStateChangeListener(this); |
||||
realHandleDisplayCutoutMode(window, v); |
||||
} |
||||
|
||||
@Override |
||||
public void onViewDetachedFromWindow(View v) { |
||||
|
||||
} |
||||
}); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@TargetApi(Build.VERSION_CODES.P) |
||||
private static void realHandleDisplayCutoutMode(Window window, View decorView) { |
||||
if (decorView.getRootWindowInsets() != null && |
||||
decorView.getRootWindowInsets().getDisplayCutout() != null) { |
||||
WindowManager.LayoutParams params = window.getAttributes(); |
||||
params.layoutInDisplayCutoutMode = WindowManager.LayoutParams |
||||
.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES; |
||||
window.setAttributes(params); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 设置状态栏黑色字体图标, |
||||
* 支持 4.4 以上版本 MIUI 和 Flyme,以及 6.0 以上版本的其他 Android |
||||
* |
||||
* @param activity 需要被处理的 Activity |
||||
*/ |
||||
public static boolean setStatusBarLightMode(Activity activity) { |
||||
if (activity == null) { |
||||
return false; |
||||
} |
||||
// 无语系列:ZTK C2016只能时间和电池图标变色。。。。
|
||||
if (DeviceUtils.isZTKC2016()) { |
||||
return false; |
||||
} |
||||
|
||||
if (mStatusBarType != STATUSBAR_TYPE_DEFAULT) { |
||||
return setStatusBarLightMode(activity, mStatusBarType); |
||||
} |
||||
if (Build.VERSION.SDK_INT >= KITKAT) { |
||||
if (isMIUICustomStatusBarLightModeImpl() && MIUISetStatusBarLightMode(activity.getWindow(), true)) { |
||||
mStatusBarType = STATUSBAR_TYPE_MIUI; |
||||
return true; |
||||
} else if (FlymeSetStatusBarLightMode(activity.getWindow(), true)) { |
||||
mStatusBarType = STATUSBAR_TYPE_FLYME; |
||||
return true; |
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { |
||||
Android6SetStatusBarLightMode(activity.getWindow(), true); |
||||
mStatusBarType = STATUSBAR_TYPE_ANDROID6; |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* 已知系统类型时,设置状态栏黑色字体图标。 |
||||
* 支持 4.4 以上版本 MIUI 和 Flyme,以及 6.0 以上版本的其他 Android |
||||
* |
||||
* @param activity 需要被处理的 Activity |
||||
* @param type StatusBar 类型,对应不同的系统 |
||||
*/ |
||||
private static boolean setStatusBarLightMode(Activity activity, @StatusBarType int type) { |
||||
if (type == STATUSBAR_TYPE_MIUI) { |
||||
return MIUISetStatusBarLightMode(activity.getWindow(), true); |
||||
} else if (type == STATUSBAR_TYPE_FLYME) { |
||||
return FlymeSetStatusBarLightMode(activity.getWindow(), true); |
||||
} else if (type == STATUSBAR_TYPE_ANDROID6) { |
||||
return Android6SetStatusBarLightMode(activity.getWindow(), true); |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 设置状态栏白色字体图标 |
||||
* 支持 4.4 以上版本 MIUI 和 Flyme,以及 6.0 以上版本的其他 Android |
||||
*/ |
||||
public static boolean setStatusBarDarkMode(Activity activity) { |
||||
if (activity == null) { |
||||
return false; |
||||
} |
||||
if (mStatusBarType == STATUSBAR_TYPE_DEFAULT) { |
||||
// 默认状态,不需要处理
|
||||
return true; |
||||
} |
||||
|
||||
if (mStatusBarType == STATUSBAR_TYPE_MIUI) { |
||||
return MIUISetStatusBarLightMode(activity.getWindow(), false); |
||||
} else if (mStatusBarType == STATUSBAR_TYPE_FLYME) { |
||||
return FlymeSetStatusBarLightMode(activity.getWindow(), false); |
||||
} else if (mStatusBarType == STATUSBAR_TYPE_ANDROID6) { |
||||
return Android6SetStatusBarLightMode(activity.getWindow(), false); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
@TargetApi(Build.VERSION_CODES.M) |
||||
private static int changeStatusBarModeRetainFlag(Window window, int out) { |
||||
out = retainSystemUiFlag(window, out, View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); |
||||
out = retainSystemUiFlag(window, out, View.SYSTEM_UI_FLAG_FULLSCREEN); |
||||
out = retainSystemUiFlag(window, out, View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); |
||||
out = retainSystemUiFlag(window, out, View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); |
||||
out = retainSystemUiFlag(window, out, View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); |
||||
out = retainSystemUiFlag(window, out, View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); |
||||
return out; |
||||
} |
||||
|
||||
public static int retainSystemUiFlag(Window window, int out, int type) { |
||||
int now = window.getDecorView().getSystemUiVisibility(); |
||||
if ((now & type) == type) { |
||||
out |= type; |
||||
} |
||||
return out; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 设置状态栏字体图标为深色,Android 6 |
||||
* |
||||
* @param window 需要设置的窗口 |
||||
* @param light 是否把状态栏字体及图标颜色设置为深色 |
||||
* @return boolean 成功执行返回true |
||||
*/ |
||||
@TargetApi(Build.VERSION_CODES.M) |
||||
private static boolean Android6SetStatusBarLightMode(Window window, boolean light) { |
||||
View decorView = window.getDecorView(); |
||||
int systemUi = light ? View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR : View.SYSTEM_UI_FLAG_LAYOUT_STABLE; |
||||
systemUi = changeStatusBarModeRetainFlag(window, systemUi); |
||||
decorView.setSystemUiVisibility(systemUi); |
||||
if (DeviceUtils.isMIUIV9()) { |
||||
// MIUI 9 低于 6.0 版本依旧只能回退到以前的方案
|
||||
// https://github.com/Tencent/QMUI_Android/issues/160
|
||||
MIUISetStatusBarLightMode(window, light); |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* 设置状态栏字体图标为深色,需要 MIUIV6 以上 |
||||
* |
||||
* @param window 需要设置的窗口 |
||||
* @param light 是否把状态栏字体及图标颜色设置为深色 |
||||
* @return boolean 成功执行返回 true |
||||
*/ |
||||
@SuppressWarnings("unchecked") |
||||
public static boolean MIUISetStatusBarLightMode(Window window, boolean light) { |
||||
boolean result = false; |
||||
if (window != null) { |
||||
Class clazz = window.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); |
||||
if (light) { |
||||
extraFlagField.invoke(window, darkModeFlag, darkModeFlag);//状态栏透明且黑色字体
|
||||
} else { |
||||
extraFlagField.invoke(window, 0, darkModeFlag);//清除黑色字体
|
||||
} |
||||
result = true; |
||||
} catch (Exception ignored) { |
||||
|
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* 更改状态栏图标、文字颜色的方案是否是MIUI自家的, MIUI9 && Android 6 之后用回Android原生实现 |
||||
* 见小米开发文档说明:https://dev.mi.com/console/doc/detail?pId=1159
|
||||
*/ |
||||
private static boolean isMIUICustomStatusBarLightModeImpl() { |
||||
if (DeviceUtils.isMIUIV9() && Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { |
||||
return true; |
||||
} |
||||
return DeviceUtils.isMIUIV5() || DeviceUtils.isMIUIV6() || |
||||
DeviceUtils.isMIUIV7() || DeviceUtils.isMIUIV8(); |
||||
} |
||||
|
||||
/** |
||||
* 设置状态栏图标为深色和魅族特定的文字风格 |
||||
* 可以用来判断是否为 Flyme 用户 |
||||
* |
||||
* @param window 需要设置的窗口 |
||||
* @param light 是否把状态栏字体及图标颜色设置为深色 |
||||
* @return boolean 成功执行返回true |
||||
*/ |
||||
public static boolean FlymeSetStatusBarLightMode(Window window, boolean light) { |
||||
boolean result = false; |
||||
if (window != null) { |
||||
// flyme 在 6.2.0.0A 支持了 Android 官方的实现方案,旧的方案失效
|
||||
Android6SetStatusBarLightMode(window, light); |
||||
|
||||
try { |
||||
WindowManager.LayoutParams lp = window.getAttributes(); |
||||
Field darkFlag = WindowManager.LayoutParams.class |
||||
.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON"); |
||||
Field meizuFlags = WindowManager.LayoutParams.class |
||||
.getDeclaredField("meizuFlags"); |
||||
darkFlag.setAccessible(true); |
||||
meizuFlags.setAccessible(true); |
||||
int bit = darkFlag.getInt(null); |
||||
int value = meizuFlags.getInt(lp); |
||||
if (light) { |
||||
value |= bit; |
||||
} else { |
||||
value &= ~bit; |
||||
} |
||||
meizuFlags.setInt(lp, value); |
||||
window.setAttributes(lp); |
||||
result = true; |
||||
} catch (Exception ignored) { |
||||
|
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* 获取是否全屏 |
||||
* |
||||
* @return 是否全屏 |
||||
*/ |
||||
public static boolean isFullScreen(Activity activity) { |
||||
boolean ret = false; |
||||
try { |
||||
WindowManager.LayoutParams attrs = activity.getWindow().getAttributes(); |
||||
ret = (attrs.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0; |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
} |
||||
return ret; |
||||
} |
||||
|
||||
/** |
||||
* API19之前透明状态栏:获取设置透明状态栏的system ui visibility的值,这是部分有提供接口的rom使用的 |
||||
* http://stackoverflow.com/questions/21865621/transparent-status-bar-before-4-4-kitkat
|
||||
*/ |
||||
public static Integer getStatusBarAPITransparentValue(Context context) { |
||||
if (sTransparentValue != null) { |
||||
return sTransparentValue; |
||||
} |
||||
String[] systemSharedLibraryNames = context.getPackageManager() |
||||
.getSystemSharedLibraryNames(); |
||||
String fieldName = null; |
||||
for (String lib : systemSharedLibraryNames) { |
||||
if ("touchwiz".equals(lib)) { |
||||
fieldName = "SYSTEM_UI_FLAG_TRANSPARENT_BACKGROUND"; |
||||
} else if (lib.startsWith("com.sonyericsson.navigationbar")) { |
||||
fieldName = "SYSTEM_UI_FLAG_TRANSPARENT"; |
||||
} |
||||
} |
||||
|
||||
if (fieldName != null) { |
||||
try { |
||||
Field field = View.class.getField(fieldName); |
||||
if (field != null) { |
||||
Class<?> type = field.getType(); |
||||
if (type == int.class) { |
||||
sTransparentValue = field.getInt(null); |
||||
} |
||||
} |
||||
} catch (Exception ignored) { |
||||
} |
||||
} |
||||
return sTransparentValue; |
||||
} |
||||
|
||||
/** |
||||
* 检测 Android 6.0 是否可以启用 window.setStatusBarColor(Color.TRANSPARENT)。 |
||||
*/ |
||||
public static boolean supportTransclentStatusBar6() { |
||||
return !(DeviceUtils.isZUKZ1() || DeviceUtils.isZTKC2016()); |
||||
} |
||||
|
||||
/** |
||||
* 获取状态栏的高度。 |
||||
* |
||||
* @param context 上下文 |
||||
* @return 状态栏高度 |
||||
*/ |
||||
public static int getStatusBarHeight(Context context) { |
||||
if (sStatusbarHeight == -1) { |
||||
sStatusbarHeight = Utils.getStatusBarHeight(context); |
||||
} |
||||
return sStatusbarHeight; |
||||
} |
||||
|
||||
public static void setVirtualDensity(float density) { |
||||
sVirtualDensity = density; |
||||
} |
||||
|
||||
public static void setVirtualDensityDpi(float densityDpi) { |
||||
sVirtualDensityDpi = densityDpi; |
||||
} |
||||
|
||||
@IntDef({STATUSBAR_TYPE_DEFAULT, STATUSBAR_TYPE_MIUI, STATUSBAR_TYPE_FLYME, STATUSBAR_TYPE_ANDROID6}) |
||||
@Retention(RetentionPolicy.SOURCE) |
||||
private @interface StatusBarType { |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 全屏 |
||||
* |
||||
* @param activity 窗口 |
||||
*/ |
||||
public static void fullScreen(Activity activity) { |
||||
if (activity == null) { |
||||
return; |
||||
} |
||||
fullScreen(activity.getWindow()); |
||||
} |
||||
|
||||
/** |
||||
* 全屏 |
||||
* |
||||
* @param window 窗口 |
||||
*/ |
||||
public static void fullScreen(Window window) { |
||||
if (window == null) { |
||||
return; |
||||
} |
||||
if (Build.VERSION.SDK_INT > HONEYCOMB && Build.VERSION.SDK_INT < KITKAT) { // lower api
|
||||
window.getDecorView().setSystemUiVisibility(View.GONE); |
||||
} else if (Build.VERSION.SDK_INT >= KITKAT) { |
||||
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE |
||||
| View.SYSTEM_UI_FLAG_FULLSCREEN |
||||
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
||||
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 取消全屏 |
||||
* |
||||
* @param activity 窗口 |
||||
* @param statusBarColor 状态栏的颜色 |
||||
* @param navigationBarColor 导航栏的颜色 |
||||
*/ |
||||
public static void cancelFullScreen(Activity activity, @ColorInt int statusBarColor, @ColorInt int navigationBarColor) { |
||||
if (activity == null) { |
||||
return; |
||||
} |
||||
cancelFullScreen(activity.getWindow(), statusBarColor, navigationBarColor); |
||||
} |
||||
|
||||
/** |
||||
* 取消全屏 |
||||
* |
||||
* @param window 窗口 |
||||
* @param statusBarColor 状态栏的颜色 |
||||
* @param navigationBarColor 导航栏的颜色 |
||||
*/ |
||||
public static void cancelFullScreen(Window window, @ColorInt int statusBarColor, @ColorInt int navigationBarColor) { |
||||
if (window == null) { |
||||
return; |
||||
} |
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS |
||||
| WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); |
||||
window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); |
||||
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); |
||||
if (statusBarColor != -1) { |
||||
window.setStatusBarColor(statusBarColor); |
||||
} |
||||
if (navigationBarColor != -1) { |
||||
window.setNavigationBarColor(navigationBarColor); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 取消全屏 |
||||
* |
||||
* @param activity 窗口 |
||||
*/ |
||||
public static void cancelFullScreen(Activity activity) { |
||||
if (activity == null) { |
||||
return; |
||||
} |
||||
cancelFullScreen(activity.getWindow()); |
||||
} |
||||
|
||||
/** |
||||
* 取消全屏 |
||||
* |
||||
* @param window 窗口 |
||||
*/ |
||||
public static void cancelFullScreen(Window window) { |
||||
cancelFullScreen(window, -1, -1); |
||||
} |
||||
|
||||
/** |
||||
* 设置底部导航条的颜色 |
||||
* |
||||
* @param activity 窗口 |
||||
* @param color 颜色 |
||||
*/ |
||||
public static void setNavigationBarColor(Activity activity, int color) { |
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) { |
||||
//5.0以上可以直接设置 navigation颜色
|
||||
activity.getWindow().setNavigationBarColor(color); |
||||
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { |
||||
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); |
||||
ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView(); |
||||
View navigationBar = new View(activity); |
||||
FrameLayout.LayoutParams params; |
||||
params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, getNavigationBarHeight(activity)); |
||||
params.gravity = Gravity.BOTTOM; |
||||
navigationBar.setLayoutParams(params); |
||||
navigationBar.setBackgroundColor(color); |
||||
decorView.addView(navigationBar); |
||||
} else { |
||||
//4.4以下无法设置NavigationBar颜色
|
||||
} |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 获取底部导航条的高度 |
||||
* |
||||
* @param context 上下文 |
||||
* @return 底部导航条的高度 |
||||
*/ |
||||
public static int getNavigationBarHeight(Context context) { |
||||
int height = 0; |
||||
int id = context.getResources().getIdentifier("navigation_bar_height", "dimen", "android"); |
||||
if (id > 0) { |
||||
height = context.getResources().getDimensionPixelSize(id); |
||||
} |
||||
return height; |
||||
} |
||||
|
||||
/** |
||||
* 底部导航条是否显示 |
||||
* |
||||
* @param activity 窗口 |
||||
* @return 底部导航条是否显示 |
||||
*/ |
||||
public static boolean isNavigationBarExist(Activity activity) { |
||||
return DensityUtils.isNavigationBarExist(activity); |
||||
} |
||||
|
||||
/** |
||||
* 全屏下显示弹窗 |
||||
* |
||||
* @param dialog 弹窗 |
||||
*/ |
||||
public static void showDialogInFullScreen(final Dialog dialog) { |
||||
if (dialog == null) { |
||||
return; |
||||
} |
||||
showWindowInFullScreen(dialog.getWindow(), new IWindowShower() { |
||||
@Override |
||||
public void show(Window window) { |
||||
dialog.show(); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 全屏下显示窗口【包括dialog等】 |
||||
* |
||||
* @param window 窗口 |
||||
* @param iWindowShower 窗口显示接口 |
||||
*/ |
||||
public static void showWindowInFullScreen(Window window, IWindowShower iWindowShower) { |
||||
if (window == null || iWindowShower == null) { |
||||
return; |
||||
} |
||||
window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); |
||||
iWindowShower.show(window); |
||||
StatusBarUtils.fullScreen(window); |
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); |
||||
} |
||||
|
||||
/** |
||||
* 显示窗口【同步窗口系统view的可见度, 解决全屏下显示窗口导致界面退出全屏的问题】 |
||||
* |
||||
* @param activity 活动窗口 |
||||
* @param dialog 需要显示的窗口 |
||||
*/ |
||||
public static void showDialog(Activity activity, final Dialog dialog) { |
||||
if (dialog == null) { |
||||
return; |
||||
} |
||||
showWindow(activity, dialog.getWindow(), new IWindowShower() { |
||||
@Override |
||||
public void show(Window window) { |
||||
dialog.show(); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* 显示窗口【同步窗口系统view的可见度, 解决全屏下显示窗口导致界面退出全屏的问题】 |
||||
* |
||||
* @param activity 活动窗口 |
||||
* @param window 需要显示的窗口 |
||||
* @param iWindowShower 窗口显示接口 |
||||
* @return 是否执行成功 |
||||
*/ |
||||
public static boolean showWindow(Activity activity, Window window, IWindowShower iWindowShower) { |
||||
if (activity == null || window == null || iWindowShower == null) { |
||||
return false; |
||||
} |
||||
window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); |
||||
iWindowShower.show(window); |
||||
StatusBarUtils.syncSystemUiVisibility(activity, window); |
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* 同步窗口的系统view的可见度【解决全屏下显示窗口导致界面退出全屏的问题】 |
||||
* |
||||
* @param original 活动窗口 |
||||
* @param target 目标窗口 |
||||
* @return 是否执行成功 |
||||
*/ |
||||
public static boolean syncSystemUiVisibility(Activity original, Window target) { |
||||
if (original == null) { |
||||
return false; |
||||
} |
||||
return syncSystemUiVisibility(original.getWindow(), target); |
||||
} |
||||
|
||||
/** |
||||
* 同步两个窗口的系统view的可见度【解决全屏下显示窗口导致界面退出全屏的问题】 |
||||
* |
||||
* @param original 原始窗口 |
||||
* @param target 目标窗口 |
||||
* @return 是否执行成功 |
||||
*/ |
||||
public static boolean syncSystemUiVisibility(Window original, Window target) { |
||||
if (original == null || target == null) { |
||||
return false; |
||||
} |
||||
target.getDecorView().setSystemUiVisibility(original.getDecorView().getSystemUiVisibility()); |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* 窗口显示接口 |
||||
*/ |
||||
public interface IWindowShower { |
||||
/** |
||||
* 显示窗口 |
||||
* |
||||
* @param window 窗口 |
||||
*/ |
||||
void show(Window window); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,414 @@ |
||||
package com.project.survey.util; |
||||
|
||||
import android.annotation.SuppressLint; |
||||
import android.content.Context; |
||||
import android.content.res.ColorStateList; |
||||
import android.content.res.Configuration; |
||||
import android.content.res.Resources; |
||||
import android.content.res.TypedArray; |
||||
import android.graphics.Color; |
||||
import android.graphics.drawable.Drawable; |
||||
import android.os.Build; |
||||
import android.text.TextUtils; |
||||
import android.util.TypedValue; |
||||
import android.view.View; |
||||
|
||||
import androidx.annotation.ArrayRes; |
||||
import androidx.annotation.AttrRes; |
||||
import androidx.annotation.ColorInt; |
||||
import androidx.annotation.ColorRes; |
||||
import androidx.annotation.IntDef; |
||||
import androidx.annotation.NonNull; |
||||
import androidx.annotation.Nullable; |
||||
import androidx.appcompat.app.AppCompatDelegate; |
||||
import androidx.appcompat.content.res.AppCompatResources; |
||||
import androidx.core.content.ContextCompat; |
||||
|
||||
|
||||
import com.project.survey.R; |
||||
import com.project.survey.widget.edittext.GravityEnum; |
||||
|
||||
import java.lang.annotation.Retention; |
||||
import java.lang.annotation.RetentionPolicy; |
||||
|
||||
/** |
||||
* 主题工具 |
||||
* |
||||
* @author xuexiang |
||||
* @since 2018/11/14 下午1:46 |
||||
*/ |
||||
public final class ThemeUtils { |
||||
|
||||
private ThemeUtils() { |
||||
throw new UnsupportedOperationException("u can't instantiate me..."); |
||||
} |
||||
|
||||
@ColorInt |
||||
public static int getDisabledColor(Context context) { |
||||
final int primaryColor = resolveColor(context, android.R.attr.textColorPrimary); |
||||
final int disabledColor = isColorDark(primaryColor) ? Color.BLACK : Color.WHITE; |
||||
return adjustAlpha(disabledColor, 0.3f); |
||||
} |
||||
|
||||
@ColorInt |
||||
public static int adjustAlpha( |
||||
@ColorInt int color, @SuppressWarnings("SameParameterValue") float factor) { |
||||
int alpha = Math.round(Color.alpha(color) * factor); |
||||
int red = Color.red(color); |
||||
int green = Color.green(color); |
||||
int blue = Color.blue(color); |
||||
return Color.argb(alpha, red, green, blue); |
||||
} |
||||
|
||||
@ColorInt |
||||
public static int resolveColor(Context context, @AttrRes int attr) { |
||||
return resolveColor(context, attr, 0); |
||||
} |
||||
|
||||
@ColorInt |
||||
public static int resolveColor(Context context, @AttrRes int attr, int fallback) { |
||||
TypedArray a = context.getTheme().obtainStyledAttributes(new int[]{attr}); |
||||
try { |
||||
return a.getColor(0, fallback); |
||||
} finally { |
||||
a.recycle(); |
||||
} |
||||
} |
||||
|
||||
public static int getColorFromAttrRes(int attrRes, int defaultValue, Context context) { |
||||
TypedArray a = context.obtainStyledAttributes(new int[]{attrRes}); |
||||
try { |
||||
return a.getColor(0, defaultValue); |
||||
} finally { |
||||
a.recycle(); |
||||
} |
||||
} |
||||
|
||||
public static float resolveFloat(Context context, int attrRes) { |
||||
TypedValue typedValue = new TypedValue(); |
||||
context.getTheme().resolveAttribute(attrRes, typedValue, true); |
||||
return typedValue.getFloat(); |
||||
} |
||||
|
||||
public static int resolveInt(Context context, int attrRes) { |
||||
return resolveInt(context, attrRes, 0); |
||||
} |
||||
|
||||
public static int resolveInt(Context context, int attrRes, int defaultValue) { |
||||
TypedArray a = context.obtainStyledAttributes(new int[]{attrRes}); |
||||
try { |
||||
return a.getInt(0, defaultValue); |
||||
} finally { |
||||
a.recycle(); |
||||
} |
||||
} |
||||
|
||||
public static float resolveFloat(Context context, int attrRes, float defaultValue) { |
||||
TypedArray a = context.obtainStyledAttributes(new int[]{attrRes}); |
||||
try { |
||||
return a.getFloat(0, defaultValue); |
||||
} finally { |
||||
a.recycle(); |
||||
} |
||||
} |
||||
|
||||
// Try to resolve the colorAttr attribute.
|
||||
public static ColorStateList resolveActionTextColorStateList( |
||||
Context context, @AttrRes int colorAttr, ColorStateList fallback) { |
||||
TypedArray a = context.getTheme().obtainStyledAttributes(new int[]{colorAttr}); |
||||
try { |
||||
final TypedValue value = a.peekValue(0); |
||||
if (value == null) { |
||||
return fallback; |
||||
} |
||||
if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT |
||||
&& value.type <= TypedValue.TYPE_LAST_COLOR_INT) { |
||||
return getActionTextStateList(context, value.data); |
||||
} else { |
||||
final ColorStateList stateList = a.getColorStateList(0); |
||||
if (stateList != null) { |
||||
return stateList; |
||||
} else { |
||||
return fallback; |
||||
} |
||||
} |
||||
} finally { |
||||
a.recycle(); |
||||
} |
||||
} |
||||
|
||||
// Get the specified color resource, creating a ColorStateList if the resource
|
||||
// points to a color value.
|
||||
public static ColorStateList getActionTextColorStateList(Context context, @ColorRes int colorId) { |
||||
final TypedValue value = new TypedValue(); |
||||
context.getResources().getValue(colorId, value, true); |
||||
if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT |
||||
&& value.type <= TypedValue.TYPE_LAST_COLOR_INT) { |
||||
return getActionTextStateList(context, value.data); |
||||
} else { |
||||
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) { |
||||
//noinspection deprecation
|
||||
return context.getResources().getColorStateList(colorId); |
||||
} else { |
||||
return context.getColorStateList(colorId); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns a color associated with a particular resource ID |
||||
* |
||||
* <p>Starting in {@link Build.VERSION_CODES#M}, the returned color will be styled for |
||||
* the specified Context's theme. |
||||
* |
||||
* @param colorId The desired resource identifier, as generated by the aapt tool. This integer |
||||
* encodes the package, type, and resource entry. The value 0 is an invalid identifier. |
||||
* @return A single color value in the form 0xAARRGGBB. |
||||
*/ |
||||
@ColorInt |
||||
public static int getColor(Context context, @ColorRes int colorId) { |
||||
return ContextCompat.getColor(context, colorId); |
||||
} |
||||
|
||||
public static String resolveString(Context context, @AttrRes int attr) { |
||||
TypedValue v = new TypedValue(); |
||||
context.getTheme().resolveAttribute(attr, v, true); |
||||
return (String) v.string; |
||||
} |
||||
|
||||
public static String resolveString(Context context, @AttrRes int attr, String defaultValue) { |
||||
TypedValue v = new TypedValue(); |
||||
context.getTheme().resolveAttribute(attr, v, true); |
||||
String value = (String) v.string; |
||||
return TextUtils.isEmpty(value) ? defaultValue : value; |
||||
} |
||||
|
||||
public static String resolveString(Resources.Theme theme, @AttrRes int attr) { |
||||
TypedValue v = new TypedValue(); |
||||
theme.resolveAttribute(attr, v, true); |
||||
return (String) v.string; |
||||
} |
||||
|
||||
|
||||
public static Drawable resolveDrawable(Context context, @AttrRes int attr) { |
||||
return resolveDrawable(context, attr, null); |
||||
} |
||||
|
||||
public static Drawable resolveDrawable( |
||||
Context context, |
||||
@AttrRes int attr, |
||||
@SuppressWarnings("SameParameterValue") Drawable fallback) { |
||||
TypedArray array = context.getTheme().obtainStyledAttributes(new int[]{attr}); |
||||
try { |
||||
Drawable drawable = null; |
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { |
||||
drawable = array.getDrawable(0); |
||||
} else { |
||||
int id = array.getResourceId(0, -1); |
||||
if (id != -1) { |
||||
drawable = AppCompatResources.getDrawable(context, id); |
||||
} |
||||
} |
||||
if (drawable == null && fallback != null) { |
||||
drawable = fallback; |
||||
} |
||||
return drawable; |
||||
} finally { |
||||
array.recycle(); |
||||
} |
||||
} |
||||
|
||||
public static int resolveDimension(Context context, @AttrRes int attr) { |
||||
return resolveDimension(context, attr, -1); |
||||
} |
||||
|
||||
public static int resolveDimension(Context context, @AttrRes int attr, int fallback) { |
||||
TypedArray a = context.getTheme().obtainStyledAttributes(new int[]{attr}); |
||||
try { |
||||
return a.getDimensionPixelSize(0, fallback); |
||||
} finally { |
||||
a.recycle(); |
||||
} |
||||
} |
||||
|
||||
public static boolean resolveBoolean(Context context, @AttrRes int attr, boolean fallback) { |
||||
TypedArray a = context.getTheme().obtainStyledAttributes(new int[]{attr}); |
||||
try { |
||||
return a.getBoolean(0, fallback); |
||||
} finally { |
||||
a.recycle(); |
||||
} |
||||
} |
||||
|
||||
public static boolean resolveBoolean(Context context, @AttrRes int attr) { |
||||
return resolveBoolean(context, attr, false); |
||||
} |
||||
|
||||
public static boolean isColorDark(@ColorInt int color) { |
||||
double darkness = |
||||
1 |
||||
- (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) |
||||
/ 255; |
||||
return darkness >= 0.5; |
||||
} |
||||
|
||||
public static void setBackgroundCompat(View view, Drawable d) { |
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) { |
||||
//noinspection deprecation
|
||||
view.setBackgroundDrawable(d); |
||||
} else { |
||||
view.setBackground(d); |
||||
} |
||||
} |
||||
|
||||
|
||||
public static ColorStateList getActionTextStateList(Context context, int newPrimaryColor) { |
||||
final int fallBackButtonColor = |
||||
ThemeUtils.resolveColor(context, android.R.attr.textColorPrimary); |
||||
if (newPrimaryColor == 0) { |
||||
newPrimaryColor = fallBackButtonColor; |
||||
} |
||||
int[][] states = |
||||
new int[][]{ |
||||
new int[]{-android.R.attr.state_enabled}, // disabled
|
||||
new int[]{} // enabled
|
||||
}; |
||||
int[] colors = new int[]{ThemeUtils.adjustAlpha(newPrimaryColor, 0.4f), newPrimaryColor}; |
||||
return new ColorStateList(states, colors); |
||||
} |
||||
|
||||
public static int[] getColorArray(@NonNull Context context, @ArrayRes int array) { |
||||
if (array == 0) { |
||||
return null; |
||||
} |
||||
TypedArray ta = context.getResources().obtainTypedArray(array); |
||||
int[] colors = new int[ta.length()]; |
||||
for (int i = 0; i < ta.length(); i++) { |
||||
colors[i] = ta.getColor(i, 0); |
||||
} |
||||
ta.recycle(); |
||||
return colors; |
||||
} |
||||
|
||||
public static <T> boolean isIn(@NonNull T find, @Nullable T[] ary) { |
||||
if (ary == null || ary.length == 0) { |
||||
return false; |
||||
} |
||||
for (T item : ary) { |
||||
if (item.equals(find)) { |
||||
return true; |
||||
} |
||||
} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* 获取主题色 |
||||
* |
||||
* @param context 上下文 |
||||
* @return 主题色 |
||||
*/ |
||||
@ColorInt |
||||
public static int getMainThemeColor(Context context) { |
||||
return resolveColor(context, R.attr.colorPrimary, getColor(context, R.color.colorPrimary)); |
||||
} |
||||
|
||||
//========================深色模式==============================//
|
||||
/** |
||||
* 系统默认模式 |
||||
*/ |
||||
public static final int DEFAULT_MODE = 0; |
||||
/** |
||||
* 浅色模式 |
||||
*/ |
||||
public static final int LIGHT_MODE = 1; |
||||
/** |
||||
* 深色模式 |
||||
*/ |
||||
public static final int DARK_MODE = 2; |
||||
|
||||
@IntDef({DEFAULT_MODE, LIGHT_MODE, DARK_MODE}) |
||||
@Retention(RetentionPolicy.SOURCE) |
||||
public @interface Theme { |
||||
} |
||||
|
||||
/** |
||||
* 当前是否是处于深色模式 |
||||
* |
||||
* @return 是否是深色模式 |
||||
*/ |
||||
@Deprecated |
||||
public static boolean isNightMode() { |
||||
int mode = ResUtils.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; |
||||
return mode == Configuration.UI_MODE_NIGHT_YES; |
||||
} |
||||
|
||||
/** |
||||
* 当前是否是处于深色模式 |
||||
* |
||||
* @param context 上下文 |
||||
* @return 是否是深色模式 |
||||
*/ |
||||
public static boolean isNightMode(@NonNull Context context) { |
||||
int mode = ResUtils.getResources(context).getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; |
||||
return mode == Configuration.UI_MODE_NIGHT_YES; |
||||
} |
||||
|
||||
/** |
||||
* 设置应用的主题(深色模式) |
||||
* |
||||
* @param theme 主题类型 |
||||
*/ |
||||
@SuppressLint("WrongConstant") |
||||
public static void applyTheme(@Theme int theme) { |
||||
switch (theme) { |
||||
case LIGHT_MODE: |
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO); |
||||
break; |
||||
case DARK_MODE: |
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); |
||||
break; |
||||
case DEFAULT_MODE: |
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { |
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM); |
||||
} else { |
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY); |
||||
} |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
} |
||||
|
||||
//=================//
|
||||
|
||||
private static int gravityEnumToAttrInt(GravityEnum value) { |
||||
switch (value) { |
||||
case CENTER: |
||||
return 1; |
||||
case END: |
||||
return 2; |
||||
default: |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
public static GravityEnum resolveGravityEnum( |
||||
Context context, @AttrRes int attr, GravityEnum defaultGravity) { |
||||
TypedArray a = context.getTheme().obtainStyledAttributes(new int[]{attr}); |
||||
try { |
||||
switch (a.getInt(0, gravityEnumToAttrInt(defaultGravity))) { |
||||
case 1: |
||||
return GravityEnum.CENTER; |
||||
case 2: |
||||
return GravityEnum.END; |
||||
default: |
||||
return GravityEnum.START; |
||||
} |
||||
} finally { |
||||
a.recycle(); |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,114 @@ |
||||
package com.project.survey.widget; |
||||
|
||||
|
||||
import android.app.Activity; |
||||
import android.app.Application; |
||||
import android.content.Context; |
||||
import android.content.res.Configuration; |
||||
import android.graphics.Typeface; |
||||
import android.text.TextUtils; |
||||
import android.view.View; |
||||
|
||||
import androidx.annotation.ColorInt; |
||||
import androidx.annotation.Nullable; |
||||
|
||||
import com.project.survey.R; |
||||
|
||||
import io.github.inflationx.calligraphy3.CalligraphyConfig; |
||||
import io.github.inflationx.calligraphy3.CalligraphyInterceptor; |
||||
import io.github.inflationx.calligraphy3.TypefaceUtils; |
||||
import io.github.inflationx.viewpump.ViewPump; |
||||
|
||||
/** |
||||
* UI全局设置 |
||||
* |
||||
* @author xuexiang |
||||
* @since 2018/11/14 上午11:40 |
||||
*/ |
||||
public class XUI { |
||||
|
||||
private static Application sContext; |
||||
|
||||
private static boolean sIsTabletChecked; |
||||
|
||||
private static int sScreenType; |
||||
|
||||
private static String sDefaultFontAssetPath; |
||||
|
||||
//=======================初始化设置===========================//
|
||||
|
||||
/** |
||||
* 初始化 |
||||
* |
||||
* @param context 上下文 |
||||
*/ |
||||
public static void init(Application context) { |
||||
sContext = context; |
||||
} |
||||
|
||||
/** |
||||
* 设置默认字体 |
||||
*/ |
||||
public static void initFontStyle(String defaultFontAssetPath) { |
||||
if (!TextUtils.isEmpty(defaultFontAssetPath)) { |
||||
sDefaultFontAssetPath = defaultFontAssetPath; |
||||
ViewPump.init(ViewPump.builder() |
||||
.addInterceptor(new CalligraphyInterceptor( |
||||
new CalligraphyConfig.Builder() |
||||
.setDefaultFontPath(defaultFontAssetPath) |
||||
.setFontAttrId(R.attr.fontPath) |
||||
.build())) |
||||
.build()); |
||||
} |
||||
} |
||||
|
||||
public static Context getContext() { |
||||
testInitialize(); |
||||
return sContext; |
||||
} |
||||
|
||||
private static void testInitialize() { |
||||
if (sContext == null) { |
||||
throw new ExceptionInInitializerError("请先在全局Application中调用 XUI.init() 初始化!"); |
||||
} |
||||
} |
||||
|
||||
//=======================日志调试===========================//
|
||||
|
||||
|
||||
//=======================字体===========================//
|
||||
/** |
||||
* @return 获取默认字体 |
||||
*/ |
||||
@Nullable |
||||
public static Typeface getDefaultTypeface() { |
||||
if (!TextUtils.isEmpty(sDefaultFontAssetPath)) { |
||||
return TypefaceUtils.load(getContext().getAssets(), sDefaultFontAssetPath); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* @return 默认字体的存储位置 |
||||
*/ |
||||
public static String getDefaultFontAssetPath() { |
||||
return sDefaultFontAssetPath; |
||||
} |
||||
|
||||
/** |
||||
* @param fontPath 字体路径 |
||||
* @return 获取默认字体 |
||||
*/ |
||||
@Nullable |
||||
public static Typeface getDefaultTypeface(String fontPath) { |
||||
if (TextUtils.isEmpty(fontPath)) { |
||||
fontPath = sDefaultFontAssetPath; |
||||
} |
||||
if (!TextUtils.isEmpty(fontPath)) { |
||||
return TypefaceUtils.load(getContext().getAssets(), fontPath); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
|
||||
} |
@ -0,0 +1,69 @@ |
||||
/* |
||||
* Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
package com.project.survey.widget.edittext; |
||||
|
||||
import android.text.method.PasswordTransformationMethod; |
||||
import android.view.View; |
||||
|
||||
/** |
||||
* ‘****’号密码输入样式 |
||||
* |
||||
* @author xuexiang |
||||
* @since 2019-07-05 9:34 |
||||
*/ |
||||
public class AsteriskPasswordTransformationMethod extends PasswordTransformationMethod { |
||||
|
||||
private static AsteriskPasswordTransformationMethod sInstance; |
||||
|
||||
public static PasswordTransformationMethod getInstance() { |
||||
if (sInstance != null) { |
||||
return sInstance; |
||||
} |
||||
sInstance = new AsteriskPasswordTransformationMethod(); |
||||
return sInstance; |
||||
} |
||||
|
||||
@Override |
||||
public CharSequence getTransformation(CharSequence source, View view) { |
||||
return new AsteriskPasswordCharSequence(source); |
||||
} |
||||
|
||||
private static class AsteriskPasswordCharSequence implements CharSequence { |
||||
private CharSequence mSource; |
||||
|
||||
AsteriskPasswordCharSequence(CharSequence source) { |
||||
mSource = source; // Store char sequence
|
||||
} |
||||
|
||||
@Override |
||||
public char charAt(int index) { |
||||
return '*'; // This is the important part
|
||||
} |
||||
|
||||
@Override |
||||
public int length() { |
||||
return mSource.length(); // Return default
|
||||
} |
||||
|
||||
@Override |
||||
public CharSequence subSequence(int start, int end) { |
||||
return mSource.subSequence(start, end); // Return default
|
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,74 @@ |
||||
/* |
||||
* Copyright (C) 2018 xuexiangjys(xuexiangjys@163.com) |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
package com.project.survey.widget.edittext; |
||||
|
||||
import android.annotation.SuppressLint; |
||||
import android.annotation.TargetApi; |
||||
import android.os.Build; |
||||
import android.view.Gravity; |
||||
import android.view.View; |
||||
|
||||
/** |
||||
* 对齐方式 |
||||
* |
||||
* @author xuexiang |
||||
* @since 2018/11/14 下午4:44 |
||||
*/ |
||||
public enum GravityEnum { |
||||
/** |
||||
* 头部对齐 |
||||
*/ |
||||
START, |
||||
/** |
||||
* 居中对齐 |
||||
*/ |
||||
CENTER, |
||||
/** |
||||
* 尾部对齐 |
||||
*/ |
||||
END; |
||||
|
||||
private static final boolean HAS_RTL = |
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1; |
||||
|
||||
@SuppressLint("RtlHardcoded") |
||||
public int getGravityInt() { |
||||
switch (this) { |
||||
case START: |
||||
return HAS_RTL ? Gravity.START : Gravity.LEFT; |
||||
case CENTER: |
||||
return Gravity.CENTER_HORIZONTAL; |
||||
case END: |
||||
return HAS_RTL ? Gravity.END : Gravity.RIGHT; |
||||
default: |
||||
throw new IllegalStateException("Invalid gravity constant"); |
||||
} |
||||
} |
||||
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) |
||||
public int getTextAlignment() { |
||||
switch (this) { |
||||
case CENTER: |
||||
return View.TEXT_ALIGNMENT_CENTER; |
||||
case END: |
||||
return View.TEXT_ALIGNMENT_VIEW_END; |
||||
default: |
||||
return View.TEXT_ALIGNMENT_VIEW_START; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,318 @@ |
||||
package com.project.survey.widget.edittext; |
||||
|
||||
import android.content.Context; |
||||
import android.content.res.TypedArray; |
||||
import android.graphics.Typeface; |
||||
import android.graphics.drawable.Drawable; |
||||
import android.os.Parcel; |
||||
import android.os.Parcelable; |
||||
import android.text.Editable; |
||||
import android.text.TextWatcher; |
||||
import android.text.method.PasswordTransformationMethod; |
||||
import android.util.AttributeSet; |
||||
import android.view.MotionEvent; |
||||
import android.widget.EditText; |
||||
|
||||
import androidx.annotation.NonNull; |
||||
import androidx.appcompat.widget.AppCompatEditText; |
||||
|
||||
import com.project.survey.R; |
||||
import com.project.survey.util.DensityUtils; |
||||
import com.project.survey.util.ResUtils; |
||||
|
||||
public class PassEdittext2 extends androidx.appcompat.widget.AppCompatEditText { |
||||
/** |
||||
* 增大点击区域 |
||||
*/ |
||||
private int mExtraClickArea; |
||||
|
||||
private final static int ALPHA_ICON_ENABLED = (int) (255 * 0.54f); |
||||
private final static int ALPHA_ICON_DISABLED = (int) (255 * 0.38f); |
||||
|
||||
private Drawable mShowPwDrawable; |
||||
private Drawable mHidePwDrawable; |
||||
private boolean mPasswordVisible; |
||||
private boolean mShowingIcon; |
||||
private boolean mSetErrorCalled; |
||||
private boolean mHoverShowsPw; |
||||
private boolean mHandlingHoverEvent; |
||||
private PasswordTransformationMethod mTransformationMethod; |
||||
|
||||
public PassEdittext2(Context context) { |
||||
this(context, null); |
||||
} |
||||
|
||||
public PassEdittext2(Context context, AttributeSet attrs) { |
||||
this(context, attrs, R.attr.PasswordEditTextStyle); |
||||
} |
||||
|
||||
public PassEdittext2(Context context, AttributeSet attrs, int defStyleAttr) { |
||||
super(context, attrs, defStyleAttr); |
||||
initAttrs(context, attrs, defStyleAttr); |
||||
} |
||||
|
||||
public void initAttrs(Context context, AttributeSet attrs, int defStyleAttr) { |
||||
mExtraClickArea = DensityUtils.dp2px(context, 20); |
||||
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.PasswordEditText, defStyleAttr, 0); |
||||
boolean useNonMonospaceFont; |
||||
boolean enableIconAlpha; |
||||
try { |
||||
mShowPwDrawable = ResUtils.getDrawableAttrRes(getContext(), typedArray, R.styleable.PasswordEditText_pet_iconShow); |
||||
if (mShowPwDrawable == null) { |
||||
mShowPwDrawable = ResUtils.getVectorDrawable(getContext(), R.drawable.pet_icon_visibility_24dp); |
||||
} |
||||
mHidePwDrawable = ResUtils.getDrawableAttrRes(getContext(), typedArray, R.styleable.PasswordEditText_pet_iconHide); |
||||
if (mHidePwDrawable == null) { |
||||
mHidePwDrawable = ResUtils.getVectorDrawable(getContext(), R.drawable.pet_icon_visibility_off_24dp); |
||||
} |
||||
mHoverShowsPw = typedArray.getBoolean(R.styleable.PasswordEditText_pet_hoverShowsPw, false); |
||||
useNonMonospaceFont = typedArray.getBoolean(R.styleable.PasswordEditText_pet_nonMonospaceFont, false); |
||||
enableIconAlpha = typedArray.getBoolean(R.styleable.PasswordEditText_pet_enableIconAlpha, true); |
||||
boolean isAsteriskStyle = typedArray.getBoolean(R.styleable.PasswordEditText_pet_isAsteriskStyle, false); |
||||
if (isAsteriskStyle) { |
||||
mTransformationMethod = AsteriskPasswordTransformationMethod.getInstance(); |
||||
} else { |
||||
mTransformationMethod = PasswordTransformationMethod.getInstance(); |
||||
} |
||||
} finally { |
||||
typedArray.recycle(); |
||||
} |
||||
|
||||
if (enableIconAlpha) { |
||||
mHidePwDrawable.setAlpha(ALPHA_ICON_ENABLED); |
||||
mShowPwDrawable.setAlpha(ALPHA_ICON_DISABLED); |
||||
} |
||||
|
||||
// if (useNonMonospaceFont) {
|
||||
// setTypeface(Typeface.DEFAULT);
|
||||
// }
|
||||
|
||||
addTextChangedListener(new TextWatcher() { |
||||
@Override |
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) { |
||||
} |
||||
|
||||
@Override |
||||
public void onTextChanged(CharSequence seq, int start, int before, int count) { |
||||
} |
||||
|
||||
@Override |
||||
public void afterTextChanged(Editable s) { |
||||
if (s.length() > 0) { |
||||
if (mSetErrorCalled) { |
||||
setCompoundDrawablesRelative(null, null, null, null); |
||||
mSetErrorCalled = false; |
||||
showPasswordVisibilityIndicator(true); |
||||
} |
||||
if (!mShowingIcon) { |
||||
showPasswordVisibilityIndicator(true); |
||||
} |
||||
} else { |
||||
// hides the indicator if no text inside text field
|
||||
mPasswordVisible = false; |
||||
handlePasswordInputVisibility(); |
||||
showPasswordVisibilityIndicator(false); |
||||
} |
||||
|
||||
} |
||||
}); |
||||
|
||||
handlePasswordInputVisibility(); |
||||
} |
||||
|
||||
public PassEdittext2 setExtraClickAreaSize(int extraClickArea) { |
||||
mExtraClickArea = extraClickArea; |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* 设置密码输入框的样式 |
||||
* |
||||
* @param transformationMethod |
||||
* @return |
||||
*/ |
||||
public PassEdittext2 setPasswordTransformationMethod(PasswordTransformationMethod transformationMethod) { |
||||
mTransformationMethod = transformationMethod; |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* 设置密码输入框的样式 |
||||
* |
||||
* @param isAsteriskStyle |
||||
* @return |
||||
*/ |
||||
public PassEdittext2 setIsAsteriskStyle(boolean isAsteriskStyle) { |
||||
if (isAsteriskStyle) { |
||||
mTransformationMethod = AsteriskPasswordTransformationMethod.getInstance(); |
||||
} else { |
||||
mTransformationMethod = PasswordTransformationMethod.getInstance(); |
||||
} |
||||
return this; |
||||
} |
||||
|
||||
private boolean isRtl() { |
||||
return getLayoutDirection() == LAYOUT_DIRECTION_RTL; |
||||
} |
||||
|
||||
@Override |
||||
public Parcelable onSaveInstanceState() { |
||||
Parcelable superState = super.onSaveInstanceState(); |
||||
return new PassEdittext2.SavedState(superState, mShowingIcon, mPasswordVisible); |
||||
} |
||||
|
||||
@Override |
||||
public void onRestoreInstanceState(Parcelable state) { |
||||
PasswordEditText.SavedState savedState = (PasswordEditText.SavedState) state; |
||||
super.onRestoreInstanceState(savedState.getSuperState()); |
||||
mShowingIcon = savedState.isShowingIcon(); |
||||
mPasswordVisible = savedState.isPasswordVisible(); |
||||
handlePasswordInputVisibility(); |
||||
showPasswordVisibilityIndicator(mShowingIcon); |
||||
} |
||||
|
||||
@Override |
||||
public void setError(CharSequence error) { |
||||
super.setError(error); |
||||
mSetErrorCalled = true; |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void setError(CharSequence error, Drawable icon) { |
||||
super.setError(error, icon); |
||||
mSetErrorCalled = true; |
||||
} |
||||
|
||||
@Override |
||||
public boolean onTouchEvent(MotionEvent event) { |
||||
if (!mShowingIcon) { |
||||
return super.onTouchEvent(event); |
||||
} else { |
||||
boolean touchable = isTouchable(event); |
||||
switch (event.getAction()) { |
||||
case MotionEvent.ACTION_DOWN: |
||||
if (mHoverShowsPw) { |
||||
if (touchable) { |
||||
togglePasswordIconVisibility(); |
||||
// prevent keyboard from coming up
|
||||
event.setAction(MotionEvent.ACTION_CANCEL); |
||||
mHandlingHoverEvent = true; |
||||
} |
||||
} |
||||
break; |
||||
case MotionEvent.ACTION_UP: |
||||
if (mHandlingHoverEvent || touchable) { |
||||
togglePasswordIconVisibility(); |
||||
// prevent keyboard from coming up
|
||||
event.setAction(MotionEvent.ACTION_CANCEL); |
||||
mHandlingHoverEvent = false; |
||||
} |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
return super.onTouchEvent(event); |
||||
} |
||||
} |
||||
|
||||
private boolean isTouchable(MotionEvent event) { |
||||
boolean touchable; |
||||
if (isRtl()) { |
||||
touchable = event.getX() > getPaddingLeft() - mExtraClickArea && event.getX() < getPaddingLeft() + mShowPwDrawable.getIntrinsicWidth() + mExtraClickArea; |
||||
} else { |
||||
touchable = event.getX() > getWidth() - getPaddingRight() - mShowPwDrawable.getIntrinsicWidth() - mExtraClickArea && event.getX() < getWidth() - getPaddingRight() + mExtraClickArea; |
||||
} |
||||
return touchable; |
||||
} |
||||
|
||||
|
||||
private void showPasswordVisibilityIndicator(boolean shouldShowIcon) { |
||||
if (shouldShowIcon) { |
||||
Drawable drawable = mPasswordVisible ? mShowPwDrawable : mHidePwDrawable; |
||||
mShowingIcon = true; |
||||
setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, drawable, null); |
||||
} else { |
||||
// reset drawable
|
||||
setCompoundDrawablesRelative(null, null, null, null); |
||||
mShowingIcon = false; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* This method toggles the visibility of the icon and takes care of switching the input type |
||||
* of the view to be able to see the password afterwards. |
||||
* <p> |
||||
* This method may only be called if there is an icon visible |
||||
*/ |
||||
private void togglePasswordIconVisibility() { |
||||
mPasswordVisible = !mPasswordVisible; |
||||
handlePasswordInputVisibility(); |
||||
showPasswordVisibilityIndicator(true); |
||||
} |
||||
|
||||
/** |
||||
* This method is called when restoring the state (e.g. on orientation change) |
||||
*/ |
||||
private void handlePasswordInputVisibility() { |
||||
int selectionStart = getSelectionStart(); |
||||
int selectionEnd = getSelectionEnd(); |
||||
if (mPasswordVisible) { |
||||
setTransformationMethod(null); |
||||
} else { |
||||
setTransformationMethod(mTransformationMethod); |
||||
} |
||||
setSelection(selectionStart, selectionEnd); |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Convenience class to save / restore the state of icon. |
||||
*/ |
||||
protected static class SavedState extends BaseSavedState { |
||||
|
||||
private final boolean mShowingIcon; |
||||
private final boolean mPasswordVisible; |
||||
|
||||
private SavedState(Parcelable superState, boolean sI, boolean pV) { |
||||
super(superState); |
||||
mShowingIcon = sI; |
||||
mPasswordVisible = pV; |
||||
} |
||||
|
||||
private SavedState(Parcel in) { |
||||
super(in); |
||||
mShowingIcon = in.readByte() != 0; |
||||
mPasswordVisible = in.readByte() != 0; |
||||
} |
||||
|
||||
public boolean isShowingIcon() { |
||||
return mShowingIcon; |
||||
} |
||||
|
||||
public boolean isPasswordVisible() { |
||||
return mPasswordVisible; |
||||
} |
||||
|
||||
@Override |
||||
public void writeToParcel(Parcel destination, int flags) { |
||||
super.writeToParcel(destination, flags); |
||||
destination.writeByte((byte) (mShowingIcon ? 1 : 0)); |
||||
destination.writeByte((byte) (mPasswordVisible ? 1 : 0)); |
||||
} |
||||
|
||||
public static final Creator<PassEdittext2.SavedState> CREATOR = new Creator<PassEdittext2.SavedState>() { |
||||
|
||||
@Override |
||||
public PassEdittext2.SavedState createFromParcel(Parcel in) { |
||||
return new PassEdittext2.SavedState(in); |
||||
} |
||||
|
||||
@Override |
||||
public PassEdittext2.SavedState[] newArray(int size) { |
||||
return new PassEdittext2.SavedState[size]; |
||||
} |
||||
|
||||
}; |
||||
} |
||||
} |
@ -0,0 +1,323 @@ |
||||
package com.project.survey.widget.edittext; |
||||
|
||||
import android.content.Context; |
||||
import android.content.res.TypedArray; |
||||
import android.graphics.Typeface; |
||||
import android.graphics.drawable.Drawable; |
||||
import android.os.Parcel; |
||||
import android.os.Parcelable; |
||||
import android.text.Editable; |
||||
import android.text.TextWatcher; |
||||
import android.text.method.PasswordTransformationMethod; |
||||
import android.util.AttributeSet; |
||||
import android.view.MotionEvent; |
||||
|
||||
import androidx.appcompat.widget.AppCompatEditText; |
||||
|
||||
import com.project.survey.R; |
||||
import com.project.survey.util.DensityUtils; |
||||
import com.project.survey.util.ResUtils; |
||||
|
||||
|
||||
/** |
||||
* 支持显示密码的输入框 |
||||
* |
||||
* @author xuexiang |
||||
* @since 2019/1/14 下午10:08 |
||||
*/ |
||||
public class PasswordEditText extends AppCompatEditText { |
||||
/** |
||||
* 增大点击区域 |
||||
*/ |
||||
private int mExtraClickArea; |
||||
|
||||
private final static int ALPHA_ICON_ENABLED = (int) (255 * 0.54f); |
||||
private final static int ALPHA_ICON_DISABLED = (int) (255 * 0.38f); |
||||
|
||||
private Drawable mShowPwDrawable; |
||||
private Drawable mHidePwDrawable; |
||||
private boolean mPasswordVisible; |
||||
private boolean mShowingIcon; |
||||
private boolean mSetErrorCalled; |
||||
private boolean mHoverShowsPw; |
||||
private boolean mHandlingHoverEvent; |
||||
private PasswordTransformationMethod mTransformationMethod; |
||||
|
||||
public PasswordEditText(Context context) { |
||||
this(context, null); |
||||
} |
||||
|
||||
public PasswordEditText(Context context, AttributeSet attrs) { |
||||
this(context, attrs, R.attr.PasswordEditTextStyle); |
||||
} |
||||
|
||||
public PasswordEditText(Context context, AttributeSet attrs, int defStyleAttr) { |
||||
super(context, attrs, defStyleAttr); |
||||
initAttrs(context, attrs, defStyleAttr); |
||||
} |
||||
|
||||
public void initAttrs(Context context, AttributeSet attrs, int defStyleAttr) { |
||||
mExtraClickArea = DensityUtils.dp2px(context, 20); |
||||
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.PasswordEditText, defStyleAttr, 0); |
||||
boolean useNonMonospaceFont; |
||||
boolean enableIconAlpha; |
||||
try { |
||||
mShowPwDrawable = ResUtils.getDrawableAttrRes(getContext(), typedArray, R.styleable.PasswordEditText_pet_iconShow); |
||||
if (mShowPwDrawable == null) { |
||||
mShowPwDrawable = ResUtils.getVectorDrawable(getContext(), R.drawable.pet_icon_visibility_24dp); |
||||
} |
||||
mHidePwDrawable = ResUtils.getDrawableAttrRes(getContext(), typedArray, R.styleable.PasswordEditText_pet_iconHide); |
||||
if (mHidePwDrawable == null) { |
||||
mHidePwDrawable = ResUtils.getVectorDrawable(getContext(), R.drawable.pet_icon_visibility_off_24dp); |
||||
} |
||||
mHoverShowsPw = typedArray.getBoolean(R.styleable.PasswordEditText_pet_hoverShowsPw, false); |
||||
useNonMonospaceFont = typedArray.getBoolean(R.styleable.PasswordEditText_pet_nonMonospaceFont, false); |
||||
enableIconAlpha = typedArray.getBoolean(R.styleable.PasswordEditText_pet_enableIconAlpha, true); |
||||
boolean isAsteriskStyle = typedArray.getBoolean(R.styleable.PasswordEditText_pet_isAsteriskStyle, false); |
||||
if (isAsteriskStyle) { |
||||
mTransformationMethod = AsteriskPasswordTransformationMethod.getInstance(); |
||||
} else { |
||||
mTransformationMethod = PasswordTransformationMethod.getInstance(); |
||||
} |
||||
} finally { |
||||
typedArray.recycle(); |
||||
} |
||||
|
||||
if (enableIconAlpha) { |
||||
mHidePwDrawable.setAlpha(ALPHA_ICON_ENABLED); |
||||
mShowPwDrawable.setAlpha(ALPHA_ICON_DISABLED); |
||||
} |
||||
|
||||
if (useNonMonospaceFont) { |
||||
setTypeface(Typeface.DEFAULT); |
||||
} |
||||
|
||||
addTextChangedListener(new TextWatcher() { |
||||
@Override |
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) { |
||||
} |
||||
|
||||
@Override |
||||
public void onTextChanged(CharSequence seq, int start, int before, int count) { |
||||
} |
||||
|
||||
@Override |
||||
public void afterTextChanged(Editable s) { |
||||
if (s.length() > 0) { |
||||
if (mSetErrorCalled) { |
||||
setCompoundDrawablesRelative(null, null, null, null); |
||||
mSetErrorCalled = false; |
||||
showPasswordVisibilityIndicator(true); |
||||
} |
||||
if (!mShowingIcon) { |
||||
showPasswordVisibilityIndicator(true); |
||||
} |
||||
} else { |
||||
// hides the indicator if no text inside text field
|
||||
mPasswordVisible = false; |
||||
handlePasswordInputVisibility(); |
||||
showPasswordVisibilityIndicator(false); |
||||
} |
||||
|
||||
} |
||||
}); |
||||
|
||||
handlePasswordInputVisibility(); |
||||
} |
||||
|
||||
public PasswordEditText setExtraClickAreaSize(int extraClickArea) { |
||||
mExtraClickArea = extraClickArea; |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* 设置密码输入框的样式 |
||||
* |
||||
* @param transformationMethod |
||||
* @return |
||||
*/ |
||||
public PasswordEditText setPasswordTransformationMethod(PasswordTransformationMethod transformationMethod) { |
||||
mTransformationMethod = transformationMethod; |
||||
return this; |
||||
} |
||||
|
||||
/** |
||||
* 设置密码输入框的样式 |
||||
* |
||||
* @param isAsteriskStyle |
||||
* @return |
||||
*/ |
||||
public PasswordEditText setIsAsteriskStyle(boolean isAsteriskStyle) { |
||||
if (isAsteriskStyle) { |
||||
mTransformationMethod = AsteriskPasswordTransformationMethod.getInstance(); |
||||
} else { |
||||
mTransformationMethod = PasswordTransformationMethod.getInstance(); |
||||
} |
||||
return this; |
||||
} |
||||
|
||||
private boolean isRtl() { |
||||
return getLayoutDirection() == LAYOUT_DIRECTION_RTL; |
||||
} |
||||
|
||||
@Override |
||||
public Parcelable onSaveInstanceState() { |
||||
Parcelable superState = super.onSaveInstanceState(); |
||||
return new SavedState(superState, mShowingIcon, mPasswordVisible); |
||||
} |
||||
|
||||
@Override |
||||
public void onRestoreInstanceState(Parcelable state) { |
||||
SavedState savedState = (SavedState) state; |
||||
super.onRestoreInstanceState(savedState.getSuperState()); |
||||
mShowingIcon = savedState.isShowingIcon(); |
||||
mPasswordVisible = savedState.isPasswordVisible(); |
||||
handlePasswordInputVisibility(); |
||||
showPasswordVisibilityIndicator(mShowingIcon); |
||||
} |
||||
|
||||
@Override |
||||
public void setError(CharSequence error) { |
||||
super.setError(error); |
||||
mSetErrorCalled = true; |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public void setError(CharSequence error, Drawable icon) { |
||||
super.setError(error, icon); |
||||
mSetErrorCalled = true; |
||||
} |
||||
|
||||
@Override |
||||
public boolean onTouchEvent(MotionEvent event) { |
||||
if (!mShowingIcon) { |
||||
return super.onTouchEvent(event); |
||||
} else { |
||||
boolean touchable = isTouchable(event); |
||||
switch (event.getAction()) { |
||||
case MotionEvent.ACTION_DOWN: |
||||
if (mHoverShowsPw) { |
||||
if (touchable) { |
||||
togglePasswordIconVisibility(); |
||||
// prevent keyboard from coming up
|
||||
event.setAction(MotionEvent.ACTION_CANCEL); |
||||
mHandlingHoverEvent = true; |
||||
} |
||||
} |
||||
break; |
||||
case MotionEvent.ACTION_UP: |
||||
if (mHandlingHoverEvent || touchable) { |
||||
togglePasswordIconVisibility(); |
||||
// prevent keyboard from coming up
|
||||
event.setAction(MotionEvent.ACTION_CANCEL); |
||||
mHandlingHoverEvent = false; |
||||
} |
||||
break; |
||||
default: |
||||
break; |
||||
} |
||||
return super.onTouchEvent(event); |
||||
} |
||||
} |
||||
|
||||
private boolean isTouchable(MotionEvent event) { |
||||
boolean touchable; |
||||
if (isRtl()) { |
||||
touchable = event.getX() > getPaddingLeft() - mExtraClickArea && event.getX() < getPaddingLeft() + mShowPwDrawable.getIntrinsicWidth() + mExtraClickArea; |
||||
} else { |
||||
touchable = event.getX() > getWidth() - getPaddingRight() - mShowPwDrawable.getIntrinsicWidth() - mExtraClickArea && event.getX() < getWidth() - getPaddingRight() + mExtraClickArea; |
||||
} |
||||
return touchable; |
||||
} |
||||
|
||||
|
||||
private void showPasswordVisibilityIndicator(boolean shouldShowIcon) { |
||||
if (shouldShowIcon) { |
||||
Drawable drawable = mPasswordVisible ? mShowPwDrawable : mHidePwDrawable; |
||||
mShowingIcon = true; |
||||
setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, drawable, null); |
||||
} else { |
||||
// reset drawable
|
||||
setCompoundDrawablesRelative(null, null, null, null); |
||||
mShowingIcon = false; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* This method toggles the visibility of the icon and takes care of switching the input type |
||||
* of the view to be able to see the password afterwards. |
||||
* <p> |
||||
* This method may only be called if there is an icon visible |
||||
*/ |
||||
private void togglePasswordIconVisibility() { |
||||
mPasswordVisible = !mPasswordVisible; |
||||
handlePasswordInputVisibility(); |
||||
showPasswordVisibilityIndicator(true); |
||||
} |
||||
|
||||
/** |
||||
* This method is called when restoring the state (e.g. on orientation change) |
||||
*/ |
||||
private void handlePasswordInputVisibility() { |
||||
int selectionStart = getSelectionStart(); |
||||
int selectionEnd = getSelectionEnd(); |
||||
if (mPasswordVisible) { |
||||
setTransformationMethod(null); |
||||
} else { |
||||
setTransformationMethod(mTransformationMethod); |
||||
} |
||||
setSelection(selectionStart, selectionEnd); |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Convenience class to save / restore the state of icon. |
||||
*/ |
||||
protected static class SavedState extends BaseSavedState { |
||||
|
||||
private final boolean mShowingIcon; |
||||
private final boolean mPasswordVisible; |
||||
|
||||
private SavedState(Parcelable superState, boolean sI, boolean pV) { |
||||
super(superState); |
||||
mShowingIcon = sI; |
||||
mPasswordVisible = pV; |
||||
} |
||||
|
||||
private SavedState(Parcel in) { |
||||
super(in); |
||||
mShowingIcon = in.readByte() != 0; |
||||
mPasswordVisible = in.readByte() != 0; |
||||
} |
||||
|
||||
public boolean isShowingIcon() { |
||||
return mShowingIcon; |
||||
} |
||||
|
||||
public boolean isPasswordVisible() { |
||||
return mPasswordVisible; |
||||
} |
||||
|
||||
@Override |
||||
public void writeToParcel(Parcel destination, int flags) { |
||||
super.writeToParcel(destination, flags); |
||||
destination.writeByte((byte) (mShowingIcon ? 1 : 0)); |
||||
destination.writeByte((byte) (mPasswordVisible ? 1 : 0)); |
||||
} |
||||
|
||||
public static final Creator<SavedState> CREATOR = new Creator<SavedState>() { |
||||
|
||||
@Override |
||||
public SavedState createFromParcel(Parcel in) { |
||||
return new SavedState(in); |
||||
} |
||||
|
||||
@Override |
||||
public SavedState[] newArray(int size) { |
||||
return new SavedState[size]; |
||||
} |
||||
|
||||
}; |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,13 @@ |
||||
package com.project.survey.widget.edittext.materialedittext.validation; |
||||
|
||||
/** |
||||
* 长度验证 |
||||
* |
||||
* @author xuexiang |
||||
* @since 2018/11/26 下午5:06 |
||||
*/ |
||||
public abstract class METLengthChecker { |
||||
|
||||
public abstract int getLength(CharSequence text); |
||||
|
||||
} |
@ -0,0 +1,43 @@ |
||||
package com.project.survey.widget.edittext.materialedittext.validation; |
||||
|
||||
import androidx.annotation.NonNull; |
||||
|
||||
/** |
||||
* 自定义校验器 |
||||
* |
||||
* @author xuexiang |
||||
* @since 2018/11/26 下午5:06 |
||||
*/ |
||||
public abstract class METValidator { |
||||
|
||||
/** |
||||
* Error message that the view will display if validation fails. |
||||
* <p/> |
||||
* This is protected, so you can change this dynamically in your {@link #isValid(CharSequence, boolean)} |
||||
* implementation. If necessary, you can also interact with this via its getter and setter. |
||||
*/ |
||||
protected String errorMessage; |
||||
|
||||
public METValidator(@NonNull String errorMessage) { |
||||
this.errorMessage = errorMessage; |
||||
} |
||||
|
||||
public void setErrorMessage(@NonNull String errorMessage) { |
||||
this.errorMessage = errorMessage; |
||||
} |
||||
|
||||
@NonNull |
||||
public String getErrorMessage() { |
||||
return this.errorMessage; |
||||
} |
||||
|
||||
/** |
||||
* Abstract method to implement your own validation checking. |
||||
* |
||||
* @param text The CharSequence representation of the text in the EditText field. Cannot be null, but may be empty. |
||||
* @param isEmpty Boolean indicating whether or not the text param is empty |
||||
* @return True if valid, false if not |
||||
*/ |
||||
public abstract boolean isValid(@NonNull CharSequence text, boolean isEmpty); |
||||
|
||||
} |
@ -0,0 +1,38 @@ |
||||
/* |
||||
* Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
package com.project.survey.widget.edittext.materialedittext.validation; |
||||
|
||||
import androidx.annotation.NonNull; |
||||
|
||||
/** |
||||
* 非空检验 |
||||
* |
||||
* @author xuexiang |
||||
* @since 2019/5/14 10:27 |
||||
*/ |
||||
public class NotAllowEmptyValidator extends METValidator { |
||||
|
||||
public NotAllowEmptyValidator(@NonNull String errorMessage) { |
||||
super(errorMessage); |
||||
} |
||||
|
||||
@Override |
||||
public boolean isValid(@NonNull CharSequence text, boolean isEmpty) { |
||||
return !isEmpty; |
||||
} |
||||
} |
@ -0,0 +1,31 @@ |
||||
package com.project.survey.widget.edittext.materialedittext.validation; |
||||
|
||||
import androidx.annotation.NonNull; |
||||
|
||||
import java.util.regex.Pattern; |
||||
|
||||
/** |
||||
* 正则表达式验证 |
||||
* |
||||
* @author xuexiang |
||||
* @since 2018/11/26 下午5:06 |
||||
*/ |
||||
public class RegexpValidator extends METValidator { |
||||
|
||||
private Pattern pattern; |
||||
|
||||
public RegexpValidator(@NonNull String errorMessage, @NonNull String regex) { |
||||
super(errorMessage); |
||||
pattern = Pattern.compile(regex); |
||||
} |
||||
|
||||
public RegexpValidator(@NonNull String errorMessage, @NonNull Pattern pattern) { |
||||
super(errorMessage); |
||||
this.pattern = pattern; |
||||
} |
||||
|
||||
@Override |
||||
public boolean isValid(@NonNull CharSequence text, boolean isEmpty) { |
||||
return pattern.matcher(text).matches(); |
||||
} |
||||
} |
@ -0,0 +1,470 @@ |
||||
/* |
||||
* Copyright (C) 2018 xuexiangjys(xuexiangjys@163.com) |
||||
* |
||||
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
* you may not use this file except in compliance with the License. |
||||
* You may obtain a copy of the License at |
||||
* |
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* |
||||
* Unless required by applicable law or agreed to in writing, software |
||||
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
* See the License for the specific language governing permissions and |
||||
* limitations under the License. |
||||
* |
||||
*/ |
||||
|
||||
package com.project.survey.widget.util; |
||||
|
||||
import android.annotation.SuppressLint; |
||||
import android.app.Application; |
||||
import android.content.Context; |
||||
import android.content.pm.ApplicationInfo; |
||||
import android.content.pm.PackageManager; |
||||
import android.content.res.Resources; |
||||
import android.graphics.Bitmap; |
||||
import android.graphics.BitmapFactory; |
||||
import android.graphics.Canvas; |
||||
import android.graphics.Color; |
||||
import android.graphics.ColorFilter; |
||||
import android.graphics.LightingColorFilter; |
||||
import android.graphics.Matrix; |
||||
import android.graphics.PixelFormat; |
||||
import android.graphics.PorterDuff; |
||||
import android.graphics.drawable.BitmapDrawable; |
||||
import android.graphics.drawable.Drawable; |
||||
import android.os.Build; |
||||
import android.text.TextUtils; |
||||
import android.view.View; |
||||
import android.view.ViewGroup; |
||||
import android.widget.AbsListView; |
||||
import android.widget.ImageView; |
||||
import android.widget.ListAdapter; |
||||
import android.widget.ListView; |
||||
import android.widget.RelativeLayout.LayoutParams; |
||||
|
||||
import androidx.annotation.ColorInt; |
||||
import androidx.annotation.Nullable; |
||||
|
||||
import java.io.Closeable; |
||||
import java.io.File; |
||||
import java.io.IOException; |
||||
import java.lang.reflect.InvocationTargetException; |
||||
|
||||
/** |
||||
* 工具类(不建议外部调用) |
||||
* |
||||
* @author xuexiang |
||||
* @since 2018/11/26 下午5:07 |
||||
*/ |
||||
public final class Utils { |
||||
|
||||
private Utils() { |
||||
throw new UnsupportedOperationException("u can't instantiate me..."); |
||||
} |
||||
|
||||
/** |
||||
* 得到设备屏幕的宽度 |
||||
*/ |
||||
public static int getScreenWidth(Context context) { |
||||
return context.getResources().getDisplayMetrics().widthPixels; |
||||
} |
||||
|
||||
/** |
||||
* 得到设备屏幕的高度 |
||||
*/ |
||||
public static int getScreenHeight(Context context) { |
||||
return context.getResources().getDisplayMetrics().heightPixels; |
||||
} |
||||
|
||||
private static final String STATUS_BAR_HEIGHT_RES_NAME = "status_bar_height"; |
||||
|
||||
/** |
||||
* 计算状态栏高度 getStatusBarHeight |
||||
* |
||||
* @param context 上下文 |
||||
* @return 状态栏高度 |
||||
*/ |
||||
public static int getStatusBarHeight(Context context) { |
||||
if (context == null) { |
||||
return getStatusBarHeight(); |
||||
} |
||||
return getInternalDimensionSize(context.getResources(), |
||||
STATUS_BAR_HEIGHT_RES_NAME); |
||||
} |
||||
|
||||
/** |
||||
* 计算状态栏高度 getStatusBarHeight |
||||
* |
||||
* @return 状态栏高度 |
||||
*/ |
||||
public static int getStatusBarHeight() { |
||||
return getInternalDimensionSize(Resources.getSystem(), |
||||
STATUS_BAR_HEIGHT_RES_NAME); |
||||
} |
||||
|
||||
private static int getInternalDimensionSize(Resources res, String key) { |
||||
int result = 0; |
||||
int resourceId = res.getIdentifier(key, "dimen", "android"); |
||||
if (resourceId > 0) { |
||||
result = res.getDimensionPixelSize(resourceId); |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* get ListView height according to every children |
||||
* |
||||
* @param view |
||||
* @return |
||||
*/ |
||||
public static int getListViewHeightBasedOnChildren(ListView view) { |
||||
int height = getAbsListViewHeightBasedOnChildren(view); |
||||
ListAdapter adapter; |
||||
int adapterCount; |
||||
if (view != null && (adapter = view.getAdapter()) != null |
||||
&& (adapterCount = adapter.getCount()) > 0) { |
||||
height += view.getDividerHeight() * (adapterCount - 1); |
||||
} |
||||
return height; |
||||
} |
||||
|
||||
/** |
||||
* get AbsListView height according to every children |
||||
* |
||||
* @param view |
||||
* @return |
||||
*/ |
||||
public static int getAbsListViewHeightBasedOnChildren(AbsListView view) { |
||||
ListAdapter adapter; |
||||
if (view == null || (adapter = view.getAdapter()) == null) { |
||||
return 0; |
||||
} |
||||
|
||||
int height = 0; |
||||
for (int i = 0; i < adapter.getCount(); i++) { |
||||
View item = adapter.getView(i, null, view); |
||||
if (item instanceof ViewGroup) { |
||||
item.setLayoutParams(new LayoutParams( |
||||
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); |
||||
} |
||||
item.measure(0, 0); |
||||
height += item.getMeasuredHeight(); |
||||
} |
||||
height += view.getPaddingTop() + view.getPaddingBottom(); |
||||
return height; |
||||
} |
||||
|
||||
/** |
||||
* View设备背景 |
||||
* |
||||
* @param context 上下文 |
||||
* @param view 控件 |
||||
* @param resId 资源id |
||||
*/ |
||||
public static void setBackground(Context context, View view, int resId) { |
||||
if (view == null) { |
||||
return; |
||||
} |
||||
Bitmap bm = BitmapFactory.decodeResource(context.getResources(), resId); |
||||
BitmapDrawable bd = new BitmapDrawable(context.getResources(), bm); |
||||
view.setBackground(bd); |
||||
} |
||||
|
||||
/** |
||||
* 释放图片资源 |
||||
* |
||||
* @param view 控件 |
||||
*/ |
||||
public static void recycleBackground(View view) { |
||||
Drawable d = view.getBackground(); |
||||
//别忘了把背景设为null,避免onDraw刷新背景时候出现used a recycled bitmap错误
|
||||
view.setBackgroundResource(0); |
||||
if (d != null && d instanceof BitmapDrawable) { |
||||
Bitmap bmp = ((BitmapDrawable) d).getBitmap(); |
||||
if (bmp != null && !bmp.isRecycled()) { |
||||
bmp.recycle(); |
||||
} |
||||
} |
||||
if (d != null) { |
||||
d.setCallback(null); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 遍历View,清除所有ImageView的缓存 |
||||
* |
||||
* @param view |
||||
*/ |
||||
public static void clearImageView(View view) { |
||||
if (view instanceof ViewGroup) { |
||||
ViewGroup parent = (ViewGroup) view; |
||||
int count = parent.getChildCount(); |
||||
for (int i = 0; i < count; i++) { |
||||
clearImageView(parent.getChildAt(i)); |
||||
} |
||||
} else if (view instanceof ImageView) { |
||||
clearImgMemory((ImageView) view); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 清空图片的内存 |
||||
*/ |
||||
public static void clearImgMemory(ImageView imageView) { |
||||
Drawable d = imageView.getDrawable(); |
||||
if (d != null && d instanceof BitmapDrawable) { |
||||
Bitmap bmp = ((BitmapDrawable) d).getBitmap(); |
||||
if (bmp != null && !bmp.isRecycled()) { |
||||
bmp.recycle(); |
||||
} |
||||
} |
||||
imageView.setImageBitmap(null); |
||||
if (d != null) { |
||||
d.setCallback(null); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 放大缩小图片 |
||||
* |
||||
* @param bitmap 源Bitmap |
||||
* @param w 宽 |
||||
* @param h 高 |
||||
* @return 目标Bitmap |
||||
*/ |
||||
public static Bitmap zoom(Bitmap bitmap, int w, int h) { |
||||
int width = bitmap.getWidth(); |
||||
int height = bitmap.getHeight(); |
||||
Matrix matrix = new Matrix(); |
||||
float scaleWidth = ((float) w / width); |
||||
float scaleHeight = ((float) h / height); |
||||
matrix.postScale(scaleWidth, scaleHeight); |
||||
return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true); |
||||
} |
||||
|
||||
/** |
||||
* 安静关闭 IO |
||||
* |
||||
* @param closeables closeables |
||||
*/ |
||||
public static void closeIOQuietly(final Closeable... closeables) { |
||||
if (closeables == null) { |
||||
return; |
||||
} |
||||
for (Closeable closeable : closeables) { |
||||
if (closeable != null) { |
||||
try { |
||||
closeable.close(); |
||||
} catch (IOException ignored) { |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Indicates if this file represents a file on the underlying file system. |
||||
* |
||||
* @param filePath 文件路径 |
||||
* @return 是否存在文件 |
||||
*/ |
||||
public static boolean isFileExist(String filePath) { |
||||
if (TextUtils.isEmpty(filePath)) { |
||||
return false; |
||||
} |
||||
|
||||
File file = new File(filePath); |
||||
return (file.exists() && file.isFile()); |
||||
} |
||||
|
||||
/** |
||||
* 获取bitmap |
||||
* |
||||
* @param filePath 文件路径 |
||||
* @return bitmap |
||||
*/ |
||||
public static Bitmap getBitmap(String filePath) { |
||||
if (!isFileExist(filePath)) { |
||||
return null; |
||||
} |
||||
return BitmapFactory.decodeFile(filePath); |
||||
} |
||||
|
||||
/** |
||||
* 检查是否为空指针 |
||||
* |
||||
* @param object |
||||
* @param hint |
||||
*/ |
||||
public static void checkNull(Object object, String hint) { |
||||
if (null == object) { |
||||
throw new NullPointerException(hint); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 检查是否为空指针 |
||||
* |
||||
* @param t |
||||
* @param message |
||||
*/ |
||||
public static <T> T checkNotNull(T t, String message) { |
||||
if (t == null) { |
||||
throw new NullPointerException(message); |
||||
} |
||||
return t; |
||||
} |
||||
|
||||
/** |
||||
* 旋转图片 |
||||
* |
||||
* @param angle 旋转角度 |
||||
* @param bitmap 要旋转的图片 |
||||
* @return 旋转后的图片 |
||||
*/ |
||||
public static Bitmap rotate(Bitmap bitmap, int angle) { |
||||
Matrix matrix = new Matrix(); |
||||
matrix.postRotate(angle); |
||||
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), |
||||
bitmap.getHeight(), matrix, true); |
||||
} |
||||
|
||||
/** |
||||
* 将Drawable转化为Bitmap |
||||
* |
||||
* @param drawable Drawable |
||||
* @return Bitmap |
||||
*/ |
||||
public static Bitmap getBitmapFromDrawable(Drawable drawable) { |
||||
int width = drawable.getIntrinsicWidth(); |
||||
int height = drawable.getIntrinsicHeight(); |
||||
Bitmap bitmap = Bitmap.createBitmap(width, height, drawable |
||||
.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 |
||||
: Bitmap.Config.RGB_565); |
||||
Canvas canvas = new Canvas(bitmap); |
||||
drawable.setBounds(0, 0, width, height); |
||||
drawable.draw(canvas); |
||||
return bitmap; |
||||
} |
||||
|
||||
/** |
||||
* 将Drawable转化为Bitmap |
||||
* |
||||
* @param drawable Drawable |
||||
* @return Bitmap |
||||
*/ |
||||
public static Bitmap getBitmapFromDrawable(Drawable drawable, int color) { |
||||
int width = drawable.getIntrinsicWidth(); |
||||
int height = drawable.getIntrinsicHeight(); |
||||
Bitmap bitmap = Bitmap.createBitmap(width, height, drawable |
||||
.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 |
||||
: Bitmap.Config.RGB_565); |
||||
Canvas canvas = new Canvas(bitmap); |
||||
canvas.drawColor(color, PorterDuff.Mode.SRC_IN); |
||||
drawable.setBounds(0, 0, width, height); |
||||
drawable.draw(canvas); |
||||
|
||||
bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true); |
||||
canvas = new Canvas(bitmap); |
||||
canvas.drawColor(color, PorterDuff.Mode.SRC_IN); |
||||
return bitmap; |
||||
} |
||||
|
||||
/** |
||||
* 获取应用的图标 |
||||
* |
||||
* @param context |
||||
* @return |
||||
*/ |
||||
public static Drawable getAppIcon(Context context) { |
||||
try { |
||||
PackageManager pm = context.getPackageManager(); |
||||
ApplicationInfo info = pm.getApplicationInfo(context.getPackageName(), 0); |
||||
return info.loadIcon(pm); |
||||
} catch (Exception e) { |
||||
e.printStackTrace(); |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* 支持?attrs属性 http://stackoverflow.com/questions/27986204 :As mentioned here on API < 21 you can't use attrs to color in xml drawable.
|
||||
* |
||||
* @return 支持?attrs属性 |
||||
*/ |
||||
public static boolean isSupportColorAttrs() { |
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP; |
||||
} |
||||
|
||||
public static boolean isLight(int color) { |
||||
return Math.sqrt( |
||||
Color.red(color) * Color.red(color) * .241 + |
||||
Color.green(color) * Color.green(color) * .691 + |
||||
Color.blue(color) * Color.blue(color) * .068) > 130; |
||||
} |
||||
|
||||
public static boolean isNullOrEmpty(@Nullable CharSequence string) { |
||||
return string == null || string.length() == 0; |
||||
} |
||||
|
||||
/** |
||||
* 获取数值的位数,例如9返回1,99返回2,999返回3 |
||||
* |
||||
* @param number 要计算位数的数值,必须>0 |
||||
* @return 数值的位数,若传的参数小于等于0,则返回0 |
||||
*/ |
||||
public static int getNumberDigits(int number) { |
||||
if (number <= 0) { |
||||
return 0; |
||||
} |
||||
return (int) (Math.log10(number) + 1); |
||||
} |
||||
|
||||
/** |
||||
* 设置Drawable的颜色 |
||||
* <b>这里不对Drawable进行mutate(),会影响到所有用到这个Drawable的地方,如果要避免,请先自行mutate()</b> |
||||
*/ |
||||
public static ColorFilter setDrawableTintColor(Drawable drawable, @ColorInt int tintColor) { |
||||
LightingColorFilter colorFilter = new LightingColorFilter(Color.argb(255, 0, 0, 0), tintColor); |
||||
if (drawable != null) { |
||||
drawable.setColorFilter(colorFilter); |
||||
} |
||||
return colorFilter; |
||||
} |
||||
|
||||
public static Application getApplicationByReflect() { |
||||
try { |
||||
@SuppressLint("PrivateApi") |
||||
Class<?> activityThread = Class.forName("android.app.ActivityThread"); |
||||
Object thread = activityThread.getMethod("currentActivityThread").invoke(null); |
||||
Object app = activityThread.getMethod("getApplication").invoke(thread); |
||||
if (app == null) { |
||||
throw new NullPointerException("you should init first"); |
||||
} |
||||
return (Application) app; |
||||
} catch (NoSuchMethodException e) { |
||||
e.printStackTrace(); |
||||
} catch (IllegalAccessException e) { |
||||
e.printStackTrace(); |
||||
} catch (InvocationTargetException e) { |
||||
e.printStackTrace(); |
||||
} catch (ClassNotFoundException e) { |
||||
e.printStackTrace(); |
||||
} |
||||
throw new NullPointerException("you should init first"); |
||||
} |
||||
|
||||
/** |
||||
* 类型强转 |
||||
* |
||||
* @param object 需要强转的对象 |
||||
* @param clazz 需要强转的类型 |
||||
* @param <T> |
||||
* @return 类型强转结果 |
||||
*/ |
||||
public static <T> T cast(final Object object, Class<T> clazz) { |
||||
return clazz != null && clazz.isInstance(object) ? (T) object : null; |
||||
} |
||||
|
||||
} |
@ -0,0 +1,10 @@ |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="16dp" |
||||
android:height="16dp" |
||||
android:viewportWidth="16" |
||||
android:viewportHeight="16"> |
||||
<path |
||||
android:pathData="M7.992,16C3.576,16 0,12.416 0,8C0,3.584 3.576,0 7.992,0C12.416,0 16,3.584 16,8C16,12.416 12.416,16 7.992,16ZM8,1.6Q8.157,1.6 8.314,1.608Q8.471,1.615 8.627,1.631Q8.784,1.646 8.939,1.669Q9.094,1.692 9.249,1.723Q9.403,1.754 9.555,1.792Q9.707,1.83 9.858,1.876Q10.008,1.921 10.156,1.974Q10.304,2.027 10.449,2.087Q10.594,2.147 10.736,2.215Q10.878,2.282 11.017,2.356Q11.156,2.43 11.29,2.511Q11.425,2.591 11.556,2.679Q11.686,2.766 11.813,2.86Q11.939,2.953 12.06,3.053Q12.182,3.152 12.298,3.258Q12.414,3.363 12.526,3.475Q12.637,3.586 12.742,3.702Q12.848,3.819 12.947,3.94Q13.047,4.061 13.141,4.188Q13.234,4.314 13.321,4.444Q13.409,4.575 13.489,4.71Q13.57,4.844 13.644,4.983Q13.718,5.122 13.785,5.264Q13.853,5.406 13.913,5.551Q13.973,5.696 14.026,5.844Q14.079,5.992 14.124,6.142Q14.17,6.293 14.208,6.445Q14.246,6.597 14.277,6.751Q14.308,6.906 14.331,7.061Q14.354,7.216 14.369,7.373Q14.385,7.529 14.392,7.686Q14.4,7.843 14.4,8Q14.4,8.157 14.392,8.314Q14.385,8.471 14.369,8.627Q14.354,8.784 14.331,8.939Q14.308,9.095 14.277,9.249Q14.246,9.403 14.208,9.555Q14.17,9.708 14.124,9.858Q14.079,10.008 14.026,10.156Q13.973,10.304 13.913,10.449Q13.853,10.594 13.785,10.736Q13.718,10.878 13.644,11.017Q13.57,11.156 13.489,11.29Q13.409,11.425 13.321,11.556Q13.234,11.686 13.141,11.813Q13.047,11.939 12.947,12.06Q12.848,12.182 12.742,12.298Q12.637,12.414 12.526,12.526Q12.414,12.637 12.298,12.742Q12.182,12.848 12.06,12.947Q11.939,13.047 11.813,13.141Q11.686,13.234 11.556,13.321Q11.425,13.409 11.29,13.489Q11.156,13.57 11.017,13.644Q10.878,13.718 10.736,13.786Q10.594,13.853 10.449,13.913Q10.304,13.973 10.156,14.026Q10.008,14.079 9.858,14.124Q9.707,14.17 9.555,14.208Q9.403,14.246 9.249,14.277Q9.094,14.308 8.939,14.331Q8.784,14.354 8.627,14.369Q8.471,14.385 8.314,14.392Q8.157,14.4 8,14.4Q7.843,14.4 7.686,14.392Q7.529,14.385 7.373,14.369Q7.216,14.354 7.061,14.331Q6.905,14.308 6.751,14.277Q6.597,14.246 6.445,14.208Q6.293,14.17 6.142,14.124Q5.992,14.079 5.844,14.026Q5.696,13.973 5.551,13.913Q5.406,13.853 5.264,13.786Q5.122,13.718 4.983,13.644Q4.844,13.57 4.71,13.489Q4.575,13.409 4.444,13.321Q4.314,13.234 4.188,13.141Q4.061,13.047 3.94,12.947Q3.818,12.848 3.702,12.742Q3.586,12.637 3.474,12.526Q3.363,12.414 3.258,12.298Q3.152,12.182 3.053,12.06Q2.953,11.939 2.859,11.813Q2.766,11.686 2.679,11.556Q2.591,11.425 2.511,11.29Q2.43,11.156 2.356,11.017Q2.282,10.878 2.214,10.736Q2.147,10.594 2.087,10.449Q2.027,10.304 1.974,10.156Q1.921,10.008 1.876,9.858Q1.83,9.708 1.792,9.555Q1.754,9.403 1.723,9.249Q1.692,9.095 1.669,8.939Q1.646,8.784 1.631,8.627Q1.615,8.471 1.608,8.314Q1.6,8.157 1.6,8Q1.6,7.843 1.608,7.686Q1.615,7.529 1.631,7.373Q1.646,7.216 1.669,7.061Q1.692,6.906 1.723,6.751Q1.754,6.597 1.792,6.445Q1.83,6.293 1.876,6.142Q1.921,5.992 1.974,5.844Q2.027,5.696 2.087,5.551Q2.147,5.406 2.214,5.264Q2.282,5.122 2.356,4.983Q2.43,4.844 2.511,4.71Q2.591,4.575 2.679,4.444Q2.766,4.314 2.859,4.188Q2.953,4.061 3.053,3.94Q3.152,3.819 3.258,3.702Q3.363,3.586 3.474,3.475Q3.586,3.363 3.702,3.258Q3.818,3.152 3.94,3.053Q4.061,2.953 4.188,2.86Q4.314,2.766 4.444,2.679Q4.575,2.591 4.71,2.511Q4.844,2.43 4.983,2.356Q5.122,2.282 5.264,2.215Q5.406,2.147 5.551,2.087Q5.696,2.027 5.844,1.974Q5.992,1.921 6.142,1.876Q6.293,1.83 6.445,1.792Q6.597,1.754 6.751,1.723Q6.905,1.692 7.061,1.669Q7.216,1.646 7.373,1.631Q7.529,1.615 7.686,1.608Q7.843,1.6 8,1.6ZM8.8,11.2C8.8,11.64 8.44,12 8,12C7.56,12 7.2,11.64 7.2,11.2L7.2,8C7.2,7.56 7.56,7.2 8,7.2C8.44,7.2 8.8,7.56 8.8,8L8.8,11.2ZM7.2,5.6L7.2,4L8.8,4L8.8,5.6L7.2,5.6Z" |
||||
android:fillColor="#D77A25" |
||||
android:fillType="evenOdd"/> |
||||
</vector> |
@ -0,0 +1,9 @@ |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="6dp" |
||||
android:height="10dp" |
||||
android:viewportWidth="6" |
||||
android:viewportHeight="10"> |
||||
<path |
||||
android:pathData="M5.877,4.718L0.734,0.111C0.569,-0.037 0.296,-0.037 0.124,0.111C-0.041,0.259 -0.041,0.503 0.124,0.658L4.972,5.001L0.131,9.337C-0.034,9.485 -0.034,9.73 0.131,9.884C0.217,9.961 0.325,10 0.433,10C0.54,10 0.655,9.961 0.734,9.884L5.877,5.277C5.963,5.2 6.006,5.097 5.999,5.001C6.006,4.891 5.963,4.795 5.877,4.718Z" |
||||
android:fillColor="#5B5A5E"/> |
||||
</vector> |
@ -0,0 +1,9 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:shape="rectangle"> |
||||
<gradient |
||||
android:angle="0" |
||||
android:endColor="#396BD0" |
||||
android:startColor="#3F79F0" /> |
||||
<corners android:radius="@dimen/sw_4dp" /> |
||||
</shape> |
@ -0,0 +1,5 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android"> |
||||
<item android:drawable="@drawable/pwd_show" android:state_selected="true" /> |
||||
<item android:drawable="@drawable/pwd_hide" android:state_selected="false" /> |
||||
</selector> |
@ -0,0 +1,10 @@ |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="12.444dp" |
||||
android:height="16dp" |
||||
android:viewportWidth="12.444" |
||||
android:viewportHeight="16"> |
||||
<path |
||||
android:pathData="M10.111,5.333L10.889,5.333C11.744,5.333 12.444,6.019 12.444,6.857L12.444,14.476C12.444,15.314 11.744,16 10.889,16L1.556,16C0.7,16 0,15.314 0,14.476L0,6.857C0,6.019 0.7,5.333 1.556,5.333L2.333,5.333L2.333,3.81C2.333,1.707 4.076,0 6.222,0C8.369,0 10.111,1.707 10.111,3.81L10.111,5.333ZM6.222,1.524C4.931,1.524 3.889,2.545 3.889,3.81L3.889,5.333L8.556,5.333L8.556,3.81C8.556,2.545 7.513,1.524 6.222,1.524ZM1.556,14.476L10.889,14.476L10.889,6.857L1.556,6.857L1.556,14.476ZM6.222,12.191C7.078,12.191 7.778,11.505 7.778,10.667C7.778,9.829 7.078,9.143 6.222,9.143C5.367,9.143 4.667,9.829 4.667,10.667C4.667,11.505 5.367,12.191 6.222,12.191Z" |
||||
android:fillColor="#C53E28" |
||||
android:fillType="evenOdd"/> |
||||
</vector> |
@ -0,0 +1,10 @@ |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="16dp" |
||||
android:height="14dp" |
||||
android:viewportWidth="16" |
||||
android:viewportHeight="14"> |
||||
<path |
||||
android:pathData="M16,14L8,0L0,14L16,14ZM8.727,8.842L7.273,8.842L7.273,4.912L8.727,4.912L8.727,8.842ZM7.273,11.79L8.727,11.79L8.727,10.316L7.273,10.316L7.273,11.79Z" |
||||
android:fillColor="#CC5155" |
||||
android:fillType="evenOdd"/> |
||||
</vector> |
@ -0,0 +1,9 @@ |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="24dp" |
||||
android:height="24dp" |
||||
android:viewportWidth="24.0" |
||||
android:viewportHeight="24.0"> |
||||
<path |
||||
android:fillColor="#FF000000" |
||||
android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zm0,-8c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z" /> |
||||
</vector> |
@ -0,0 +1,9 @@ |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="24dp" |
||||
android:height="24dp" |
||||
android:viewportWidth="24.0" |
||||
android:viewportHeight="24.0"> |
||||
<path |
||||
android:fillColor="#FF000000" |
||||
android:pathData="M12,7c2.76,0 5,2.24 5,5 0,0.65 -0.13,1.26 -0.36,1.83l2.92,2.92c1.51,-1.26 2.7,-2.89 3.43,-4.75 -1.73,-4.39 -6,-7.5 -11,-7.5 -1.4,0 -2.74,0.25 -3.98,0.7l2.16,2.16C10.74,7.13 11.35,7 12,7zM2,4.27l2.28,2.28 0.46,0.46C3.08,8.3 1.78,10.02 1,12c1.73,4.39 6,7.5 11,7.5 1.55,0 3.03,-0.3 4.38,-0.84l0.42,0.42L19.73,22 21,20.73 3.27,3 2,4.27zM7.53,9.8l1.55,1.55c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.66 1.34,3 3,3 0.22,0 0.44,-0.03 0.65,-0.08l1.55,1.55c-0.67,0.33 -1.41,0.53 -2.2,0.53 -2.76,0 -5,-2.24 -5,-5 0,-0.79 0.2,-1.53 0.53,-2.2zm4.31,-0.78l3.15,3.15 0.02,-0.16c0,-1.66 -1.34,-3 -3,-3l-0.17,0.01z" /> |
||||
</vector> |
@ -0,0 +1,10 @@ |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="16dp" |
||||
android:height="13.333dp" |
||||
android:viewportWidth="16" |
||||
android:viewportHeight="13.333"> |
||||
<path |
||||
android:pathData="M0.728,0.889L2.387,2.489L2.722,2.812C1.514,3.712 0.573,4.923 0,6.316C1.354,9.529 4.513,11.607 8,11.579C9.089,11.58 10.17,11.38 11.187,10.989L11.492,11.284L13.628,13.333L14.553,12.444L1.652,0L0.728,0.889ZM8,2.807C8.949,2.789 9.865,3.148 10.549,3.806C11.232,4.464 11.627,5.367 11.644,6.316C11.642,6.757 11.552,7.194 11.378,7.6L13.502,9.649C14.604,8.768 15.464,7.621 16,6.316C14.646,3.102 11.487,1.024 8,1.052C7.014,1.052 6.035,1.218 5.104,1.544L6.672,3.06C7.095,2.893 7.545,2.808 8,2.807ZM7.887,4.224L10.179,6.435L10.193,6.323C10.183,5.754 9.948,5.212 9.538,4.817C9.128,4.423 8.579,4.207 8.01,4.218L7.887,4.224ZM4.751,4.772L5.879,5.86C5.842,6.009 5.822,6.162 5.821,6.316C5.84,6.965 6.149,7.573 6.664,7.97C7.178,8.367 7.844,8.512 8.477,8.364L9.6,9.452C9.101,9.694 8.554,9.821 8,9.824C6.027,9.858 4.399,8.288 4.362,6.316C4.367,5.777 4.5,5.248 4.751,4.772Z" |
||||
android:fillColor="#5B5A5E" |
||||
android:fillType="evenOdd"/> |
||||
</vector> |
@ -0,0 +1,10 @@ |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="16dp" |
||||
android:height="10.667dp" |
||||
android:viewportWidth="16" |
||||
android:viewportHeight="10.667"> |
||||
<path |
||||
android:pathData="M8,0C4.496,-0.018 1.331,2.092 0,5.333C1.331,8.575 4.496,10.685 8,10.667C11.504,10.685 14.669,8.575 16,5.333C14.669,2.092 11.504,-0.018 8,0ZM8,8.889C6.048,8.845 4.496,7.234 4.526,5.281C4.555,3.328 6.154,1.764 8.107,1.779C10.06,1.793 11.636,3.38 11.637,5.333C11.613,7.319 9.986,8.91 8,8.889ZM5.916,5.365C5.898,4.194 6.829,3.227 8,3.2C8.573,3.193 9.124,3.414 9.534,3.814C9.943,4.214 10.177,4.761 10.182,5.333C10.182,6.505 9.237,7.457 8.065,7.466C6.893,7.475 5.934,6.537 5.916,5.365Z" |
||||
android:fillColor="#5B5A5E" |
||||
android:fillType="evenOdd"/> |
||||
</vector> |
@ -0,0 +1,10 @@ |
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="13.333dp" |
||||
android:height="16dp" |
||||
android:viewportWidth="13.333" |
||||
android:viewportHeight="16"> |
||||
<path |
||||
android:pathData="M1.667,0L11.667,0C12.583,0 13.333,0.72 13.333,1.6L13.333,14.4C13.333,15.28 12.583,16 11.667,16L1.667,16C0.75,16 0,15.28 0,14.4L0,1.6C0,0.72 0.75,0 1.667,0ZM11.667,14.4L1.667,14.4L1.667,1.6L2.5,1.6L2.5,8.8L5,7L7.5,8.8L7.5,1.6L11.667,1.6L11.667,14.4ZM4.167,1.6L5.833,1.6L5.833,5.6L5,5L4.167,5.6L4.167,1.6Z" |
||||
android:fillColor="#396BD0" |
||||
android:fillType="evenOdd"/> |
||||
</vector> |
@ -0,0 +1,26 @@ |
||||
<!-- |
||||
~ Copyright (C) 2019 xuexiangjys(xuexiangjys@163.com) |
||||
~ |
||||
~ Licensed under the Apache License, Version 2.0 (the "License"); |
||||
~ you may not use this file except in compliance with the License. |
||||
~ You may obtain a copy of the License at |
||||
~ |
||||
~ http://www.apache.org/licenses/LICENSE-2.0 |
||||
~ |
||||
~ Unless required by applicable law or agreed to in writing, software |
||||
~ distributed under the License is distributed on an "AS IS" BASIS, |
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
~ See the License for the specific language governing permissions and |
||||
~ limitations under the License. |
||||
~ |
||||
--> |
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:width="21dp" |
||||
android:height="21dp" |
||||
android:viewportWidth="1024" |
||||
android:viewportHeight="1024"> |
||||
<path |
||||
android:fillColor="#8A8A8A" |
||||
android:pathData="M513.34,0a512,512 0,1 0,0 1024,512 512,0 0,0 0,-1024zM739.39,674.62l-54.53,56.9 -171.52,-164.93 -171.39,164.93 -54.59,-56.9L456.58,512 287.36,349.31l54.59,-56.77 171.39,164.8 171.52,-164.8 54.53,56.77L570.18,512l169.22,162.62z" /> |
||||
</vector> |
@ -0,0 +1,166 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
android:focusable="true" |
||||
android:focusableInTouchMode="true" |
||||
android:orientation="vertical" |
||||
android:paddingHorizontal="@dimen/sw_22dp"> |
||||
|
||||
<TextView |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginTop="@dimen/sw_55dp" |
||||
android:text="@string/engineering_surveying_integrated_management_system" |
||||
android:textColor="@color/text_color_1" |
||||
android:textSize="@dimen/sw_22sp" |
||||
android:textStyle="bold" /> |
||||
|
||||
<TextView |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:text="@string/engineering_surveying_integrated_management_system_en" |
||||
android:textColor="@color/text_color_1" |
||||
android:textSize="@dimen/sw_9sp" |
||||
android:textStyle="bold" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/tvAccountDesc" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginTop="@dimen/sw_55dp" |
||||
android:text="@string/group_account_login" |
||||
android:textColor="@color/text_color_1" |
||||
android:textSize="@dimen/sw_22sp" |
||||
android:textStyle="bold" /> |
||||
|
||||
<TextView |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginTop="@dimen/sw_15dp" |
||||
android:text="@string/account" |
||||
android:textColor="@color/c_727778" |
||||
android:textSize="@dimen/sw_11sp" /> |
||||
|
||||
<EditText |
||||
android:id="@+id/etAccount" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:text="" |
||||
android:textColor="@color/text_color_1" |
||||
android:textSize="@dimen/sw_14sp" /> |
||||
|
||||
<TextView |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginTop="@dimen/sw_15dp" |
||||
android:text="@string/password" |
||||
android:textColor="@color/c_727778" |
||||
android:textSize="@dimen/sw_11sp" /> |
||||
|
||||
<RelativeLayout |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content"> |
||||
|
||||
<EditText |
||||
android:id="@+id/etPwd" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:inputType="textPassword" |
||||
android:textColor="@color/text_color_1" |
||||
android:textSize="@dimen/sw_14sp" /> |
||||
|
||||
<FrameLayout |
||||
android:id="@+id/pwdShowHide" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_alignParentEnd="true" |
||||
android:layout_centerVertical="true" |
||||
android:padding="@dimen/sw_12dp"> |
||||
|
||||
<ImageView |
||||
android:id="@+id/ivPwdShowHide" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:background="@drawable/bg_pwd_sc" /> |
||||
|
||||
</FrameLayout> |
||||
|
||||
|
||||
</RelativeLayout> |
||||
|
||||
<TextView |
||||
android:id="@+id/tvError" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginTop="@dimen/sw_6dp" |
||||
android:drawablePadding="@dimen/sw_6dp" |
||||
android:text="" |
||||
android:visibility="invisible" |
||||
app:drawableStartCompat="@drawable/login_error" /> |
||||
|
||||
<Button |
||||
android:id="@+id/btnLogin" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginTop="@dimen/sw_24dp" |
||||
android:background="@drawable/bg_btn_login" |
||||
android:text="@string/login" |
||||
android:textColor="@color/white" |
||||
android:textSize="@dimen/sw_16sp" /> |
||||
|
||||
<!--显示外部账号登录--> |
||||
<LinearLayout |
||||
android:id="@+id/llShowOutLogin" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginTop="12dp" |
||||
android:gravity="center"> |
||||
|
||||
<TextView |
||||
android:id="@+id/tvShowOutLogin" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:padding="6dp" |
||||
android:text="@string/external_account_login" |
||||
android:textColor="@color/c_727778" |
||||
android:textSize="@dimen/sw_14sp" /> |
||||
|
||||
</LinearLayout> |
||||
|
||||
<!--显示集团账号登录--> |
||||
<LinearLayout |
||||
android:id="@+id/llShowInnerLogin" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginTop="12dp" |
||||
android:gravity="center" |
||||
android:visibility="gone"> |
||||
|
||||
<TextView |
||||
android:id="@+id/tvShowInnerLogin" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:padding="6dp" |
||||
android:text="@string/group_account_login" |
||||
android:textColor="@color/c_727778" |
||||
android:textSize="@dimen/sw_14sp" /> |
||||
|
||||
<View |
||||
android:layout_width="@dimen/sw_1dp" |
||||
android:layout_height="@dimen/sw_12dp" |
||||
android:background="@color/c_727778" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/tvForgetPwd" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:padding="6dp" |
||||
android:text="@string/forget_the_password" |
||||
android:textColor="@color/c_727778" |
||||
android:textSize="@dimen/sw_14sp" /> |
||||
|
||||
</LinearLayout> |
||||
|
||||
</LinearLayout> |
@ -1,11 +1,183 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
xmlns:tools="http://schemas.android.com/tools" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="match_parent" |
||||
android:orientation="vertical"> |
||||
|
||||
<LinearLayout |
||||
android:layout_width="match_parent" |
||||
android:layout_height="@dimen/sw_140dp" |
||||
android:background="@color/c_2964da" |
||||
android:gravity="center_vertical" |
||||
android:orientation="vertical" |
||||
android:paddingStart="@dimen/sw_26dp" |
||||
app:layout_constraintStart_toStartOf="parent" |
||||
app:layout_constraintTop_toTopOf="parent"> |
||||
|
||||
<TextView |
||||
android:id="@+id/tvName" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:text="我的" /> |
||||
android:text="请登录" |
||||
android:textColor="@color/white" |
||||
android:textSize="@dimen/sw_22sp" |
||||
android:textStyle="bold" |
||||
app:layout_constraintStart_toStartOf="parent" |
||||
app:layout_constraintTop_toTopOf="parent" /> |
||||
|
||||
<TextView |
||||
android:id="@+id/tvCompany" |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:layout_marginTop="@dimen/sw_10dp" |
||||
android:textColor="@color/white" |
||||
android:textSize="@dimen/sw_15sp" |
||||
app:layout_constraintStart_toStartOf="parent" |
||||
app:layout_constraintTop_toTopOf="parent" |
||||
tools:text="某工程" /> |
||||
|
||||
</LinearLayout> |
||||
|
||||
<LinearLayout |
||||
android:id="@+id/llSwitchProject" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="@dimen/sw_48dp" |
||||
android:layout_marginTop="@dimen/sw_8dp" |
||||
android:background="@color/white" |
||||
android:gravity="center_vertical" |
||||
android:orientation="horizontal" |
||||
android:paddingHorizontal="@dimen/sw_16dp" |
||||
app:layout_constraintStart_toStartOf="parent" |
||||
app:layout_constraintTop_toBottomOf="@+id/llTop"> |
||||
|
||||
<TextView |
||||
android:layout_width="0dp" |
||||
android:layout_height="wrap_content" |
||||
android:layout_weight="1" |
||||
android:drawablePadding="@dimen/sw_16dp" |
||||
android:text="@string/switch_project" |
||||
android:textColor="@color/text_color_1" |
||||
android:textSize="@dimen/sw_15sp" |
||||
app:drawableLeftCompat="@drawable/switch_project" /> |
||||
|
||||
<ImageView |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:src="@drawable/arrow_right" /> |
||||
|
||||
</LinearLayout> |
||||
|
||||
<include |
||||
layout="@layout/line_hor" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="@dimen/sw_0_5dp" |
||||
android:layout_marginStart="@dimen/sw_45dp" /> |
||||
|
||||
<LinearLayout |
||||
android:id="@+id/llChangePwd" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="@dimen/sw_48dp" |
||||
android:background="@color/white" |
||||
android:gravity="center_vertical" |
||||
android:orientation="horizontal" |
||||
android:paddingHorizontal="@dimen/sw_16dp" |
||||
app:layout_constraintStart_toStartOf="parent" |
||||
app:layout_constraintTop_toBottomOf="@+id/llTop"> |
||||
|
||||
<TextView |
||||
android:layout_width="0dp" |
||||
android:layout_height="wrap_content" |
||||
android:layout_weight="1" |
||||
android:drawablePadding="@dimen/sw_16dp" |
||||
android:text="@string/change_pwd" |
||||
android:textColor="@color/text_color_1" |
||||
android:textSize="@dimen/sw_15sp" |
||||
app:drawableStartCompat="@drawable/change_pwd" /> |
||||
|
||||
<ImageView |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:src="@drawable/arrow_right" /> |
||||
|
||||
</LinearLayout> |
||||
|
||||
<include |
||||
layout="@layout/line_hor" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="@dimen/sw_0_5dp" |
||||
android:layout_marginStart="@dimen/sw_45dp" /> |
||||
|
||||
<LinearLayout |
||||
android:id="@+id/llAbout" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="@dimen/sw_48dp" |
||||
android:background="@color/white" |
||||
android:gravity="center_vertical" |
||||
android:orientation="horizontal" |
||||
android:paddingHorizontal="@dimen/sw_16dp" |
||||
app:layout_constraintStart_toStartOf="parent" |
||||
app:layout_constraintTop_toBottomOf="@+id/llTop"> |
||||
|
||||
<TextView |
||||
android:layout_width="0dp" |
||||
android:layout_height="wrap_content" |
||||
android:layout_weight="1" |
||||
android:drawablePadding="@dimen/sw_16dp" |
||||
android:text="@string/about" |
||||
android:textColor="@color/text_color_1" |
||||
android:textSize="@dimen/sw_15sp" |
||||
app:drawableStartCompat="@drawable/about" /> |
||||
|
||||
<ImageView |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:src="@drawable/arrow_right" /> |
||||
|
||||
</LinearLayout> |
||||
|
||||
<LinearLayout |
||||
android:id="@+id/llLogin" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="@dimen/sw_48dp" |
||||
android:layout_marginTop="@dimen/sw_8dp" |
||||
android:background="@color/white" |
||||
android:gravity="center" |
||||
android:orientation="horizontal" |
||||
android:paddingHorizontal="@dimen/sw_16dp" |
||||
app:layout_constraintStart_toStartOf="parent" |
||||
app:layout_constraintTop_toBottomOf="@+id/llTop"> |
||||
|
||||
<TextView |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:text="@string/login" |
||||
android:textColor="@color/text_color_1" |
||||
android:textSize="@dimen/sw_15sp" /> |
||||
|
||||
</LinearLayout> |
||||
|
||||
<LinearLayout |
||||
android:id="@+id/llLoginOut" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="@dimen/sw_48dp" |
||||
android:layout_marginTop="@dimen/sw_8dp" |
||||
android:background="@color/white" |
||||
android:gravity="center" |
||||
android:orientation="horizontal" |
||||
android:paddingHorizontal="@dimen/sw_16dp" |
||||
android:visibility="gone" |
||||
app:layout_constraintStart_toStartOf="parent" |
||||
app:layout_constraintTop_toBottomOf="@+id/llTop"> |
||||
|
||||
<TextView |
||||
android:layout_width="wrap_content" |
||||
android:layout_height="wrap_content" |
||||
android:text="@string/login_out" |
||||
android:textColor="@color/text_color_1" |
||||
android:textSize="@dimen/sw_15sp" /> |
||||
|
||||
</LinearLayout> |
||||
|
||||
</LinearLayout> |
@ -0,0 +1,5 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<View xmlns:android="http://schemas.android.com/apk/res/android" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="@dimen/sw_0_5dp" |
||||
android:background="@color/c_ebebeb" /> |
@ -0,0 +1,10 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<androidx.appcompat.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android" |
||||
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||
android:id="@+id/toolbar" |
||||
android:layout_width="match_parent" |
||||
android:layout_height="wrap_content" |
||||
android:background="?colorPrimary" |
||||
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" |
||||
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" /> |
||||
|
@ -0,0 +1,131 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources> |
||||
<attr name="PasswordEditTextStyle" format="reference" /> |
||||
<attr name="MaterialEditTextStyle" format="reference" /> |
||||
<attr name="md_dialog_frame_margin" format="dimension"/> |
||||
|
||||
<attr name="md_button_height" format="dimension"/> |
||||
<attr name="md_button_padding_horizontal" format="dimension"/> |
||||
<attr name="md_listitem_textsize" format="dimension"/> |
||||
|
||||
<!--出错文字的颜色--> |
||||
<attr name="xui_config_color_error_text" format="color" /> |
||||
|
||||
<!-- MaterialEditText --> |
||||
<declare-styleable name="MaterialEditText"> |
||||
<!-- 线和文字的基础颜色,默认是black --> |
||||
<attr name="met_baseColor" format="color" /> |
||||
<!-- 高亮样式的颜色 --> |
||||
<attr name="met_primaryColor" format="color" /> |
||||
<!-- 悬浮提示文字的样式(默认是none)--> |
||||
<attr name="met_floatingLabel" format="enum"> |
||||
<enum name="none" value="0" /> |
||||
<enum name="normal" value="1" /> |
||||
<enum name="highlight" value="2" /> |
||||
</attr> |
||||
<!-- 出现错误时文字的颜色 --> |
||||
<attr name="met_errorColor" format="color" /> |
||||
<!-- 是否允许输入为空, 默认是true --> |
||||
<attr name="met_allowEmpty" format="boolean" /> |
||||
<!-- 为空的错误提示,默认是“输入不能为空” --> |
||||
<attr name="met_errorEmpty" format="string" /> |
||||
<!-- 最少文字的限制(0代表无限)--> |
||||
<attr name="met_minCharacters" format="integer" /> |
||||
<!-- 最多文字的限制(0代表无限) --> |
||||
<attr name="met_maxCharacters" format="integer" /> |
||||
<!-- 底部文字是否显示单行,显示不全的省略号 --> |
||||
<attr name="met_singleLineEllipsis" format="boolean" /> |
||||
<!-- 底部文字最小的行数 --> |
||||
<attr name="met_minBottomTextLines" format="integer" /> |
||||
<!-- 在底部的辅助文字 --> |
||||
<attr name="met_helperText" format="string" /> |
||||
<!-- 辅助文字的颜色 --> |
||||
<attr name="met_helperTextColor" format="color" /> |
||||
<!-- 强调文字的字体 --> |
||||
<attr name="met_accentTypeface" format="string" /> |
||||
<!-- 输入框字体 --> |
||||
<attr name="met_typeface" format="string" /> |
||||
<!-- 自定义悬浮提示文字 --> |
||||
<attr name="met_floatingLabelText" format="string" /> |
||||
<!-- 输入框文字与悬浮提示文字的间距 --> |
||||
<attr name="met_floatingLabelPadding" format="dimension" /> |
||||
<!-- 隐藏底线 --> |
||||
<attr name="met_hideUnderline" format="boolean" /> |
||||
<!-- 输入框底线的颜色 --> |
||||
<attr name="met_underlineColor" format="color" /> |
||||
<!-- 输入框底线的高度,默认1dp --> |
||||
<attr name="met_underlineHeight" format="dimension" /> |
||||
<!-- 输入框聚焦时底线的高度,默认2dp --> |
||||
<attr name="met_underlineHeightFocused" format="dimension" /> |
||||
<!-- 是否自动校验 --> |
||||
<attr name="met_autoValidate" format="boolean" /> |
||||
<!-- 左侧图标资源 --> |
||||
<attr name="met_iconLeft" format="reference" /> |
||||
<!-- 右侧图标资源 --> |
||||
<attr name="met_iconRight" format="reference" /> |
||||
<!-- 图标与输入区域的距离(默认8dp) --> |
||||
<attr name="met_iconPadding" format="dimension" /> |
||||
<!-- 是否使用清除按钮 --> |
||||
<attr name="met_clearButton" format="boolean" /> |
||||
<!-- 是否使用显示密码按钮 --> |
||||
<attr name="met_passWordButton" format="boolean" /> |
||||
<!--密码输入框文字的样式是否是“*”,默认是false--> |
||||
<attr name="met_isAsteriskStyle" format="boolean" /> |
||||
<!-- 悬浮提示文字的大小(默认12sp) --> |
||||
<attr name="met_floatingLabelTextSize" format="dimension" /> |
||||
<!-- 悬浮提示文字的颜色 --> |
||||
<attr name="met_floatingLabelTextColor" format="color" /> |
||||
<!-- 底部提示文字的大小(默认12sp)--> |
||||
<attr name="met_bottomTextSize" format="dimension" /> |
||||
<!-- 悬浮提示一直显示(而不是通过动画显示/消失,默认false) --> |
||||
<attr name="met_floatingLabelAlwaysShown" format="boolean" /> |
||||
<!-- 是否一直显示辅助性文字(错误提示),无论是否在焦点。(默认false) --> |
||||
<attr name="met_helperTextAlwaysShown" format="boolean" /> |
||||
<!-- 是否使用动画显示悬浮提示(默认true) --> |
||||
<attr name="met_floatingLabelAnimating" format="boolean" /> |
||||
<!-- 输入文字的颜色 --> |
||||
<attr name="met_textColor" format="color" /> |
||||
<!-- 提示文字的颜色 --> |
||||
<attr name="met_textColorHint" format="color" /> |
||||
<!-- 是否失去焦点后自动校验(默认false)--> |
||||
<attr name="met_validateOnFocusLost" format="boolean" /> |
||||
<!-- 是否在文字显示的时候开始计算文字的数量(默认true)--> |
||||
<attr name="met_checkCharactersCountAtBeginning" format="boolean" /> |
||||
<!--校验的正则表达式--> |
||||
<attr name="met_regexp" format="string" /> |
||||
<!--校验不通过的提示信息--> |
||||
<attr name="met_errorMessage" format="string" /> |
||||
</declare-styleable> |
||||
|
||||
<!-- PasswordEditText --> |
||||
<declare-styleable name="PasswordEditText"> |
||||
<!--显示密码的图标资源--> |
||||
<attr name="pet_iconShow" format="reference" /> |
||||
<!--隐藏密码的图标资源--> |
||||
<attr name="pet_iconHide" format="reference" /> |
||||
<!--是否触摸显示密码--> |
||||
<attr name="pet_hoverShowsPw" format="boolean" /> |
||||
<!--是否使用系统默认字体--> |
||||
<attr name="pet_nonMonospaceFont" format="boolean" /> |
||||
<!--图标是否设置透明度, 默认是true--> |
||||
<attr name="pet_enableIconAlpha" format="boolean" /> |
||||
<!--密码输入框文字的样式是否是“*”,默认是false--> |
||||
<attr name="pet_isAsteriskStyle" format="boolean" /> |
||||
</declare-styleable> |
||||
|
||||
<!-- MaterialEditText--> |
||||
<dimen name="default_edittext_components_spacing">8dp</dimen> |
||||
<dimen name="default_bottom_ellipsis_height">4dp</dimen> |
||||
<dimen name="default_floating_label_text_size">12sp</dimen> |
||||
<dimen name="default_bottom_text_size">12sp</dimen> |
||||
|
||||
<!-- <dimen name="default_md_dialog_frame_margin">24dp</dimen>--> |
||||
<!-- <dimen name="default_md_icon_max_size">40dp</dimen>--> |
||||
|
||||
<declare-styleable name="MDRootLayout"> |
||||
<attr name="md_reduce_padding_no_title_no_buttons" format="boolean" /> |
||||
</declare-styleable> |
||||
|
||||
|
||||
|
||||
</resources> |
@ -1,18 +1,16 @@ |
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<resources> |
||||
<color name="colorPrimary">#2964DA</color> |
||||
|
||||
<!--新增--> |
||||
<color name="bg_content">#f8f8f8</color> |
||||
<color name="text_color_1">#333333</color> |
||||
<color name="text_color_2">#999</color> |
||||
<color name="white">#ffffff</color> |
||||
<color name="black">#000000</color> |
||||
<color name="c_2964da">#2964DA</color> |
||||
<color name="c_ebebeb">#EBEBEB</color> |
||||
<color name="c_727778">#727778</color> |
||||
|
||||
|
||||
<color name="hor_line">#f2f2f2</color> |
||||
<color name="text_color_desc">#F3AE42</color> |
||||
<color name="divide_line">#1A000000</color> |
||||
<color name="text_color_disable">#AAA</color> |
||||
<color name="green_gnss">#00B050</color> |
||||
<color name="yellow_gnss">#FFFF00</color> |
||||
<color name="red">#ff0000</color> |
||||
</resources> |
@ -0,0 +1,478 @@ |
||||
<?xml version="1.0" encoding="utf-8"?><!-- |
||||
~ Copyright (C) 2018 xuexiangjys(xuexiangjys@163.com) |
||||
~ |
||||
~ Licensed under the Apache License, Version 2.0 (the "License"); |
||||
~ you may not use this file except in compliance with the License. |
||||
~ You may obtain a copy of the License at |
||||
~ |
||||
~ http://www.apache.org/licenses/LICENSE-2.0 |
||||
~ |
||||
~ Unless required by applicable law or agreed to in writing, software |
||||
~ distributed under the License is distributed on an "AS IS" BASIS, |
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
~ See the License for the specific language governing permissions and |
||||
~ limitations under the License. |
||||
~ |
||||
--> |
||||
|
||||
<resources> |
||||
<!--全局样式--> |
||||
<dimen name="xui_config_content_spacing_horizontal_tablet_big">20dp |
||||
</dimen> <!-- margin 和 padding 等使用的内容通用水平间距 --> |
||||
<dimen name="xui_config_content_spacing_horizontal_tablet_small">16dp |
||||
</dimen> <!-- margin 和 padding 等使用的内容通用水平间距 --> |
||||
<dimen name="xui_config_content_spacing_horizontal_phone">12dp |
||||
</dimen> <!-- margin 和 padding 等使用的内容通用水平间距 --> |
||||
|
||||
<dimen name="xui_config_content_spacing_vertical_tablet_big">12dp |
||||
</dimen> <!-- margin 和 padding 等使用的内容通用垂直间距 --> |
||||
<dimen name="xui_config_content_spacing_vertical_tablet_small">10dp |
||||
</dimen> <!-- margin 和 padding 等使用的内容通用垂直间距 --> |
||||
<dimen name="xui_config_content_spacing_vertical_phone">7.5dp |
||||
</dimen> <!-- margin 和 padding 等使用的内容通用垂直间距 --> |
||||
|
||||
<dimen name="xui_config_simple_list_item_height_tablet_big">61dp</dimen> |
||||
<dimen name="xui_config_simple_list_item_height_tablet_small">49dp</dimen> |
||||
<dimen name="xui_config_simple_list_item_height_phone">41dp</dimen> |
||||
|
||||
<dimen name="xui_config_simple_list_icon_size_tablet_big">26dp</dimen> |
||||
<dimen name="xui_config_simple_list_icon_size_tablet_small">24dp</dimen> |
||||
<dimen name="xui_config_simple_list_icon_size_phone">22dp</dimen> |
||||
|
||||
<!-- xui splash view --> |
||||
<dimen name="xui_config_app_logo_bottom">250dp</dimen> |
||||
<dimen name="xui_config_company_logo_bottom">80dp</dimen> |
||||
|
||||
<dimen name="xui_alpha_pressed">0.5</dimen> |
||||
<dimen name="xui_alpha_disabled">0.5</dimen> |
||||
|
||||
<dimen name="default_xui_general_shadow_elevation">14dp</dimen> |
||||
<dimen name="default_xui_general_shadow_alpha">0.25</dimen> |
||||
|
||||
<dimen name="xui_guide_btn_padding_horizontal_table_big">60dp</dimen> |
||||
<dimen name="xui_guide_btn_padding_vertical_table_big">16dp</dimen> |
||||
<dimen name="xui_guide_btn_margin_bottom_table_big">50dp</dimen> |
||||
|
||||
<dimen name="xui_guide_btn_padding_horizontal_table_small">45dp</dimen> |
||||
<dimen name="xui_guide_btn_padding_vertical_table_small">12dp</dimen> |
||||
<dimen name="xui_guide_btn_margin_bottom_table_small">38dp</dimen> |
||||
|
||||
<dimen name="xui_guide_btn_padding_horizontal_phone">30dp</dimen> |
||||
<dimen name="xui_guide_btn_padding_vertical_phone">8dp</dimen> |
||||
<dimen name="xui_guide_btn_margin_bottom_phone">25dp</dimen> |
||||
|
||||
<!-- ActionBar--> |
||||
<dimen name="xui_actionbar_height_tablet_big">70dp</dimen> |
||||
<dimen name="xui_actionbar_height_tablet_small">60dp</dimen> |
||||
<dimen name="xui_actionbar_height_phone">52dp</dimen> |
||||
|
||||
<dimen name="xui_actionbar_title_text_size_tablet_big">24sp</dimen> |
||||
<dimen name="xui_actionbar_title_text_size_tablet_small">21sp</dimen> |
||||
<dimen name="xui_actionbar_title_text_size_phone">18sp</dimen> |
||||
|
||||
<dimen name="xui_actionbar_action_text_size_tablet_big">22sp</dimen> |
||||
<dimen name="xui_actionbar_action_text_size_tablet_small">18sp</dimen> |
||||
<dimen name="xui_actionbar_action_text_size_phone">15sp</dimen> |
||||
|
||||
<dimen name="xui_actionbar_sub_text_size_tablet_big">16sp</dimen> |
||||
<dimen name="xui_actionbar_sub_text_size_tablet_small">14sp</dimen> |
||||
<dimen name="xui_actionbar_sub_text_size_phone">12sp</dimen> |
||||
|
||||
<dimen name="xui_actionbar_action_padding_tablet_big">7dp</dimen> |
||||
<dimen name="xui_actionbar_action_padding_tablet_small">6dp</dimen> |
||||
<dimen name="xui_actionbar_action_padding_phone">5dp</dimen> |
||||
|
||||
<dimen name="xui_actionbar_side_text_padding_tablet_big">18dp</dimen> |
||||
<dimen name="xui_actionbar_side_text_padding_tablet_small">16dp</dimen> |
||||
<dimen name="xui_actionbar_side_text_padding_phone">14dp</dimen> |
||||
|
||||
<!-- ShadowButton--> |
||||
<dimen name="default_shadow_button_radius">2dp</dimen> |
||||
|
||||
<!--RoundButton--> |
||||
<dimen name="default_rb_border_width">1dp</dimen> |
||||
<dimen name="default_rb_radius">5dp</dimen> |
||||
|
||||
<!--ShadowDrawable--> |
||||
<dimen name="default_sd_shadow_radius">8dp</dimen> |
||||
<dimen name="default_sd_shape_radius">5dp</dimen> |
||||
|
||||
<!--SwitchButton--> |
||||
<dimen name="swb_md_thumb_ripple_size">42dp</dimen> |
||||
<dimen name="swb_md_thumb_solid_inset">11dp</dimen> |
||||
<dimen name="swb_md_thumb_shadow_inset">11dp</dimen> |
||||
<dimen name="swb_md_thumb_shadow_inset_top">11dp</dimen> |
||||
<dimen name="swb_md_thumb_shadow_inset_bottom">10dp</dimen> |
||||
<dimen name="swb_md_thumb_solid_size">20dp</dimen> |
||||
<dimen name="swb_md_thumb_shadow_size">21dp</dimen> |
||||
<dimen name="swb_md_thumb_shadow_offset">2dp</dimen> |
||||
|
||||
<!-- SuperTextView--> |
||||
<dimen name="default_stv_text_size">15sp</dimen> |
||||
<dimen name="default_stv_margin">10dp</dimen> |
||||
|
||||
<!-- Button--> |
||||
<dimen name="default_btn_view_radius_tablet_big">7dp</dimen> |
||||
<dimen name="default_btn_view_width_tablet_big">148dp</dimen> |
||||
<dimen name="default_btn_view_height_tablet_big">52dp</dimen> |
||||
<dimen name="default_btn_view_text_size_tablet_big">21sp</dimen> |
||||
<dimen name="default_btn_view_border_width_tablet_big">1dp</dimen> |
||||
|
||||
<dimen name="default_btn_view_radius_tablet_small">5dp</dimen> |
||||
<dimen name="default_btn_view_width_tablet_small">112dp</dimen> |
||||
<dimen name="default_btn_view_height_tablet_small">38dp</dimen> |
||||
<dimen name="default_btn_view_text_size_tablet_small">16sp</dimen> |
||||
<dimen name="default_btn_view_border_width_tablet_small">1dp</dimen> |
||||
|
||||
<dimen name="default_btn_view_radius_phone">5dp</dimen> |
||||
<dimen name="default_btn_view_width_phone">104dp</dimen> |
||||
<dimen name="default_btn_view_height_phone">32dp</dimen> |
||||
<dimen name="default_btn_view_text_size_phone">13sp</dimen> |
||||
<dimen name="default_btn_view_border_width_phone">0.5dp</dimen> |
||||
|
||||
<dimen name="xui_config_icon_drawable_padding_tablet_big">12dp</dimen> |
||||
<dimen name="xui_config_icon_drawable_padding_tablet_small">9dp</dimen> |
||||
<dimen name="xui_config_icon_drawable_padding_phone">7dp</dimen> |
||||
|
||||
<!-- ClearEditText--> |
||||
<dimen name="default_clear_icon_size">24dp</dimen> |
||||
|
||||
<!-- MaterialEditText--> |
||||
<!-- <dimen name="default_edittext_components_spacing">8dp</dimen>--> |
||||
<!-- <dimen name="default_bottom_ellipsis_height">4dp</dimen>--> |
||||
<!-- <dimen name="default_floating_label_text_size">12sp</dimen>--> |
||||
<!-- <dimen name="default_bottom_text_size">12sp</dimen>--> |
||||
|
||||
<!-- VerifyCodeEditText--> |
||||
<dimen name="default_vcet_width">21dp</dimen> |
||||
<dimen name="default_vcet_pwd_radius">5dp</dimen> |
||||
<dimen name="default_vcet_text_size">16sp</dimen> |
||||
|
||||
<!--StatefulLayout--> |
||||
<dimen name="default_stf_progressbar_size_tablet_big">75dp</dimen> |
||||
<dimen name="default_stf_progressbar_size_tablet_small">65dp</dimen> |
||||
<dimen name="default_stf_progressbar_size_phone">60dp</dimen> |
||||
|
||||
<dimen name="default_stf_tip_img_size_tablet_big">105dp</dimen> |
||||
<dimen name="default_stf_tip_img_size_tablet_small">90dp</dimen> |
||||
<dimen name="default_stf_tip_img_size_phone">80dp</dimen> |
||||
|
||||
<!--MaterialSpinner--> |
||||
<dimen name="default_ms_padding_left_size_tablet_big">13dp</dimen> |
||||
<dimen name="default_ms_padding_top_size_tablet_big">11dp</dimen> |
||||
<dimen name="default_ms_item_height_size_tablet_big">45dp</dimen> |
||||
<dimen name="default_ms_dropdown_offset_tablet_big">3dp</dimen> |
||||
<dimen name="default_ms_arrow_size_tablet_big">12dp</dimen> |
||||
|
||||
<dimen name="default_ms_padding_left_size_tablet_small">10dp</dimen> |
||||
<dimen name="default_ms_padding_top_size_tablet_small">8dp</dimen> |
||||
<dimen name="default_ms_item_height_size_tablet_small">35dp</dimen> |
||||
<dimen name="default_ms_dropdown_offset_tablet_small">2dp</dimen> |
||||
<dimen name="default_ms_arrow_size_tablet_small">10dp</dimen> |
||||
|
||||
<dimen name="default_ms_padding_left_size_phone">8dp</dimen> |
||||
<dimen name="default_ms_padding_top_size_phone">6.5dp</dimen> |
||||
<dimen name="default_ms_item_height_size_phone">30dp</dimen> |
||||
<dimen name="default_ms_dropdown_offset_phone">1dp</dimen> |
||||
<dimen name="default_ms_arrow_size_phone">8dp</dimen> |
||||
|
||||
<!-- DropDownMenu--> |
||||
<dimen name="default_ddm_underline_height">1dp</dimen> |
||||
<dimen name="default_ddm_divider_width">0.5dp</dimen> |
||||
<dimen name="default_ddm_divider_margin">10dp</dimen> |
||||
<dimen name="default_ddm_menu_text_size">14sp</dimen> |
||||
<dimen name="default_ddm_menu_text_padding_horizontal">5dp</dimen> |
||||
<dimen name="default_ddm_menu_text_padding_vertical">12dp</dimen> |
||||
|
||||
|
||||
<!--WheelView--> |
||||
<dimen name="default_wheel_view_text_size">20sp</dimen> |
||||
<dimen name="picker_view_topbar_padding">20dp</dimen> |
||||
<dimen name="picker_view_topbar_height">44dp</dimen> |
||||
|
||||
<!--MaterialSearchView--> |
||||
<dimen name="default_search_icon_padding">16dp</dimen> |
||||
<dimen name="default_search_view_text_padding">8dp</dimen> |
||||
<dimen name="default_search_view_text_size">16sp</dimen> |
||||
<dimen name="default_search_view_separator_height">1px</dimen> |
||||
|
||||
<!-- TabControlView--> |
||||
<dimen name="default_tcv_text_size">14sp</dimen> |
||||
<dimen name="default_tcv_stroke_width">1dp</dimen> |
||||
|
||||
<!--ProgressView--> |
||||
<dimen name="default_pv_trace_width">16dp</dimen> |
||||
<dimen name="default_pv_progress_text_size">28sp</dimen> |
||||
<dimen name="default_pv_corner_radius">5dp</dimen> |
||||
<dimen name="default_pv_horizontal_text_size">14sp</dimen> |
||||
<dimen name="default_pv_zone_length">22dp</dimen> |
||||
<dimen name="default_pv_zone_width">6dp</dimen> |
||||
<dimen name="default_pv_zone_padding">16dp</dimen> |
||||
<dimen name="default_pv_zone_corner_radius">8dp</dimen> |
||||
|
||||
<!--BannerLayout--> |
||||
<dimen name="default_recycler_banner_itemSpace">10dp</dimen> |
||||
<dimen name="default_recycler_banner_indicatorSize">5dp</dimen> |
||||
<dimen name="default_recycler_banner_indicatorSpace">4dp</dimen> |
||||
<dimen name="default_recycler_banner_indicatorMarginLeft">16dp</dimen> |
||||
<dimen name="default_recycler_banner_indicatorMarginRight">0dp</dimen> |
||||
<dimen name="default_recycler_banner_indicatorMarginBottom">11dp</dimen> |
||||
|
||||
<!--********************************************* |
||||
* MaterialDialog * |
||||
**********************************************--> |
||||
<!-- Margin around the dialog, excluding the button bar --> |
||||
<!-- Total title margin bottom is 16, but we split this between content and title --> |
||||
<dimen name="md_title_frame_margin_bottom">12dp</dimen> |
||||
<dimen name="md_title_frame_margin_bottom_less">6dp</dimen> |
||||
<!-- The desired padding when no title is visible, |
||||
This plus md_content_padding_top should equals md_dialog_frame_margin --> |
||||
<dimen name="md_notitle_vertical_padding">16dp</dimen> |
||||
<dimen name="md_notitle_vertical_padding_more">20dp</dimen> |
||||
|
||||
<dimen name="md_button_min_width">72dp</dimen> |
||||
<!-- Above and below buttons, 36+6+6=48 for the height of the button frame --> |
||||
<dimen name="md_button_inset_vertical">6dp</dimen> |
||||
<dimen name="md_button_inset_horizontal">4dp</dimen> |
||||
<dimen name="md_button_textpadding_horizontal">1dp</dimen> |
||||
|
||||
<dimen name="default_md_button_padding_horizontal_phone">8dp</dimen> |
||||
<dimen name="default_md_button_padding_horizontal_tablet_small">12dp</dimen> |
||||
<dimen name="default_md_button_padding_horizontal_tablet_big">16dp</dimen> |
||||
|
||||
<dimen name="md_button_padding_vertical">4dp</dimen> |
||||
<!-- 16dp - 4dp (inset from background drawable) --> |
||||
<dimen name="md_button_padding_frame_side">12dp</dimen> |
||||
<dimen name="md_neutral_button_margin">12dp</dimen> |
||||
|
||||
<!-- actual content padding bottom is 16dp, but we split between button bar and content --> |
||||
<dimen name="md_content_padding_top">8dp</dimen> |
||||
<dimen name="md_content_padding_bottom">8dp</dimen> |
||||
<dimen name="md_button_frame_vertical_padding">8dp</dimen> |
||||
|
||||
<dimen name="default_md_button_height_phone">48dp</dimen> |
||||
<dimen name="default_md_button_height_tablet_small">55dp</dimen> |
||||
<dimen name="default_md_button_height_tablet_big">70dp</dimen> |
||||
|
||||
<!--文字大小--> |
||||
<dimen name="default_md_title_textsize_tablet_big">28sp</dimen> |
||||
<dimen name="default_md_dialog_frame_margin_tablet_big">32dp</dimen> |
||||
<dimen name="default_md_button_textsize_tablet_big">22sp</dimen> |
||||
<dimen name="default_md_content_textsize_tablet_big">22sp</dimen> |
||||
<dimen name="default_md_explain_textsize_tablet_big">18sp</dimen> |
||||
<dimen name="default_md_listitem_textsize_tablet_big">22sp</dimen> |
||||
<dimen name="default_md_icon_margin_tablet_big">9dp</dimen> |
||||
<dimen name="default_md_icon_max_size_tablet_big">40dp</dimen> |
||||
|
||||
<dimen name="default_md_title_textsize_tablet_small">21sp</dimen> |
||||
<dimen name="default_md_dialog_frame_margin_tablet_small">24dp</dimen> |
||||
<dimen name="default_md_button_textsize_tablet_small">16sp</dimen> |
||||
<dimen name="default_md_content_textsize_tablet_small">16sp</dimen> |
||||
<dimen name="default_md_explain_textsize_tablet_small">14sp</dimen> |
||||
<dimen name="default_md_listitem_textsize_tablet_small">16sp</dimen> |
||||
<dimen name="default_md_icon_margin_tablet_small">7dp</dimen> |
||||
<dimen name="default_md_icon_max_size_tablet_small">30dp</dimen> |
||||
|
||||
<dimen name="default_md_title_textsize_phone">19sp</dimen> |
||||
<dimen name="default_md_dialog_frame_margin_phone">25dp</dimen> |
||||
<dimen name="default_md_button_textsize_phone">15sp</dimen> |
||||
<dimen name="default_md_content_textsize_phone">15sp</dimen> |
||||
<dimen name="default_md_explain_textsize_phone">13sp</dimen> |
||||
<dimen name="default_md_listitem_textsize_phone">15sp</dimen> |
||||
<dimen name="default_md_icon_margin_phone">6dp</dimen> |
||||
<dimen name="default_md_icon_max_size_phone">28dp</dimen> |
||||
|
||||
|
||||
<dimen name="default_md_dialog_frame_margin">24dp</dimen> |
||||
<dimen name="default_md_icon_max_size">40dp</dimen> |
||||
|
||||
<dimen name="md_listitem_height">48dp</dimen> |
||||
<dimen name="md_listitem_control_margin">6dp</dimen> |
||||
<dimen name="md_icon_margin">16dp</dimen> |
||||
|
||||
<dimen name="md_listitem_margin_left">24dp</dimen> |
||||
<dimen name="md_action_corner_radius">2dp</dimen> |
||||
<dimen name="md_divider_height">1dp</dimen> |
||||
|
||||
<dimen name="md_bg_corner_radius">7dp</dimen> |
||||
<dimen name="circular_progress_border">4dp</dimen> |
||||
<dimen name="md_listitem_vertical_margin">12dp</dimen> |
||||
<dimen name="md_listitem_vertical_margin_choice">8dp</dimen> |
||||
|
||||
<dimen name="default_md_dialog_max_width_tablet_big">590dp</dimen> |
||||
<dimen name="default_md_dialog_max_width_tablet_small">440dp</dimen> |
||||
<dimen name="default_md_dialog_max_width_phone">305dp</dimen> |
||||
|
||||
<dimen name="default_md_dialog_vertical_margin_tablet_big">100dp</dimen> |
||||
<dimen name="default_md_dialog_vertical_margin_tablet_small">75dp</dimen> |
||||
<dimen name="default_md_dialog_vertical_margin_phone">52dp</dimen> |
||||
|
||||
<dimen name="default_md_dialog_horizontal_margin_tablet_big">54dp</dimen> |
||||
<dimen name="default_md_dialog_horizontal_margin_tablet_small">40dp</dimen> |
||||
<dimen name="default_md_dialog_horizontal_margin_phone">28dp</dimen> |
||||
|
||||
<dimen name="default_md_preference_content_inset_tablet_big">42dp</dimen> |
||||
<dimen name="default_md_preference_content_inset_tablet_small">28dp</dimen> |
||||
<dimen name="default_md_preference_content_inset_phone">16dp</dimen> |
||||
|
||||
<dimen name="default_md_simpleitem_height_tablet_big">76dp</dimen> |
||||
<dimen name="default_md_simplelist_icon_tablet_big">52dp</dimen> |
||||
<dimen name="default_md_simplelist_icon_margin_tablet_big">25dp</dimen> |
||||
<dimen name="default_md_simplelist_icon_padding_tablet_big">8dp</dimen> |
||||
|
||||
<dimen name="default_md_simpleitem_height_tablet_small">62dp</dimen> |
||||
<dimen name="default_md_simplelist_icon_tablet_small">40dp</dimen> |
||||
<dimen name="default_md_simplelist_icon_margin_tablet_small">20dp</dimen> |
||||
<dimen name="default_md_simplelist_icon_padding_tablet_small">6dp</dimen> |
||||
|
||||
<dimen name="default_md_simpleitem_height_phone">50dp</dimen> |
||||
<dimen name="default_md_simplelist_icon_phone">30dp</dimen> |
||||
<dimen name="default_md_simplelist_icon_margin_phone">18dp</dimen> |
||||
<dimen name="default_md_simplelist_icon_padding_phone">5dp</dimen> |
||||
|
||||
<dimen name="xui_list_divider_height_table">1dp</dimen> |
||||
<dimen name="xui_list_divider_height_phone">0.5dp</dimen> |
||||
|
||||
<dimen name="xui_config_separator_height_tablet_big">3dp</dimen> |
||||
<dimen name="xui_config_separator_height_tablet_small">2dp</dimen> |
||||
<dimen name="xui_config_separator_height_phone">1dp</dimen> |
||||
<!--********************************************* |
||||
* Text Size * |
||||
**********************************************--> |
||||
<!--标题文字大小--> |
||||
<dimen name="xui_config_size_title_text_tablet_big">24sp</dimen> |
||||
<!--正文内容文字大小--> |
||||
<dimen name="xui_config_size_content_text_tablet_big">22sp</dimen> |
||||
<!--辅助说明文字大小--> |
||||
<dimen name="xui_config_size_explain_text_tablet_big">16sp</dimen> |
||||
|
||||
<!--标题文字大小--> |
||||
<dimen name="xui_config_size_title_text_tablet_small">21sp</dimen> |
||||
<!--正文内容文字大小--> |
||||
<dimen name="xui_config_size_content_text_tablet_small">18sp</dimen> |
||||
<!--辅助说明文字大小--> |
||||
<dimen name="xui_config_size_explain_text_tablet_small">14sp</dimen> |
||||
|
||||
<!--标题文字大小--> |
||||
<dimen name="xui_config_size_title_text_phone">18sp</dimen> |
||||
<!--正文内容文字大小--> |
||||
<dimen name="xui_config_size_content_text_phone">15sp</dimen> |
||||
<!--辅助说明文字大小--> |
||||
<dimen name="xui_config_size_explain_text_phone">12sp</dimen> |
||||
|
||||
<!--********************************************* |
||||
* EditText * |
||||
**********************************************--> |
||||
<dimen name="xui_config_size_edittext_input_text_tablet_big">20sp</dimen> |
||||
<dimen name="xui_config_size_edittext_helper_text_tablet_big">12sp</dimen> |
||||
<dimen name="xui_config_size_edittext_components_spacing_tablet_big">10dp</dimen> |
||||
<dimen name="xui_config_size_edittext_left_padding_tablet_big">17dp</dimen> |
||||
<dimen name="xui_config_size_edittext_radius_tablet_big">5dp</dimen> |
||||
<dimen name="xui_config_size_edittext_height_tablet_big">40dp</dimen> |
||||
|
||||
<dimen name="xui_config_size_edittext_input_text_tablet_small">15sp</dimen> |
||||
<dimen name="xui_config_size_edittext_helper_text_tablet_small">9sp</dimen> |
||||
<dimen name="xui_config_size_edittext_components_spacing_tablet_small">8dp</dimen> |
||||
<dimen name="xui_config_size_edittext_left_padding_tablet_small">13dp</dimen> |
||||
<dimen name="xui_config_size_edittext_radius_tablet_small">4dp</dimen> |
||||
<dimen name="xui_config_size_edittext_height_tablet_small">30dp</dimen> |
||||
|
||||
<dimen name="xui_config_size_edittext_input_text_phone">13sp</dimen> |
||||
<dimen name="xui_config_size_edittext_helper_text_phone">8sp</dimen> |
||||
<dimen name="xui_config_size_edittext_components_spacing_phone">7dp</dimen> |
||||
<dimen name="xui_config_size_edittext_left_padding_phone">10dp</dimen> |
||||
<dimen name="xui_config_size_edittext_radius_phone">4dp</dimen> |
||||
<dimen name="xui_config_size_edittext_height_phone">30dp</dimen> |
||||
|
||||
<!--********************************************** |
||||
* xui popup * |
||||
***********************************************--> |
||||
<dimen name="xui_popup_width_tablet_big">232dp</dimen> |
||||
<dimen name="xui_popup_width_tablet_small">174dp</dimen> |
||||
<dimen name="xui_popup_width_phone">133dp</dimen> |
||||
|
||||
<dimen name="xui_tip_popup_padding_top_tablet_big">12dp</dimen> |
||||
<dimen name="xui_tip_popup_padding_top_tablet_small">9dp</dimen> |
||||
<dimen name="xui_tip_popup_padding_top_phone">8dp</dimen> |
||||
|
||||
<dimen name="xui_tip_popup_padding_left_tablet_big">18dp</dimen> |
||||
<dimen name="xui_tip_popup_padding_left_tablet_small">15dp</dimen> |
||||
<dimen name="xui_tip_popup_padding_left_phone">12dp</dimen> |
||||
|
||||
<!--********************************************** |
||||
* Spinner * |
||||
***********************************************--> |
||||
<dimen name="xui_config_size_spinner_text_tablet_big">20sp</dimen> |
||||
<dimen name="xui_config_size_spinner_text_tablet_small">15sp</dimen> |
||||
<dimen name="xui_config_size_spinner_text_phone">13sp</dimen> |
||||
|
||||
<dimen name="default_spinner_icon_padding_size">20dp</dimen> |
||||
|
||||
<!--********************************************** |
||||
* Dialog * |
||||
***********************************************--> |
||||
<dimen name="xui_dialog_radius_size_tablet_big">10dp</dimen> |
||||
<dimen name="xui_dialog_loading_padding_size_tablet_big">40dp</dimen> |
||||
<dimen name="xui_dialog_loading_min_size_tablet_big">250dp</dimen> |
||||
<dimen name="xui_loading_view_size_tablet_big">135dp</dimen> |
||||
<dimen name="xui_loading_view_width_tablet_big">6dp</dimen> |
||||
<dimen name="xui_loading_margin_size_tablet_big">14dp</dimen> |
||||
<dimen name="mini_loading_view_size_tablet_big">40dp</dimen> |
||||
|
||||
<dimen name="xui_dialog_radius_size_tablet_small">8dp</dimen> |
||||
<dimen name="xui_dialog_loading_padding_size_tablet_small">30dp</dimen> |
||||
<dimen name="xui_dialog_loading_min_size_tablet_small">150dp</dimen> |
||||
<dimen name="xui_loading_view_size_tablet_small">100dp</dimen> |
||||
<dimen name="xui_loading_view_width_tablet_small">5dp</dimen> |
||||
<dimen name="xui_loading_margin_size_tablet_small">10dp</dimen> |
||||
<dimen name="mini_loading_view_size_tablet_small">30dp</dimen> |
||||
|
||||
<dimen name="xui_dialog_radius_size_phone">7dp</dimen> |
||||
<dimen name="xui_dialog_loading_padding_size_phone">26dp</dimen> |
||||
<dimen name="xui_dialog_loading_min_size_phone">100dp</dimen> |
||||
<dimen name="xui_loading_view_size_phone">78dp</dimen> |
||||
<dimen name="xui_loading_view_width_phone">4dp</dimen> |
||||
<dimen name="xui_loading_margin_size_phone">6dp</dimen> |
||||
<dimen name="mini_loading_view_size_phone">20dp</dimen> |
||||
|
||||
<dimen name="xui_dialog_mini_loading_padding_size_tablet_big">30dp</dimen> |
||||
<dimen name="xui_dialog_mini_loading_min_size_tablet_big">200dp</dimen> |
||||
<dimen name="xui_dialog_mini_loading_padding_size_tablet_small">25dp</dimen> |
||||
<dimen name="xui_dialog_mini_loading_min_size_tablet_small">140dp</dimen> |
||||
<dimen name="xui_dialog_mini_loading_padding_size_phone">18dp</dimen> |
||||
<dimen name="xui_dialog_mini_loading_min_size_phone">90dp</dimen> |
||||
|
||||
<dimen name="xui_mini_loading_margin_size_tablet_big">25dp</dimen> |
||||
<dimen name="xui_mini_loading_margin_size_tablet_small">18dp</dimen> |
||||
<dimen name="xui_mini_loading_margin_size_phone">12dp</dimen> |
||||
|
||||
<dimen name="xui_mini_loading_view_size_tablet_big">45dp</dimen> |
||||
<dimen name="xui_mini_loading_view_size_tablet_small">35dp</dimen> |
||||
<dimen name="xui_mini_loading_view_size_phone">25dp</dimen> |
||||
|
||||
<dimen name="xui_loading_text_size_tablet_big">21sp</dimen> |
||||
<dimen name="xui_loading_text_size_tablet_small">16sp</dimen> |
||||
<dimen name="xui_loading_text_size_phone">12sp</dimen> |
||||
|
||||
|
||||
<!-- 提示标点 --> |
||||
<dimen name="xui_tips_point_size">8dp</dimen> |
||||
|
||||
<!--********************************************** |
||||
* TabSegment * |
||||
**********************************************--> |
||||
<dimen name="xui_tab_segment_indicator_height">2dp</dimen> |
||||
<dimen name="xui_tab_segment_text_size">16sp</dimen> |
||||
<dimen name="xui_tab_sign_count_view_minSize_with_text">16dp</dimen> |
||||
<dimen name="xui_tab_sign_count_view_minSize">8dp</dimen> |
||||
|
||||
<!--********************************************* |
||||
* xui common list * |
||||
**********************************************--> |
||||
<dimen name="xui_list_item_height">56dp</dimen> |
||||
<dimen name="xui_list_item_height_higher">103dp</dimen> |
||||
<dimen name="xui_group_list_section_header_footer_padding_vertical">8dp</dimen> |
||||
<dimen name="xui_group_list_section_header_footer_text_size">13sp</dimen> |
||||
|
||||
|
||||
</resources> |
Loading…
Reference in new issue