data, int selectPos) {
+ super(R.layout.item_dic_select, data);
+ this.selectPos = selectPos;
+ }
+
+ @Override
+ protected void convert(BaseViewHolder helper, StateBean item) {
+ helper.setText(R.id.tv_content,item.getDictLabel());
+// TextView tv = helper.getView(R.id.tv_content);
+// if (item.equals(selectString)){
+// tv.setSelected(true);
+// }else{
+// tv.setSelected(false);
+// }
+
+ }
+
+ public void setSelect(int selectString){
+ this.selectPos = selectString;
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/base/BaseActivity.java b/mylibrary/src/main/java/com/dahe/mylibrary/base/BaseActivity.java
new file mode 100644
index 0000000..65a2fc1
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/base/BaseActivity.java
@@ -0,0 +1,250 @@
+package com.dahe.mylibrary.base;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import androidx.annotation.ColorRes;
+import androidx.annotation.DrawableRes;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
+import androidx.core.content.ContextCompat;
+
+import com.dahe.mylibrary.R;
+import com.dahe.mylibrary.callback.RefreshCallBack;
+import com.dahe.mylibrary.utils.BarUtils;
+import com.dahe.mylibrary.utils.ConvertUtils;
+import com.dahe.mylibrary.utils.StatusBar;
+import com.dahe.mylibrary.utils.ToastUtils;
+import com.scwang.smartrefresh.layout.SmartRefreshLayout;
+import com.scwang.smartrefresh.layout.api.RefreshLayout;
+import com.scwang.smartrefresh.layout.constant.RefreshState;
+import com.scwang.smartrefresh.layout.listener.OnRefreshLoadMoreListener;
+
+import qiu.niorgai.StatusBarCompat;
+
+
+public abstract class BaseActivity extends AppCompatActivity {
+ protected Context mContext;
+ protected final int DEFAULT_STATUS_BAR_ALPHA = 0;
+ private static final String TAG = "BaseActivity";
+ protected Toolbar mToolbar;
+ protected int mRefreshPage = 1;
+ protected int mRefreshCount = 15;
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(getLayout());
+ mContext = this;
+ setStatusBarColor(R.color.colorPrimaryDark);
+ initView(savedInstanceState);
+ initDate();
+ }
+
+ /**
+ * 标题栏的颜色 文字白色
+ */
+ public void setStatusBarCancelLightColor() {
+ StatusBar.cancelLightStatusBar(this);
+ }
+
+
+ /**
+ * 设置沉浸式标题栏 标题栏的颜色
+ */
+ public void setStatusBarColor(int color) {
+ StatusBarCompat.setStatusBarColor(this, ContextCompat.getColor(mContext, color), DEFAULT_STATUS_BAR_ALPHA);
+ StatusBar.changeToLightStatusBar(this); //黑色 下边白色
+// StatusBar.cancelLightStatusBar(this);
+ }
+
+ /**
+ * 设置沉浸式标题栏 标题栏的颜色
+ */
+ public void setStatusBarColor() {
+// StatusBarCompat.setStatusBarColor(this, ContextCompat.getColor(mContext, color), DEFAULT_STATUS_BAR_ALPHA);
+// StatusBar.changeToLightStatusBar(this); //黑色 下边白色
+ StatusBar.cancelLightStatusBar(this);
+ }
+
+ /**
+ * 设置沉浸式标题栏 里面是Fragment
+ */
+ public void setStatusBarColorInFragment() {
+ StatusBarCompat.translucentStatusBar(this);
+ }
+
+ /**
+ * 设置透明沉浸式标题栏
+ */
+ public void setStatusBarColorToLight() {
+ StatusBar.translucentStatusBar(this, false);
+ StatusBar.changeToLightStatusBar(this);
+ }
+
+ /**
+ * 设置标题
+ */
+ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+ protected void setTitleBar(String title, View.OnClickListener listener) {
+ mToolbar = (Toolbar) findViewById(R.id.common_toolbar);
+ if (!TextUtils.isEmpty(title))
+ ((TextView) findViewById(R.id.common_toolBar_title)).setText(title);
+ mToolbar.setNavigationIcon(R.drawable.left);
+ mToolbar.setNavigationOnClickListener(listener);
+ }
+
+ /**
+ * 设置标题
+ */
+
+ protected void setTitleBar(String title) {
+ mToolbar = (Toolbar) findViewById(R.id.common_toolbar);
+ if (!TextUtils.isEmpty(title))
+ ((TextView) findViewById(R.id.common_toolBar_title)).setText(title);
+ }
+
+ /**
+ * 显示右边标题
+ *
+ * @param title
+ * @param listener
+ * @param isVisible
+ * @param right
+ */
+ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
+ protected void setTitleBar(String title, View.OnClickListener listener, boolean isVisible, String right, View.OnClickListener rightListener) {
+ mToolbar = (Toolbar) findViewById(R.id.common_toolbar);
+ if (!TextUtils.isEmpty(title))
+ ((TextView) findViewById(R.id.common_toolBar_title)).setText(title);
+ TextView mTextRight = (TextView) findViewById(R.id.common_toolBar_text_right);
+ if (isVisible) {
+ mTextRight.setVisibility(View.VISIBLE);
+ mTextRight.setText(right);
+ mTextRight.setOnClickListener(rightListener);
+ }
+ mToolbar.setNavigationIcon(R.drawable.left);
+ mToolbar.setNavigationOnClickListener(listener);
+ }
+
+ /**
+ * 设置距离顶部距离
+ */
+ protected void setStatusHeightParams(View llContent) {
+ RelativeLayout.LayoutParams closeLayoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+ closeLayoutParams.topMargin = ConvertUtils.dp2px(8) + BarUtils.getStatusBarHeight();
+// closeLayoutParams.topMargin = BarUtils.getStatusBarHeight();
+ llContent.setLayoutParams(closeLayoutParams);
+ }
+
+ protected abstract int getLayout();
+
+ protected abstract void initView(Bundle savedInstanceState);
+
+ protected abstract void initDate();
+
+ protected void showToast(Object message) {
+ ToastUtils.showToast(this, message instanceof String ? message + "" : getResources().getString((int) message));
+ }
+
+ protected void canCelToast(){
+ ToastUtils.cancelToast();
+ }
+
+
+// protected void showToast(Object message,int time) {
+// ToastUtils.showToast(this, message instanceof String ? message + "" : getResources().getString((int) message),time);
+// }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ }
+
+
+ /**
+ * 设置刷新控件
+ *
+ * @param refreshLayout
+ * @param callBack 访问网络回调
+ */
+ protected void setRefresh(final SmartRefreshLayout refreshLayout, final RefreshCallBack callBack) {
+ refreshLayout.setEnableOverScrollDrag(true)
+ .setOnRefreshLoadMoreListener(new OnRefreshLoadMoreListener() {
+ @Override
+ public void onLoadMore(@NonNull RefreshLayout refreshLayout) {
+ mRefreshPage++;
+ callBack.getRefreshDate(2, mRefreshPage, mRefreshCount);
+ }
+
+ @Override
+ public void onRefresh(@NonNull RefreshLayout refreshLayout) {
+ mRefreshPage = 1;
+ callBack.getRefreshDate(1, mRefreshPage, mRefreshCount);
+ }
+ });
+ }
+
+ /**
+ * 网络访问完成 刷新控件
+ *
+ * @param refreshLayout
+ * @param isLoadMore false禁用下拉加载更多
+ */
+ protected void setFinishRefresh(final SmartRefreshLayout refreshLayout, boolean isLoadMore) {
+ if (refreshLayout != null && refreshLayout.getState() == RefreshState.Refreshing)
+ refreshLayout.finishRefresh();
+ else if (refreshLayout != null && refreshLayout.getState() == RefreshState.Loading)
+ refreshLayout.finishLoadMore();
+ if (!isLoadMore){
+ refreshLayout.finishLoadMore(); //加载完成
+ refreshLayout.finishLoadMoreWithNoMoreData(); //全部加载完成,没有数据了调用此方法
+ }
+// refreshLayout.setEnableLoadMore(isLoadMore);
+ }
+
+ public void onClick(View view){
+
+ }
+
+
+ /**
+ * 获取Drawable
+ *
+ * @param id
+ * @return
+ */
+ protected Drawable getDrawableV4(@DrawableRes int id) {
+ return ContextCompat.getDrawable(this, id);
+ }
+
+ /**
+ * 获取Color
+ *
+ * @param id
+ * @return
+ */
+ protected int getColorV4(@ColorRes int id) {
+ return ContextCompat.getColor(this, id);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ }
+
+
+}
\ No newline at end of file
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/base/BaseFragment.java b/mylibrary/src/main/java/com/dahe/mylibrary/base/BaseFragment.java
new file mode 100644
index 0000000..0e67b39
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/base/BaseFragment.java
@@ -0,0 +1,321 @@
+package com.dahe.mylibrary.base;
+
+
+import android.content.Context;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageButton;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.widget.Toolbar;
+import androidx.core.content.ContextCompat;
+import androidx.fragment.app.Fragment;
+
+import com.dahe.mylibrary.R;
+import com.dahe.mylibrary.callback.RefreshCallBack;
+import com.dahe.mylibrary.utils.StatusBar;
+import com.dahe.mylibrary.utils.ToastUtils;
+import com.scwang.smartrefresh.layout.SmartRefreshLayout;
+import com.scwang.smartrefresh.layout.api.RefreshLayout;
+import com.scwang.smartrefresh.layout.constant.RefreshState;
+import com.scwang.smartrefresh.layout.listener.OnRefreshLoadMoreListener;
+
+import qiu.niorgai.StatusBarCompat;
+
+/**
+ *
+ * Fragment基类,封装了懒加载的实现
+ *
+ * 1、Viewpager + Fragment情况下,fragment的生命周期因Viewpager的缓存机制而失去了具体意义
+ * 该抽象类自定义一个新的回调方法,当fragment可见状态改变时会触发的回调方法
+ *
+ * @see #onFragmentVisibleChange(boolean)
+ * @see #onFragmentFirstVisible()
+ */
+public abstract class BaseFragment extends Fragment {
+ private boolean isFragmentVisible;
+ private boolean isReuseView;
+ private boolean isFirstVisible;
+ private boolean isPause;
+ private View rootView;
+ private static final String TAG = "BaseFragment";
+ protected Context mContext;
+ protected int mRefreshPage = 1;
+ protected int mRefreshCount = 20;
+ protected Toolbar mToolbar;
+ protected final int DEFAULT_STATUS_BAR_ALPHA = 0;
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ Log.i(TAG, "onViewCreated: " + (rootView == null) + "---getUserVisibleHint()" + getUserVisibleHint() + "---isFirstVisible" + isFirstVisible);
+ //如果setUserVisibleHint()在rootView创建前调用时,那么
+ //就等到rootView创建完后才回调onFragmentVisibleChange(true)
+ //保证onFragmentVisibleChange()的回调发生在rootView创建完成之后,以便支持ui操作
+ if (rootView == null) {
+ rootView = view;
+ if (getUserVisibleHint()) {
+ if (isFirstVisible) {
+ onFragmentFirstVisible();
+ isFirstVisible = false;
+ }
+
+ onFragmentVisibleChange(isFirstVisible);
+ isFragmentVisible = true;
+ }
+ }
+ super.onViewCreated(isReuseView && rootView != null ? rootView : view, savedInstanceState);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ if (getContentViewLayoutID() != 0) {
+ mContext = getActivity();
+ return inflater.inflate(getContentViewLayoutID(), container, false);
+ } else {
+ return super.onCreateView(inflater, container, savedInstanceState);
+ }
+ }
+
+
+ protected abstract int getContentViewLayoutID();
+
+
+ /**
+ * 标题栏的颜色 文字白色
+ */
+ public void setStatusBarCancelLightColor() {
+ StatusBar.cancelLightStatusBar(getActivity());
+ }
+
+ /**
+ * 设置沉浸式标题栏 标题栏的颜色
+ */
+ public void setStatusBarColor(int color) {
+ StatusBarCompat.setStatusBarColor(getActivity(), ContextCompat.getColor(mContext, color), DEFAULT_STATUS_BAR_ALPHA);
+ StatusBar.changeToLightStatusBar(getActivity());
+ }
+
+ /**
+ * 设置沉浸式标题栏 里面是Fragment
+ */
+ public void setStatusBarColorInFragment() {
+ StatusBarCompat.translucentStatusBar(getActivity());
+ }
+
+ public void setStatusBarColorToLight() {
+ StatusBar.translucentStatusBar(getActivity(), true);
+ StatusBar.changeToLightStatusBar(getActivity());
+ }
+
+ @Override
+ public void onDestroy() {
+ initVariable();
+ super.onDestroy();
+ }
+
+
+ protected void showToast(Object message) {
+ ToastUtils.showToast(mContext, message instanceof String ? message + "" : getResources().getString((int) message));
+ }
+
+ /**
+ * 设置刷新控件
+ *
+ * @param refreshLayout
+ * @param callBack 访问网络回调
+ */
+ protected void setRefresh(final SmartRefreshLayout refreshLayout, final RefreshCallBack callBack) {
+ refreshLayout.setEnableOverScrollDrag(true)
+ .setOnRefreshLoadMoreListener(new OnRefreshLoadMoreListener() {
+ @Override
+ public void onLoadMore(@NonNull RefreshLayout refreshLayout) {
+ mRefreshPage++;
+ callBack.getRefreshDate(2, mRefreshPage, mRefreshCount);
+ }
+
+ @Override
+ public void onRefresh(@NonNull RefreshLayout refreshLayout) {
+ mRefreshPage = 1;
+ callBack.getRefreshDate(1, mRefreshPage, mRefreshCount);
+ }
+ });
+ }
+
+ /**
+ * 网络访问完成 刷新控件
+ *
+ * @param refreshLayout
+ * @param isLoadMore false禁用下拉加载更多
+ */
+ protected void setFinishRefresh(final SmartRefreshLayout refreshLayout, boolean isLoadMore) {
+ if (refreshLayout.getState() == RefreshState.Refreshing)
+ refreshLayout.finishRefresh();
+ else if (refreshLayout.getState() == RefreshState.Loading)
+ refreshLayout.finishLoadMore();
+ if (!isLoadMore){
+ refreshLayout.finishLoadMore(); //加载完成
+ refreshLayout.finishLoadMoreWithNoMoreData(); //全部加载完成,没有数据了调用此方法
+ }
+// refreshLayout.setEnableLoadMore(isLoadMore);
+ }
+
+ /**
+ * 设置标题
+ */
+
+ protected void setTitleBar(String title, View.OnClickListener listener) {
+ mToolbar = (Toolbar) rootView.findViewById(R.id.common_toolbar);
+ if (!TextUtils.isEmpty(title))
+ ((TextView) rootView.findViewById(R.id.common_toolBar_title)).setText(title);
+ mToolbar.setNavigationIcon(R.drawable.black_back);
+ mToolbar.setNavigationOnClickListener(listener);
+ }
+
+ /**
+ * 设置标题
+ */
+
+ protected void setTitleBar(String title) {
+ mToolbar = (Toolbar) rootView.findViewById(R.id.common_toolbar);
+ if (!TextUtils.isEmpty(title))
+ ((TextView) rootView.findViewById(R.id.common_toolBar_title)).setText(title);
+ }
+
+ /**
+ * 设置标题
+ */
+
+ protected void setTitleBar(String title, boolean isRight, View.OnClickListener listener) {
+ mToolbar = (Toolbar) rootView.findViewById(R.id.common_toolbar);
+ if (!TextUtils.isEmpty(title)) {
+ ((TextView) rootView.findViewById(R.id.common_toolBar_title)).setText(title);
+ ((RelativeLayout) rootView.findViewById(R.id.rlMessage)).setVisibility(isRight ? View.VISIBLE : View.GONE);
+ (rootView.findViewById(R.id.rlMessage)).setOnClickListener(listener);
+ }
+ }
+
+ /**
+ * 设置标题
+ */
+
+ protected void setTitleBar(String title, boolean isRight,String message, View.OnClickListener listener) {
+ mToolbar = (Toolbar) rootView.findViewById(R.id.common_toolbar);
+ if (!TextUtils.isEmpty(title)) {
+ ((TextView) rootView.findViewById(R.id.common_toolBar_title)).setText(title);
+ ((RelativeLayout) rootView.findViewById(R.id.rlMessage)).setVisibility(isRight ? View.VISIBLE : View.GONE);
+ ((TextView) rootView.findViewById(R.id.tvMessage)).setText(message);
+ (rootView.findViewById(R.id.rlMessage)).setOnClickListener(listener);
+ }
+ }
+
+ /**
+ * 设置标题
+ */
+
+ protected void setBadView(boolean isRight) {
+ if (null != ((TextView) rootView.findViewById(R.id.tvCount))) {
+ ((TextView) rootView.findViewById(R.id.tvCount)).setVisibility(isRight ? View.VISIBLE : View.GONE);
+ }
+ }
+
+ protected void setCount(int count) {
+ if (count > 100) {
+ ((TextView) rootView.findViewById(R.id.tvCount)).setText("99··");
+ } else {
+ ((TextView) rootView.findViewById(R.id.tvCount)).setText(count + "");
+ }
+
+ }
+
+
+ //setUserVisibleHint()在Fragment创建时会先被调用一次,传入isVisibleToUser = false
+ //如果当前Fragment可见,那么setUserVisibleHint()会再次被调用一次,传入isVisibleToUser = true
+ //如果Fragment从可见->不可见,那么setUserVisibleHint()也会被调用,传入isVisibleToUser = false
+ //总结:setUserVisibleHint()除了Fragment的可见状态发生变化时会被回调外,在new Fragment()时也会被回调
+ @Override
+ public void setUserVisibleHint(boolean isVisibleToUser) {
+ Log.i(TAG, "isFirstVisible: " + isFirstVisible + "--isVisibleToUser" + isVisibleToUser + "--rootView == null" + (rootView == null));
+ super.setUserVisibleHint(isVisibleToUser);
+ //setUserVisibleHint()有可能在fragment的生命周期外被调用
+ if (rootView == null) {
+ return;
+ }
+ if (isFirstVisible && isVisibleToUser) {
+ onFragmentFirstVisible();
+ isFirstVisible = false;
+ isFragmentVisible = true;
+ return;
+ }
+ if (isVisibleToUser) {
+ onFragmentVisibleChange(true);
+ isFragmentVisible = true;
+ return;
+ }
+ if (isFragmentVisible) {
+ isFragmentVisible = false;
+ onFragmentVisibleChange(false);
+ }
+ }
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ initVariable();
+ }
+
+
+ private void initVariable() {
+ isFirstVisible = true;
+ isFragmentVisible = false;
+ isPause = false;
+ rootView = null;
+ isReuseView = true;
+ }
+
+ @Override
+ public void onPause() {
+ isPause = true;
+ super.onPause();
+ }
+
+ @Override
+ public void onResume() {
+ if (isPause && getUserVisibleHint())
+ onFragmentVisibleChange(true);
+ super.onResume();
+ }
+
+ /**
+ * @param isReuse
+ */
+ protected void reuseView(boolean isReuse) {
+ isReuseView = isReuse;
+ }
+
+ /**
+ * 去除setUserVisibleHint()多余的回调场景,保证只有当fragment可见状态发生变化时才回调
+ * 回调时机在view创建完后,所以支持ui操作,解决在setUserVisibleHint()里进行ui操作有可能报null异常的问题
+ *
+ * 可在该回调方法里进行一些ui显示与隐藏
+ *
+ * @param isVisible true 不可见 -> 可见
+ * false 可见 -> 不可见
+ */
+ protected abstract void onFragmentVisibleChange(boolean isVisible);
+
+ /**
+ * 在fragment首次可见时回调,可用于加载数据,防止每次进入都重复加载数据
+ */
+ protected abstract void onFragmentFirstVisible();
+
+ protected boolean isFragmentVisible() {
+ return isFragmentVisible;
+ }
+}
\ No newline at end of file
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/bean/CarBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/bean/CarBean.java
new file mode 100644
index 0000000..1691809
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/bean/CarBean.java
@@ -0,0 +1,100 @@
+package com.dahe.mylibrary.bean;
+
+import java.io.Serializable;
+
+public class CarBean implements Serializable {
+
+
+// private String approved_load;
+// private String driver_name;
+// private String current_load;
+// private String car_number;
+// private String outline_wide;
+// private String outline_long;
+// private String driver_phone;
+// private Integer car_id;
+// private String outline_high;
+ private boolean isSelect;
+
+ private String vehicle;
+ private String carId;
+ private String outlineWide;
+ private String outlineHigh;
+ private String outlineLong;
+ private String approvedLoad;
+ private String driverName;
+ private String driverPhone;
+
+ public String getVehicle() {
+ return vehicle;
+ }
+
+ public void setVehicle(String vehicle) {
+ this.vehicle = vehicle;
+ }
+
+ public String getCarId() {
+ return carId;
+ }
+
+ public void setCarId(String carId) {
+ this.carId = carId;
+ }
+
+ public String getOutlineWide() {
+ return outlineWide;
+ }
+
+ public void setOutlineWide(String outlineWide) {
+ this.outlineWide = outlineWide;
+ }
+
+ public String getOutlineHigh() {
+ return outlineHigh;
+ }
+
+ public void setOutlineHigh(String outlineHigh) {
+ this.outlineHigh = outlineHigh;
+ }
+
+ public String getOutlineLong() {
+ return outlineLong;
+ }
+
+ public void setOutlineLong(String outlineLong) {
+ this.outlineLong = outlineLong;
+ }
+
+ public String getApprovedLoad() {
+ return approvedLoad;
+ }
+
+ public void setApprovedLoad(String approvedLoad) {
+ this.approvedLoad = approvedLoad;
+ }
+
+ public String getDriverName() {
+ return driverName;
+ }
+
+ public void setDriverName(String driverName) {
+ this.driverName = driverName;
+ }
+
+ public String getDriverPhone() {
+ return driverPhone;
+ }
+
+ public void setDriverPhone(String driverPhone) {
+ this.driverPhone = driverPhone;
+ }
+
+ public boolean isSelect() {
+ return isSelect;
+ }
+
+ public void setSelect(boolean select) {
+ isSelect = select;
+ }
+
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/bean/DictBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/bean/DictBean.java
new file mode 100644
index 0000000..f8e9983
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/bean/DictBean.java
@@ -0,0 +1,154 @@
+package com.dahe.mylibrary.bean;
+
+import java.io.Serializable;
+
+public class DictBean implements Serializable {
+
+
+ private String searchValue;
+ private String createBy;
+ private String createTime;
+ private String updateBy;
+ private String updateTime;
+ private String remark;
+ private String dictCode;
+ private String dictSort;
+ private String dictLabel;
+ private String dictValue;
+ private String dictType;
+ private String cssClass;
+ private String listClass;
+ private String isDefault;
+ private String status;
+
+ public DictBean() {
+
+ }
+
+ public DictBean(String dictValue, String dictLabel) {
+ this.dictValue = dictValue;
+ this.dictLabel = dictLabel;
+ }
+
+ public String getSearchValue() {
+ return searchValue;
+ }
+
+ public void setSearchValue(String searchValue) {
+ this.searchValue = searchValue;
+ }
+
+ public String getCreateBy() {
+ return createBy;
+ }
+
+ public void setCreateBy(String createBy) {
+ this.createBy = createBy;
+ }
+
+ public String getCreateTime() {
+ return createTime;
+ }
+
+ public void setCreateTime(String createTime) {
+ this.createTime = createTime;
+ }
+
+ public String getUpdateBy() {
+ return updateBy;
+ }
+
+ public void setUpdateBy(String updateBy) {
+ this.updateBy = updateBy;
+ }
+
+ public String getUpdateTime() {
+ return updateTime;
+ }
+
+ public void setUpdateTime(String updateTime) {
+ this.updateTime = updateTime;
+ }
+
+ public String getRemark() {
+ return remark;
+ }
+
+ public void setRemark(String remark) {
+ this.remark = remark;
+ }
+
+
+ public String getDictCode() {
+ return dictCode;
+ }
+
+ public void setDictCode(String dictCode) {
+ this.dictCode = dictCode;
+ }
+
+ public String getDictSort() {
+ return dictSort;
+ }
+
+ public void setDictSort(String dictSort) {
+ this.dictSort = dictSort;
+ }
+
+ public String getDictLabel() {
+ return dictLabel;
+ }
+
+ public void setDictLabel(String dictLabel) {
+ this.dictLabel = dictLabel;
+ }
+
+ public String getDictValue() {
+ return dictValue;
+ }
+
+ public void setDictValue(String dictValue) {
+ this.dictValue = dictValue;
+ }
+
+ public String getDictType() {
+ return dictType;
+ }
+
+ public void setDictType(String dictType) {
+ this.dictType = dictType;
+ }
+
+ public String getCssClass() {
+ return cssClass;
+ }
+
+ public void setCssClass(String cssClass) {
+ this.cssClass = cssClass;
+ }
+
+ public String getListClass() {
+ return listClass;
+ }
+
+ public void setListClass(String listClass) {
+ this.listClass = listClass;
+ }
+
+ public String getIsDefault() {
+ return isDefault;
+ }
+
+ public void setIsDefault(String isDefault) {
+ this.isDefault = isDefault;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/bean/NodeBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/bean/NodeBean.java
new file mode 100644
index 0000000..7da5641
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/bean/NodeBean.java
@@ -0,0 +1,354 @@
+package com.dahe.mylibrary.bean;
+
+import java.io.Serializable;
+
+public class NodeBean implements Serializable {
+
+
+ private String searchValue;
+ private String createBy;
+ private String createTime;
+ private String updateBy;
+ private String updateTime;
+ private String remark;
+ private String planId;
+ private String nodeId;
+ private String nodeType;
+ private String orderId;
+ private String nodeName;
+ private String address;
+ private String contacts;
+ private String contactsPhone;
+ private String contacts_phone;
+ private String provinceId;
+ private String provinceName;
+ private String cityId;
+ private String cityName;
+ private String countyId;
+ private String countyName;
+ private String planIndex;
+ private String remarks;
+ private String node_name;
+ private String warehouseId;
+ private String warehouseName;
+ private String isSelect;
+ private String w_child_id;
+ private String firstNameCode;
+
+
+ private String wChildId;
+ private String waybillId;
+ private String freighter;
+ private String freighterId;
+ private String node;
+ private String state;
+ private String isSelectOld;
+ private String dockingPhone;
+ private String docking;
+
+ public String getwChildId() {
+ return wChildId;
+ }
+
+ public void setwChildId(String wChildId) {
+ this.wChildId = wChildId;
+ }
+
+ public String getWaybillId() {
+ return waybillId;
+ }
+
+ public void setWaybillId(String waybillId) {
+ this.waybillId = waybillId;
+ }
+
+ public String getFreighter() {
+ return freighter;
+ }
+
+ public void setFreighter(String freighter) {
+ this.freighter = freighter;
+ }
+
+ public String getFreighterId() {
+ return freighterId;
+ }
+
+ public void setFreighterId(String freighterId) {
+ this.freighterId = freighterId;
+ }
+
+ public String getNode() {
+ return node;
+ }
+
+ public void setNode(String node) {
+ this.node = node;
+ }
+
+ public String getState() {
+ return state;
+ }
+
+ public void setState(String state) {
+ this.state = state;
+ }
+
+ public String getIsSelectOld() {
+ return isSelectOld;
+ }
+
+ public void setIsSelectOld(String isSelectOld) {
+ this.isSelectOld = isSelectOld;
+ }
+
+ public String getDockingPhone() {
+ return dockingPhone;
+ }
+
+ public void setDockingPhone(String dockingPhone) {
+ this.dockingPhone = dockingPhone;
+ }
+
+ public String getDocking() {
+ return docking;
+ }
+
+ public void setDocking(String docking) {
+ this.docking = docking;
+ }
+
+ public String getWarehouseId() {
+ return warehouseId;
+ }
+
+ public void setWarehouseId(String warehouseId) {
+ this.warehouseId = warehouseId;
+ }
+
+ public String getWarehouseName() {
+ return warehouseName;
+ }
+
+ public void setWarehouseName(String warehouseName) {
+ this.warehouseName = warehouseName;
+ }
+
+ public String getFirstNameCode() {
+ return firstNameCode;
+ }
+
+ public void setFirstNameCode(String firstNameCode) {
+ this.firstNameCode = firstNameCode;
+ }
+
+ public String getW_child_id() {
+ return w_child_id;
+ }
+
+ public void setW_child_id(String w_child_id) {
+ this.w_child_id = w_child_id;
+ }
+
+ public String isSelect() {
+ return isSelect;
+ }
+
+ public void setSelect(String select) {
+ isSelect = select;
+ }
+
+ public String getNode_name() {
+ return node_name;
+ }
+
+ public void setNode_name(String node_name) {
+ this.node_name = node_name;
+ }
+
+ public String getContacts_phone() {
+ return contacts_phone;
+ }
+
+ public void setContacts_phone(String contacts_phone) {
+ this.contacts_phone = contacts_phone;
+ }
+
+ public String getSearchValue() {
+ return searchValue;
+ }
+
+ public void setSearchValue(String searchValue) {
+ this.searchValue = searchValue;
+ }
+
+ public String getCreateBy() {
+ return createBy;
+ }
+
+ public void setCreateBy(String createBy) {
+ this.createBy = createBy;
+ }
+
+ public String getCreateTime() {
+ return createTime;
+ }
+
+ public void setCreateTime(String createTime) {
+ this.createTime = createTime;
+ }
+
+ public String getUpdateBy() {
+ return updateBy;
+ }
+
+ public void setUpdateBy(String updateBy) {
+ this.updateBy = updateBy;
+ }
+
+ public String getUpdateTime() {
+ return updateTime;
+ }
+
+ public void setUpdateTime(String updateTime) {
+ this.updateTime = updateTime;
+ }
+
+ public String getRemark() {
+ return remark;
+ }
+
+ public void setRemark(String remark) {
+ this.remark = remark;
+ }
+
+
+ public String getPlanId() {
+ return planId;
+ }
+
+ public void setPlanId(String planId) {
+ this.planId = planId;
+ }
+
+ public String getNodeId() {
+ return nodeId;
+ }
+
+ public void setNodeId(String nodeId) {
+ this.nodeId = nodeId;
+ }
+
+ public String getNodeType() {
+ return nodeType;
+ }
+
+ public void setNodeType(String nodeType) {
+ this.nodeType = nodeType;
+ }
+
+ public String getOrderId() {
+ return orderId;
+ }
+
+ public void setOrderId(String orderId) {
+ this.orderId = orderId;
+ }
+
+ public String getNodeName() {
+ return nodeName;
+ }
+
+ public void setNodeName(String nodeName) {
+ this.nodeName = nodeName;
+ }
+
+ public String getAddress() {
+ return address;
+ }
+
+ public void setAddress(String address) {
+ this.address = address;
+ }
+
+ public String getContacts() {
+ return contacts;
+ }
+
+ public void setContacts(String contacts) {
+ this.contacts = contacts;
+ }
+
+ public String getContactsPhone() {
+ return contactsPhone;
+ }
+
+ public void setContactsPhone(String contactsPhone) {
+ this.contactsPhone = contactsPhone;
+ }
+
+ public String getProvinceId() {
+ return provinceId;
+ }
+
+ public void setProvinceId(String provinceId) {
+ this.provinceId = provinceId;
+ }
+
+ public String getProvinceName() {
+ return provinceName;
+ }
+
+ public void setProvinceName(String provinceName) {
+ this.provinceName = provinceName;
+ }
+
+ public String getCityId() {
+ return cityId;
+ }
+
+ public void setCityId(String cityId) {
+ this.cityId = cityId;
+ }
+
+ public String getCityName() {
+ return cityName;
+ }
+
+ public void setCityName(String cityName) {
+ this.cityName = cityName;
+ }
+
+ public String getCountyId() {
+ return countyId;
+ }
+
+ public void setCountyId(String countyId) {
+ this.countyId = countyId;
+ }
+
+ public String getCountyName() {
+ return countyName;
+ }
+
+ public void setCountyName(String countyName) {
+ this.countyName = countyName;
+ }
+
+ public String getPlanIndex() {
+ return planIndex;
+ }
+
+ public void setPlanIndex(String planIndex) {
+ this.planIndex = planIndex;
+ }
+
+ public String getRemarks() {
+ return remarks;
+ }
+
+ public void setRemarks(String remarks) {
+ this.remarks = remarks;
+ }
+
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/bean/StateBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/bean/StateBean.java
new file mode 100644
index 0000000..83f9b59
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/bean/StateBean.java
@@ -0,0 +1,151 @@
+package com.dahe.mylibrary.bean;
+
+import java.io.Serializable;
+
+public class StateBean implements Serializable {
+
+
+ private String searchValue;
+ private String createBy;
+ private String createTime;
+ private String updateBy;
+ private String updateTime;
+ private String remark;
+ private String dictCode;
+ private String dictSort;
+ private String dictLabel;
+ private String dictValue;
+ private String dictType;
+ private String cssClass;
+ private String listClass;
+ private String isDefault;
+ private String status;
+
+ public StateBean(String dictLabel, String dictValue) {
+ this.dictLabel = dictLabel;
+ this.dictValue = dictValue;
+ }
+
+ public String getSearchValue() {
+ return searchValue;
+ }
+
+ public void setSearchValue(String searchValue) {
+ this.searchValue = searchValue;
+ }
+
+ public String getCreateBy() {
+ return createBy;
+ }
+
+ public void setCreateBy(String createBy) {
+ this.createBy = createBy;
+ }
+
+ public String getCreateTime() {
+ return createTime;
+ }
+
+ public void setCreateTime(String createTime) {
+ this.createTime = createTime;
+ }
+
+ public String getUpdateBy() {
+ return updateBy;
+ }
+
+ public void setUpdateBy(String updateBy) {
+ this.updateBy = updateBy;
+ }
+
+ public String getUpdateTime() {
+ return updateTime;
+ }
+
+ public void setUpdateTime(String updateTime) {
+ this.updateTime = updateTime;
+ }
+
+ public String getRemark() {
+ return remark;
+ }
+
+ public void setRemark(String remark) {
+ this.remark = remark;
+ }
+
+ public String getDictCode() {
+ return dictCode;
+ }
+
+ public void setDictCode(String dictCode) {
+ this.dictCode = dictCode;
+ }
+
+ public String getDictSort() {
+ return dictSort;
+ }
+
+ public void setDictSort(String dictSort) {
+ this.dictSort = dictSort;
+ }
+
+ public String getDictLabel() {
+ return dictLabel;
+ }
+
+ public void setDictLabel(String dictLabel) {
+ this.dictLabel = dictLabel;
+ }
+
+ public String getDictValue() {
+ return dictValue;
+ }
+
+ public void setDictValue(String dictValue) {
+ this.dictValue = dictValue;
+ }
+
+ public String getDictType() {
+ return dictType;
+ }
+
+ public void setDictType(String dictType) {
+ this.dictType = dictType;
+ }
+
+ public String getCssClass() {
+ return cssClass;
+ }
+
+ public void setCssClass(String cssClass) {
+ this.cssClass = cssClass;
+ }
+
+ public String getListClass() {
+ return listClass;
+ }
+
+ public void setListClass(String listClass) {
+ this.listClass = listClass;
+ }
+
+ public String getIsDefault() {
+ return isDefault;
+ }
+
+ public void setIsDefault(String isDefault) {
+ this.isDefault = isDefault;
+ }
+
+ public String getStatus() {
+ return status;
+ }
+
+ public void setStatus(String status) {
+ this.status = status;
+ }
+
+ public static class ParamsDTO {
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/bean/TipsBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/bean/TipsBean.java
new file mode 100644
index 0000000..1b989cc
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/bean/TipsBean.java
@@ -0,0 +1,29 @@
+package com.dahe.mylibrary.bean;
+
+import java.io.Serializable;
+
+public class TipsBean implements Serializable {
+ private String title;
+ private String content;
+
+ public TipsBean(String title, String content) {
+ this.title = title;
+ this.content = content;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getContent() {
+ return content;
+ }
+
+ public void setContent(String content) {
+ this.content = content;
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/bean/VersionBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/bean/VersionBean.java
new file mode 100644
index 0000000..55f51f7
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/bean/VersionBean.java
@@ -0,0 +1,93 @@
+package com.dahe.mylibrary.bean;
+
+import java.io.Serializable;
+
+public class VersionBean implements Serializable {
+
+
+
+ private ParamsDao data;
+
+ public ParamsDao getData() {
+ return data;
+ }
+
+ public void setData(ParamsDao data) {
+ this.data = data;
+ }
+
+ public static class ParamsDao implements Serializable{
+ private int versionId;
+ private int version;
+ private String versionName;
+ private String introduce;
+ private String updateType;
+ private String createTime;
+ private String remark;
+ private String apkUrl;
+
+ public String getApkUrl() {
+ return apkUrl;
+ }
+
+ public void setApkUrl(String apkUrl) {
+ this.apkUrl = apkUrl;
+ }
+
+ public int getVersionId() {
+ return versionId;
+ }
+
+ public void setVersionId(int versionId) {
+ this.versionId = versionId;
+ }
+
+ public int getVersion() {
+ return version;
+ }
+
+ public void setVersion(int version) {
+ this.version = version;
+ }
+
+ public String getVersionName() {
+ return versionName;
+ }
+
+ public void setVersionName(String versionName) {
+ this.versionName = versionName;
+ }
+
+ public String getIntroduce() {
+ return introduce;
+ }
+
+ public void setIntroduce(String introduce) {
+ this.introduce = introduce;
+ }
+
+ public String getUpdateType() {
+ return updateType;
+ }
+
+ public void setUpdateType(String updateType) {
+ this.updateType = updateType;
+ }
+
+ public String getCreateTime() {
+ return createTime;
+ }
+
+ public void setCreateTime(String createTime) {
+ this.createTime = createTime;
+ }
+
+ public String getRemark() {
+ return remark;
+ }
+
+ public void setRemark(String remark) {
+ this.remark = remark;
+ }
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/callback/OnItemLongClickListener.java b/mylibrary/src/main/java/com/dahe/mylibrary/callback/OnItemLongClickListener.java
new file mode 100644
index 0000000..9e949df
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/callback/OnItemLongClickListener.java
@@ -0,0 +1,14 @@
+package com.dahe.mylibrary.callback;
+
+import android.view.View;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+/**
+ * @author:luck
+ * @date:2020-01-13 17:58
+ * @describe:长按事件
+ */
+public interface OnItemLongClickListener {
+ void onItemLongClick(RecyclerView.ViewHolder holder, int position, View v);
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/callback/RefreshCallBack.java b/mylibrary/src/main/java/com/dahe/mylibrary/callback/RefreshCallBack.java
new file mode 100644
index 0000000..adc89c3
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/callback/RefreshCallBack.java
@@ -0,0 +1,14 @@
+package com.dahe.mylibrary.callback;
+
+/**
+ * 刷新的回调
+ */
+
+public interface RefreshCallBack {
+ /**
+ * @param stat 1刷新 2加载更多
+ * @param page 当前页数
+ * @param count 当前count
+ */
+ void getRefreshDate(int stat, int page, int count);
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/CarSelPopupView.java b/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/CarSelPopupView.java
new file mode 100644
index 0000000..26850dc
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/CarSelPopupView.java
@@ -0,0 +1,102 @@
+package com.dahe.mylibrary.cuspop;
+
+import android.content.Context;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.chad.library.adapter.base.BaseQuickAdapter;
+import com.chad.library.adapter.base.listener.OnItemClickListener;
+import com.dahe.mylibrary.R;
+import com.dahe.mylibrary.adapter.CarAdapter;
+import com.dahe.mylibrary.bean.CarBean;
+import com.dahe.mylibrary.net.JsonUtils;
+import com.lxj.xpopup.core.CenterPopupView;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CarSelPopupView extends CenterPopupView {
+
+
+ private Context context;
+ private List data;
+ public CarSelPopupView(Context context, String data) {
+ super(context);
+ this.context = context;
+ ArrayList nodeBeans = JsonUtils.getInstance().jsonToList(data, CarBean.class);
+ this.data = nodeBeans;
+ }
+
+ @Override
+ protected int getImplLayoutId() {
+ return R.layout.view_node;
+ }
+
+ @Override
+ protected void onCreate() {
+ super.onCreate();
+ TextView tvTitle = (TextView) findViewById(R.id.tvTitle);
+ ImageView ivCha = (ImageView) findViewById(R.id.ivCha);
+ LinearLayout llCha = (LinearLayout) findViewById(R.id.llCha);
+ Button btnOK = (Button) findViewById(R.id.btnOK);
+ RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
+ recyclerView.setLayoutManager(new LinearLayoutManager(context,RecyclerView.VERTICAL,false));
+ recyclerView.setHasFixedSize(true);
+ CarAdapter nodeAdapter = new CarAdapter(-1,data);
+ recyclerView.setAdapter(nodeAdapter);
+
+ tvTitle.setText("关联司机");
+ nodeAdapter.setOnItemClickListener(new OnItemClickListener() {
+ @Override
+ public void onItemClick(@NonNull @NotNull BaseQuickAdapter, ?> adapter, @NonNull @NotNull View view, int position) {
+ CarBean nodeSelectBean = data.get(position);
+ nodeSelectBean.setSelect(!nodeSelectBean.isSelect());
+ nodeAdapter.notifyItemChanged(position);
+ }
+ });
+
+ btnOK.setOnClickListener(v -> {
+ if (listener!=null){
+// ArrayList temp = new ArrayList<>();
+// for (int i = 0; i < data.size(); i++) {
+// CarBean nodeSelectBean = data.get(i);
+// if ("1".equals(nodeSelectBean.isSelect())){
+// temp.add(nodeSelectBean);
+// }
+//
+// }
+// if (temp.size()<=0){
+// ToastUtils.showToast(context,"至少存在一个节点");
+// return;
+// }
+ listener.okClick(JsonUtils.getInstance().toJson(nodeAdapter.getData()));
+// temp = null;
+ dismiss();
+ }
+ });
+ llCha.setOnClickListener(v -> {
+ dismiss();
+ });
+ }
+
+
+ private OnOkListener listener;
+
+ public CarSelPopupView setOnOkListener(OnOkListener listener) {
+ this.listener = listener;
+ return this;
+ }
+
+ public interface OnOkListener {
+ void okClick(String data);
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/CenterPopupView.java b/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/CenterPopupView.java
new file mode 100644
index 0000000..14a7542
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/cuspop/CenterPopupView.java
@@ -0,0 +1,90 @@
+package com.dahe.mylibrary.cuspop;
+
+import android.app.Activity;
+import android.content.Context;
+import android.util.Log;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.chad.library.adapter.base.BaseQuickAdapter;
+import com.chad.library.adapter.base.listener.OnItemClickListener;
+import com.dahe.mylibrary.R;
+import com.dahe.mylibrary.adapter.CenterSimAdapter;
+import com.dahe.mylibrary.bean.StateBean;
+import com.luck.picture.lib.decoration.GridSpacingItemDecoration;
+import com.lxj.xpopup.impl.PartShadowPopupView;
+
+import java.util.List;
+
+/**
+ * Description: 自定义局部阴影弹窗
+ * Create by dance, at 2018/12/21
+ */
+public class CenterPopupView extends PartShadowPopupView {
+ private Context ctx;
+ private RecyclerView recyclerView;
+ private List wordList;
+ private CenterSimAdapter adapter;
+ private StateBean selectString;
+
+ public CenterPopupView(@NonNull Activity context, List wordList, StateBean selectString) {
+ super(context);
+ this.wordList= wordList;
+ this.selectString = selectString;
+ }
+
+ @Override
+ protected int getImplLayoutId() {
+ return R.layout.custom_part_shadow_popup;
+ }
+
+
+ @Override
+ protected void onCreate() {
+ super.onCreate();
+ recyclerView = findViewById(R.id.recyclerView);
+ GridLayoutManager gridLayoutManager = new GridLayoutManager(ctx, 4);
+ recyclerView.addItemDecoration(new GridSpacingItemDecoration(4, 20, false));
+ recyclerView.setLayoutManager(gridLayoutManager);
+ adapter = new CenterSimAdapter(-1, wordList,selectString);
+ recyclerView.setAdapter(adapter);
+
+ adapter.setOnItemClickListener(new OnItemClickListener() {
+ @Override
+ public void onItemClick(@NonNull BaseQuickAdapter adapter, @NonNull View view, int position) {
+ if (listener!=null){
+ listener.selectChange(wordList.get(position),position);
+ }
+ ((CenterSimAdapter)adapter).setSelect(wordList.get(position));
+ adapter.notifyDataSetChanged();
+ dismiss();
+ }
+ });
+
+ }
+
+ @Override
+ protected void onShow() {
+ super.onShow();
+ Log.e("tag", "CustomPartShadowPopupView onShow");
+ }
+
+ @Override
+ protected void onDismiss() {
+ super.onDismiss();
+ Log.e("tag", "CustomPartShadowPopupView onDismiss");
+ }
+
+
+ private OnSelectChangeListener listener;
+ public CenterPopupView setOnSelectChangeListener(OnSelectChangeListener listener){
+ this.listener = listener;
+ return this;
+ }
+ public interface OnSelectChangeListener{
+ void selectChange(StateBean item ,int postion);
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/dialog/DialogPhotoSelect.java b/mylibrary/src/main/java/com/dahe/mylibrary/dialog/DialogPhotoSelect.java
new file mode 100644
index 0000000..e06f0e3
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/dialog/DialogPhotoSelect.java
@@ -0,0 +1,108 @@
+package com.dahe.mylibrary.dialog;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+
+import com.dahe.mylibrary.R;
+
+
+/**
+ * 头像选择 dialog
+ *
+ * @Description:
+ * @Author: tao
+ * @CreateDate: 2018/7/26 10:34
+ */
+public class DialogPhotoSelect extends MyBaseDialog {
+
+ private TextView take_photo;
+ private TextView select_photo;
+ private TextView do_cancel;
+
+ private onSelectClickListener onSelectClickListener;
+
+ public void setOnSelectClickListener(onSelectClickListener onSelectClickListener) {
+ this.onSelectClickListener = onSelectClickListener;
+ }
+
+ public DialogPhotoSelect(@NonNull Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.dialog_photo_select);
+
+ initView();
+ initListener();
+ }
+
+ private void initView() {
+ take_photo = findViewById( R.id.take_photo);
+ select_photo = findViewById(R.id.select_photo);
+ do_cancel = findViewById(R.id.do_cancel);
+ }
+
+ private void initListener() {
+
+ //拍照
+ take_photo.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ dismiss();
+ onSelectClickListener.onTakePhoto();
+ }
+ });
+
+ //相册选择
+ select_photo.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ dismiss();
+ onSelectClickListener.onSelectPhoto();
+ }
+ });
+
+ do_cancel.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ dismiss();
+ }
+ });
+
+
+ }
+
+ @Override
+ public void init(@NonNull Context context) {
+ Window window = getWindow();
+ window.setWindowAnimations(R.style.BottomAnim);
+ window.setGravity( Gravity.BOTTOM);
+ //默认的Dialog只有5/6左右的宽度,改为全屏宽度,由dialog的布局自己来决定实际显示宽度
+ window.getDecorView().setPadding(0, 0, 0, 0);
+ WindowManager.LayoutParams lp = window.getAttributes();
+ lp.width = WindowManager.LayoutParams.MATCH_PARENT;
+ lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
+ window.setAttributes(lp);
+ }
+
+ @Override
+ public boolean isCancelAble() {
+ return true;
+ }
+
+ public interface onSelectClickListener {
+
+ void onTakePhoto();
+
+ void onSelectPhoto();
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/dialog/MyBaseDialog.java b/mylibrary/src/main/java/com/dahe/mylibrary/dialog/MyBaseDialog.java
new file mode 100644
index 0000000..74b915f
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/dialog/MyBaseDialog.java
@@ -0,0 +1,55 @@
+package com.dahe.mylibrary.dialog;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.Window;
+import android.view.WindowManager;
+
+import androidx.annotation.NonNull;
+
+import com.dahe.mylibrary.R;
+
+
+/**
+ * Dialog 基类 基类 基类
+ *
+ * 以后再写Dialog,都要继承这个
+ *
+ * @Description:
+ * @Author: tao
+ * @CreateDate: 2018/7/26 10:29
+ */
+public class MyBaseDialog extends Dialog {
+
+
+ public MyBaseDialog(@NonNull Context context) {
+ super(context, R.style.MyBaseDialog);
+ init(context);
+ }
+
+ public void init(@NonNull Context context) {
+ Window window = getWindow();
+ window.setWindowAnimations(R.style.BottomAnim);
+ window.setGravity(Gravity.CENTER);
+ //默认的Dialog只有5/6左右的宽度,改为全屏宽度,由dialog的布局自己来决定实际显示宽度
+ window.getDecorView().setPadding(0, 0, 0, 0);
+ WindowManager.LayoutParams lp = window.getAttributes();
+ lp.width = WindowManager.LayoutParams.MATCH_PARENT;
+ lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
+ window.setAttributes(lp);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setCancelable(isCancelAble());
+ setCanceledOnTouchOutside(isCancelAble());
+ }
+
+ public boolean isCancelAble() {
+ return false;
+ }
+
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/dialog/VersionDialog.java b/mylibrary/src/main/java/com/dahe/mylibrary/dialog/VersionDialog.java
new file mode 100644
index 0000000..383c55f
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/dialog/VersionDialog.java
@@ -0,0 +1,21 @@
+package com.dahe.mylibrary.dialog;
+
+import android.app.Dialog;
+import android.content.Context;
+
+/**
+ * Created by Allen Liu on 2017/2/23.
+ */
+public class VersionDialog extends Dialog {
+ private int res;
+
+ public VersionDialog(Context context, int theme, int res) {
+ super(context, theme);
+ getWindow().setBackgroundDrawableResource(android.R.color.transparent);
+ // TODO 自动生成的构造函数存根
+ setContentView(res);
+ this.res = res;
+ setCanceledOnTouchOutside(false);
+ }
+
+}
\ No newline at end of file
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/glide/AppGlideModule.java b/mylibrary/src/main/java/com/dahe/mylibrary/glide/AppGlideModule.java
new file mode 100644
index 0000000..2387881
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/glide/AppGlideModule.java
@@ -0,0 +1,35 @@
+package com.dahe.mylibrary.glide;
+
+import android.content.Context;
+
+import androidx.annotation.NonNull;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.Registry;
+import com.bumptech.glide.annotation.GlideModule;
+import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader;
+import com.bumptech.glide.load.model.GlideUrl;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.io.InputStream;
+
+import okhttp3.OkHttpClient;
+
+/**
+ * @ClassName AppGlideModule
+ * @Author 用户
+ * @Date 2021/10/11 10:13
+ * @Description TODO
+ */
+
+@GlideModule
+public class AppGlideModule extends com.bumptech.glide.module.AppGlideModule {
+
+ @Override
+ public void registerComponents(@NonNull @NotNull Context context, @NonNull @NotNull Glide glide, @NonNull @NotNull Registry registry) {
+ super.registerComponents(context, glide, registry);
+ OkHttpClient client = UnsafeOkHttpClient.getUnsafeOkHttpClient();
+ registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(client));
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/glide/UnsafeOkHttpClient.java b/mylibrary/src/main/java/com/dahe/mylibrary/glide/UnsafeOkHttpClient.java
new file mode 100644
index 0000000..da9e54e
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/glide/UnsafeOkHttpClient.java
@@ -0,0 +1,67 @@
+package com.dahe.mylibrary.glide;
+
+import java.security.cert.CertificateException;
+import java.util.concurrent.TimeUnit;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import okhttp3.OkHttpClient;
+
+/**
+ * @ClassName UnsafeOkHttpClient
+ * @Author 用户
+ * @Date 2021/10/11 10:16
+ * @Description TODO
+ */
+public class UnsafeOkHttpClient {
+ public static OkHttpClient getUnsafeOkHttpClient() {
+ try {
+ // Create a trust manager that does not validate certificate chains
+ final TrustManager[] trustAllCerts = new TrustManager[]{
+ new X509TrustManager() {
+ @Override
+ public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
+ }
+
+ @Override
+ public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
+ }
+
+ @Override
+ public java.security.cert.X509Certificate[] getAcceptedIssuers() {
+ return new java.security.cert.X509Certificate[]{};
+ }
+ }
+ };
+
+ // Install the all-trusting trust manager
+ final SSLContext sslContext = SSLContext.getInstance("SSL");
+ sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
+
+ // Create an ssl socket factory with our all-trusting manager
+ final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
+
+ OkHttpClient.Builder builder = new OkHttpClient.Builder();
+ builder.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
+ builder.hostnameVerifier(new HostnameVerifier() {
+ @Override
+ public boolean verify(String hostname, SSLSession session) {
+ return true;
+ }
+ });
+
+ builder.connectTimeout(20, TimeUnit.SECONDS);
+ builder.readTimeout(20,TimeUnit.SECONDS);
+
+ OkHttpClient okHttpClient = builder.build();
+ return okHttpClient;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/CommonResponseBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/CommonResponseBean.java
new file mode 100644
index 0000000..d6ac17a
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/CommonResponseBean.java
@@ -0,0 +1,73 @@
+package com.dahe.mylibrary.net;
+
+import java.io.Serializable;
+
+/**
+ * 返回通用的实体类
+ */
+
+public class CommonResponseBean implements Serializable {
+ private T data;
+ private int code;
+ private String info;
+ private String msg;
+ private String url;
+ private String fileName;
+ private boolean success;
+
+ public T getData() {
+ return data;
+ }
+
+ public void setData(T data) {
+ this.data = data;
+ }
+
+ public int getCode() {
+ return code;
+ }
+
+ public void setCode(int code) {
+ this.code = code;
+ }
+
+ public String getInfo() {
+ return info;
+ }
+
+ public void setInfo(String info) {
+ this.info = info;
+ }
+
+ public String getMsg() {
+ return msg;
+ }
+
+ public void setMsg(String msg) {
+ this.msg = msg;
+ }
+
+ public boolean isSuccess() {
+ return success;
+ }
+
+ public void setSuccess(boolean success) {
+ this.success = success;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ public void setFileName(String fileName) {
+ this.fileName = fileName;
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/ErrorResponse.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/ErrorResponse.java
new file mode 100644
index 0000000..d2998e9
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/ErrorResponse.java
@@ -0,0 +1,22 @@
+package com.dahe.mylibrary.net;
+
+public class ErrorResponse {
+ private int code;
+ private String msg;
+
+ public int getCode() {
+ return code;
+ }
+
+ public void setCode(int code) {
+ this.code = code;
+ }
+
+ public String getMsg() {
+ return msg;
+ }
+
+ public void setMsg(String msg) {
+ this.msg = msg;
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/FileInterceptor.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/FileInterceptor.java
new file mode 100644
index 0000000..d373b7c
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/FileInterceptor.java
@@ -0,0 +1,60 @@
+package com.dahe.mylibrary.net;
+
+import android.util.Log;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.Charset;
+
+import okhttp3.Interceptor;
+import okhttp3.MediaType;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+import okhttp3.ResponseBody;
+import okio.Buffer;
+import okio.BufferedSource;
+
+/**
+ * 文件上传Interceptor
+ */
+
+public class FileInterceptor implements Interceptor {
+ private static final String TAG = "FileInterceptor";
+ private File mFile;
+
+ public FileInterceptor(File mFile) {
+ this.mFile = mFile;
+ }
+
+ @Override
+ public Response intercept(Chain chain) throws IOException {
+ Request request = chain.request();
+ request = request.newBuilder()
+ .post(RequestBody.create(MediaType.parse("application/file; charset=utf-8"), mFile))
+ .build();
+ Response response = chain.proceed(request);
+ Log.i(TAG, "url= " + request.body());
+ Log.i(TAG, "method= " + request.method());
+ ResponseBody responseBody = response.body();
+ //为了不消耗buffer,我们这里使用source先获得buffer对象,然后clone()后使用
+ BufferedSource source = responseBody.source();
+ source.request(Long.MAX_VALUE); // Buffer the entire body.
+ //获得返回的数据
+ Buffer buffer = source.buffer();
+ //使用前clone()下,避免直接消耗
+ String responseBodyStr = buffer.clone().readString(Charset.forName("UTF-8"));
+ Log.i(TAG, "result-body= " + responseBodyStr);
+ try {
+ JSONObject jsonObject = new JSONObject(responseBodyStr);
+ responseBody = ResponseBody.create(MediaType.parse("application/json; charset=utf-8"), jsonObject.getString("response"));
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ response = response.newBuilder().body(responseBody).build();
+ return response;
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/GsonResponseBodyConverter.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/GsonResponseBodyConverter.java
new file mode 100644
index 0000000..5ce33b2
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/GsonResponseBodyConverter.java
@@ -0,0 +1,74 @@
+package com.dahe.mylibrary.net;
+
+import com.google.gson.Gson;
+
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.lang.reflect.Type;
+import java.nio.charset.Charset;
+
+import okhttp3.ResponseBody;
+import okio.Buffer;
+import okio.BufferedSource;
+import retrofit2.Converter;
+
+
+public class GsonResponseBodyConverter implements Converter {
+ private final Gson gson;
+ private final Type type;
+
+
+ public GsonResponseBodyConverter(Gson gson, Type type) {
+ this.gson = gson;
+ this.type = type;
+ }
+
+ @Override
+ public T convert(ResponseBody value) throws IOException {
+
+ //为了不消耗buffer,我们这里使用source先获得buffer对象,然后clone()后使用
+ BufferedSource source = value.source();
+ source.request(Long.MAX_VALUE); // Buffer the entire body.
+ //获得返回的数据
+ Buffer buffer = source.buffer();
+ //使用前clone()下,避免直接消耗
+ String responseBodyStr = buffer.clone().readString(Charset.forName("UTF-8"));
+ try {
+
+ JSONObject jsonObject = new JSONObject(responseBodyStr);
+ int code = jsonObject.optInt("code");
+ if (-1 == code) {
+ jsonObject.put("data", new JSONObject());
+// ErrorResponse errorResponse = gson.fromJson(response, ErrorResponse.class);
+ //抛一个自定义ResultException 传入失败时候的状态码,和信息
+
+ throw new ResultException(-1, "errorResponse.getMsg()");
+
+// return gson.fromJson(responseBodyStr,type);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return gson.fromJson(responseBodyStr, type);
+
+
+// String response = value.string();
+// //先将返回的json数据解析到Response中,如果code==200,则解析到我们的实体基类中,否则抛异常
+// Response httpResult = gson.fromJson(response, Response.class);
+// if (httpResult.code()==200){
+// //200的时候就直接解析,不可能出现解析异常。因为我们实体基类中传入的泛型,就是数据成功时候的格式
+// return gson.fromJson(response,type);
+// }else {
+// ErrorResponse errorResponse = gson.fromJson(response,ErrorResponse.class);
+// //抛一个自定义ResultException 传入失败时候的状态码,和信息
+// try {
+// throw new ResultException(errorResponse.getCode(),errorResponse.getMsg());
+// } catch (ResultException e) {
+// e.printStackTrace();
+// }
+// return null;
+// }
+ }
+}
+
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/JsonInterceptor.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/JsonInterceptor.java
new file mode 100644
index 0000000..694a18e
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/JsonInterceptor.java
@@ -0,0 +1,62 @@
+package com.dahe.mylibrary.net;
+
+import android.text.TextUtils;
+import android.util.Log;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+
+import okhttp3.Interceptor;
+import okhttp3.MediaType;
+import okhttp3.Request;
+import okhttp3.Response;
+import okhttp3.ResponseBody;
+import okio.Buffer;
+import okio.BufferedSource;
+
+/**
+ * json的Interceptor
+ */
+
+public class JsonInterceptor implements Interceptor {
+ private static final String TAG = "JsonInterceptor";
+
+ public JsonInterceptor() {
+ }
+
+ @Override
+ public Response intercept(Chain chain) throws IOException {
+ Request request = chain.request();
+ Response response = chain.proceed(request);
+ ResponseBody responseBody = response.body();
+ //为了不消耗buffer,我们这里使用source先获得buffer对象,然后clone()后使用
+ BufferedSource source = responseBody.source();
+ source.request(Long.MAX_VALUE); // Buffer the entire body.
+ //获得返回的数据
+ Buffer buffer = source.buffer();
+ //使用前clone()下,避免直接消耗
+ String responseBodyStr = buffer.clone().readString(Charset.forName("UTF-8"));
+ Log.i(TAG, "result-body= " + responseBodyStr);
+ try {
+ JSONObject jsonObject = new JSONObject(responseBodyStr);
+ String str = jsonObject.optString("data");
+ int code = jsonObject.optInt("code");
+ if (-1 == code) {
+ jsonObject.put("data", new JSONObject());
+ throw new ResultException();
+ } else {
+ if (TextUtils.isEmpty(str)) {
+ jsonObject.put("data", new JSONObject());
+ }
+ }
+
+ String data = jsonObject.toString();
+ responseBody = ResponseBody.create(MediaType.parse("application/json; charset=utf-8"), data);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ response = response.newBuilder().body(responseBody).build();
+ return response;
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/JsonUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/JsonUtils.java
new file mode 100644
index 0000000..37d91af
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/JsonUtils.java
@@ -0,0 +1,91 @@
+package com.dahe.mylibrary.net;
+
+import android.util.Log;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonIOException;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonSyntaxException;
+import com.google.gson.reflect.TypeToken;
+import com.google.gson.stream.JsonReader;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+
+/**
+ * 利用Gson反射对象类型,将json转化为对象
+ */
+public class JsonUtils {
+ private Gson mGson = null;
+ private static JsonUtils mUtils;
+
+ public static JsonUtils getInstance() {
+ if (mUtils == null) {
+ return new JsonUtils();
+ } else {
+ return mUtils;
+ }
+ }
+
+ public Gson getGson() {
+ if (null == mGson) {
+ mGson = new GsonBuilder().serializeNulls().create();
+ }
+ return mGson;
+ }
+
+ public String toJson(Object o){
+ return getGson().toJson(o);
+ }
+
+ /**
+ * 将json数组转化为List
+ *
+ * @param json json字符串
+ * @param classOfT 对应实体类型
+ * @return 实体列表
+ */
+ public ArrayList jsonToList(String json, Class classOfT) {
+ try {
+ if (mGson == null) {
+ // 不要直接new Gson是为了避免放回结果为null的这种情况
+ mGson = new GsonBuilder().serializeNulls().create();
+ }
+ Type type = new TypeToken>() {
+ }.getType();
+ ArrayList jsonObjs = mGson.fromJson(json, type);
+
+ ArrayList listOfT = new ArrayList();
+ for (JsonObject jsonObj : jsonObjs) {
+ listOfT.add(mGson.fromJson(jsonObj, classOfT));
+ }
+ return listOfT;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public T fromJson(String json, Class type) throws JsonIOException, JsonSyntaxException {
+ try {
+ JSONObject object = new JSONObject(json);
+ json = object.getString("response");
+ Log.i("fromJson: ", json);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ return getGson().fromJson(json, type);
+ }
+
+ public T fromJson(String json, Type type) {
+ return getGson().fromJson(json, type);
+ }
+
+ public T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
+ return getGson().fromJson(reader, typeOfT);
+ }
+
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/PagerBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/PagerBean.java
new file mode 100644
index 0000000..5ce514d
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/PagerBean.java
@@ -0,0 +1,47 @@
+package com.dahe.mylibrary.net;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by Administrator on 2018\8\26 0026.
+ */
+public class PagerBean {
+ private int total;
+ private int count;
+ private int more;
+
+ private ArrayList rows;
+
+ public ArrayList getRows() {
+ return rows;
+ }
+
+ public void setRows(ArrayList rows) {
+ this.rows = rows;
+ }
+
+ public int getTotal() {
+ return total;
+ }
+
+ public void setTotal(int total) {
+ this.total = total;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public void setCount(int count) {
+ this.count = count;
+ }
+
+ public int getMore() {
+ return more;
+ }
+
+ public void setMore(int more) {
+ this.more = more;
+ }
+}
\ No newline at end of file
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/PagingBean.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/PagingBean.java
new file mode 100644
index 0000000..7aa11f5
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/PagingBean.java
@@ -0,0 +1,46 @@
+package com.dahe.mylibrary.net;
+
+import java.io.Serializable;
+
+/**
+ * 返回通用的实体类
+ */
+
+public class PagingBean implements Serializable {
+ private T data;
+ private int code;
+ private String count;
+ private String msg;
+
+ public T getData() {
+ return data;
+ }
+
+ public void setData(T data) {
+ this.data = data;
+ }
+
+ public int getCode() {
+ return code;
+ }
+
+ public void setCode(int code) {
+ this.code = code;
+ }
+
+ public String getCount() {
+ return count;
+ }
+
+ public void setCount(String count) {
+ this.count = count;
+ }
+
+ public String getMsg() {
+ return msg;
+ }
+
+ public void setMsg(String msg) {
+ this.msg = msg;
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/ResponseConverterFactory.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/ResponseConverterFactory.java
new file mode 100644
index 0000000..7d040ed
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/ResponseConverterFactory.java
@@ -0,0 +1,44 @@
+package com.dahe.mylibrary.net;
+
+import com.google.gson.Gson;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import okhttp3.RequestBody;
+import okhttp3.ResponseBody;
+import retrofit2.Converter;
+import retrofit2.Retrofit;
+
+public class ResponseConverterFactory extends Converter.Factory {
+
+ public static ResponseConverterFactory create() {
+ return create(new Gson());
+ }
+
+
+ public static ResponseConverterFactory create(Gson gson) {
+ return new ResponseConverterFactory(gson);
+ }
+
+ private final Gson gson;
+
+ private ResponseConverterFactory(Gson gson) {
+ if (gson == null) throw new NullPointerException("gson == null");
+ this.gson = gson;
+ }
+
+ @Override
+ public Converter responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
+ //返回我们自定义的Gson响应体变换器
+ return new GsonResponseBodyConverter<>(gson, type);
+ }
+
+ @Override
+ public Converter, RequestBody> requestBodyConverter(Type type,
+ Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
+ //返回我们自定义的Gson响应体变换器
+ return new GsonResponseBodyConverter<>(gson,type);
+ }
+}
+
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/net/ResultException.java b/mylibrary/src/main/java/com/dahe/mylibrary/net/ResultException.java
new file mode 100644
index 0000000..31ffeed
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/net/ResultException.java
@@ -0,0 +1,12 @@
+package com.dahe.mylibrary.net;
+
+public class ResultException extends Exception {
+
+ public ResultException() {
+ super();
+ // TODO Auto-generated constructor stub
+ }
+
+ public ResultException(int code, String msg) {
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/recycleviewswipe/GridSpacingItemDecoration.java b/mylibrary/src/main/java/com/dahe/mylibrary/recycleviewswipe/GridSpacingItemDecoration.java
new file mode 100644
index 0000000..017eb0f
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/recycleviewswipe/GridSpacingItemDecoration.java
@@ -0,0 +1,43 @@
+package com.dahe.mylibrary.recycleviewswipe;
+
+import android.graphics.Rect;
+import android.view.View;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+public class GridSpacingItemDecoration extends RecyclerView.ItemDecoration {
+
+ private int spanCount; //列数
+ private int spacing; //间隔
+ private boolean includeEdge; //是否包含边缘
+
+ public GridSpacingItemDecoration(int spanCount, int spacing, boolean includeEdge) {
+ this.spanCount = spanCount;
+ this.spacing = spacing;
+ this.includeEdge = includeEdge;
+ }
+
+ @Override
+ public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
+
+ //这里是关键,需要根据你有几列来判断
+ int position = parent.getChildAdapterPosition(view); // item position
+ int column = position % spanCount; // item column
+
+ if (includeEdge) {
+ outRect.left = spacing - column * spacing / spanCount; // spacing - column * ((1f / spanCount) * spacing)
+ outRect.right = (column + 1) * spacing / spanCount; // (column + 1) * ((1f / spanCount) * spacing)
+
+ if (position < spanCount) { // top edge
+ outRect.top = spacing;
+ }
+ outRect.bottom = spacing; // item bottom
+ } else {
+ outRect.left = column * spacing / spanCount; // column * ((1f / spanCount) * spacing)
+ outRect.right = spacing - (column + 1) * spacing / spanCount; // spacing - (column + 1) * ((1f / spanCount) * spacing)
+ if (position >= spanCount) {
+ outRect.top = spacing; // item top
+ }
+ }
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/recycleviewswipe/MyDecoration.java b/mylibrary/src/main/java/com/dahe/mylibrary/recycleviewswipe/MyDecoration.java
new file mode 100644
index 0000000..faf06a3
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/recycleviewswipe/MyDecoration.java
@@ -0,0 +1,110 @@
+package com.dahe.mylibrary.recycleviewswipe;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.dahe.mylibrary.R;
+
+
+public class MyDecoration extends RecyclerView.ItemDecoration{
+
+ public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
+
+ public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
+
+ private Drawable mDivider;
+
+ private int mOrientation;
+
+ /**
+ * 分割线缩进值
+ */
+ private int inset;
+
+ private Paint paint;
+
+ /**
+ * @param context
+ * @param orientation layout的方向
+ * @param drawable 引入的drawable的ID
+ * @param inset 分割线缩进值
+ */
+ public MyDecoration(Context context, int orientation, int drawable, int inset) {
+ mDivider = context.getResources().getDrawable(drawable);
+ this.inset = inset;
+ paint = new Paint();
+ paint.setColor(context.getResources().getColor(R.color.white));
+ paint.setStyle(Paint.Style.FILL);
+ paint.setAntiAlias(true);
+ setOrientation(orientation);
+ }
+
+ public void setOrientation(int orientation) {
+ if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
+ throw new IllegalArgumentException("invalid orientation");
+ }
+ mOrientation = orientation;
+ }
+
+ @Override
+ public void onDraw(Canvas c, RecyclerView parent) {
+ if (mOrientation == VERTICAL_LIST) {
+ drawVertical(c, parent);
+ } else {
+ drawHorizontal(c, parent);
+ }
+ }
+
+ private void drawVertical(Canvas c, RecyclerView parent) {
+ final int left = parent.getPaddingLeft();
+ final int right = parent.getWidth() - parent.getPaddingRight();
+
+ final int childCount = parent.getChildCount();
+ //最后一个item不画分割线
+ for (int i = 0; i < childCount - 1; i++) {
+ final View child = parent.getChildAt(i);
+ final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
+ final int top = child.getBottom() + params.bottomMargin;
+ final int bottom = top + mDivider.getIntrinsicHeight();
+ if (inset > 0) {
+ c.drawRect(left, top, right, bottom, paint);
+ mDivider.setBounds(left + inset, top, right - inset, bottom);
+ } else {
+ mDivider.setBounds(left, top, right, bottom);
+ }
+ mDivider.draw(c);
+ }
+ }
+
+ private void drawHorizontal(Canvas c, RecyclerView parent) {
+ final int top = parent.getPaddingTop();
+ final int bottom = parent.getHeight() - parent.getPaddingBottom();
+
+ final int childCount = parent.getChildCount();
+ for (int i = 0; i < childCount - 1; i++) {
+ final View child = parent.getChildAt(i);
+ final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
+ final int left = child.getRight() + params.rightMargin;
+ final int right = left + mDivider.getIntrinsicHeight();
+ mDivider.setBounds(left, top, right, bottom);
+ mDivider.draw(c);
+ }
+ }
+
+ //由于Divider也有宽高,每一个Item需要向下或者向右偏移
+ @Override
+ public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
+ if (mOrientation == VERTICAL_LIST) {
+ outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
+ } else {
+ outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
+ }
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/recycleviewswipe/RecycleViewDivider.java b/mylibrary/src/main/java/com/dahe/mylibrary/recycleviewswipe/RecycleViewDivider.java
new file mode 100644
index 0000000..77bb594
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/recycleviewswipe/RecycleViewDivider.java
@@ -0,0 +1,156 @@
+package com.dahe.mylibrary.recycleviewswipe;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+
+import androidx.core.content.ContextCompat;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+public class RecycleViewDivider extends RecyclerView.ItemDecoration {
+
+ private Paint mPaint;
+ //分割线
+ private Drawable mDivider;
+ //分割线高度,默认是1px
+ private int mDividerHeight = 1;
+ //列表的方向:LinearLayoutManager.VERTICAL或LinearLayoutManager.HORIZONTAL
+ private int mOrientation;
+
+ private static final int[] ATTRS = new int[]{android.R.attr.listDivider};
+
+ /**
+ *
+ * 默认分割线:高度为2px,颜色为灰色
+ * 获取属性值,
+ *
+ * @param context
+ * @param orientation 列表方向
+ */
+
+ public RecycleViewDivider(Context context, int orientation){
+ if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) {
+ throw new IllegalArgumentException("请输入正确的参数!");
+ }
+ mOrientation = orientation;
+ final TypedArray array = context.obtainStyledAttributes(ATTRS);
+ mDivider = array.getDrawable(0);
+ array.recycle();
+ mDividerHeight = mDivider.getIntrinsicHeight();
+ }
+
+ /**
+ * 自定义分割线
+ *
+ * @param context
+ * @param orientation 列表方向
+ * @param drawableId 分割线图片
+ */
+ public RecycleViewDivider(Context context, int orientation, int drawableId) {
+ if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) {
+ throw new IllegalArgumentException("请输入正确的参数!");
+ }
+ mOrientation = orientation;
+
+ mDivider = ContextCompat.getDrawable(context, drawableId);
+ mDividerHeight = mDivider.getIntrinsicHeight();
+ }
+
+ /**
+ * 自定义分割线
+ *
+ * @param orientation 列表方向
+ * @param dividerHeight 分割线高度
+ * @param dividerColor 分割线颜色
+ */
+ public RecycleViewDivider(int orientation, int dividerHeight, int dividerColor) {
+
+ if (orientation != LinearLayoutManager.VERTICAL && orientation != LinearLayoutManager.HORIZONTAL) {
+ throw new IllegalArgumentException("请输入正确的参数!");
+ }
+ mOrientation = orientation;
+
+ mDividerHeight = dividerHeight;
+
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mPaint.setColor(dividerColor);
+ mPaint.setStyle(Paint.Style.FILL);
+
+ }
+
+ //获取分割线尺寸
+ @Override
+ public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
+
+ if (mOrientation == LinearLayoutManager.VERTICAL) {
+ outRect.set(0, 0, 0, mDividerHeight);
+ } else {
+ outRect.set(0, 0, mDividerHeight, 0);
+ }
+ }
+
+ @Override
+ public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
+ super.onDraw(c, parent, state);
+ if(mOrientation==LinearLayoutManager.VERTICAL){
+ drawVerticalLine(c,parent);
+ }else{
+ drawHorizontalLine(c,parent);
+ }
+ }
+
+ //为横方向item, 画分割线
+ private void drawHorizontalLine(Canvas canvas, RecyclerView parent) {
+
+ final int top = parent.getPaddingTop();
+ final int bottom = parent.getMeasuredHeight() - parent.getPaddingBottom();
+ final int childSize = parent.getChildCount();
+ for (int i = 0; i < childSize - 1; i++) {
+ if ((i+1) % 3 != 0) {
+ final View child = parent.getChildAt(i);
+ RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
+ final int left = child.getRight() + layoutParams.rightMargin;
+ final int right = left + mDividerHeight;
+ if (mDivider != null) {
+ mDivider.setBounds(left, top, right, bottom);
+ mDivider.draw(canvas);
+ }
+ if (mPaint != null) {
+ canvas.drawRect(left, top, right, bottom, mPaint);
+ }
+ }
+ }
+ }
+
+ //为竖方向item, 画分割线
+ private void drawVerticalLine(Canvas canvas, RecyclerView parent) {
+
+ final int left = parent.getPaddingLeft();
+ final int right = parent.getMeasuredWidth() - parent.getPaddingRight();
+ final int childSize = parent.getChildCount();
+ for (int i = 0; i < childSize; i++) {
+ if (i < childSize -1) {
+ final View child = parent.getChildAt(i);
+ RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) child.getLayoutParams();
+ final int top = child.getBottom() + layoutParams.bottomMargin;
+ final int bottom = top + mDividerHeight;
+
+ if (mDivider != null) {
+ mDivider.setBounds(left, top, right, bottom);
+ mDivider.draw(canvas);
+ }
+
+ if (mPaint != null) {
+ canvas.drawRect(left, top, right, bottom, mPaint);
+ }
+
+ }
+ }
+ }
+}
+
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/ActivityUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ActivityUtils.java
new file mode 100644
index 0000000..af47200
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ActivityUtils.java
@@ -0,0 +1,330 @@
+package com.dahe.mylibrary.utils;
+
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+
+
+import com.dahe.mylibrary.CommonBaseLibrary;
+
+import java.util.List;
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/09/23
+ * desc : Activity相关工具类
+ *
+ */
+public class ActivityUtils {
+
+ public ActivityUtils() {
+ throw new UnsupportedOperationException("u can't instantiate me...");
+ }
+
+ /**
+ * 启动Activity
+ *
+ * @param context
+ * @param clz
+ * @param bundle
+ */
+ public static void startActivity(@NonNull Context context, @NonNull Class> clz, Bundle bundle) {
+ Intent intent = new Intent(context, clz);
+ if (null != bundle) intent.putExtras(bundle);
+ context.startActivity(intent);
+ }
+
+ /**
+ * 启动Activity
+ *
+ * @param context
+ * @param clz
+ * @param bundle
+ */
+ public static void startPushActivity(@NonNull Context context, @NonNull Class> clz, Bundle bundle) {
+ Intent intent = new Intent(context, clz);
+ if (null != bundle){
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtras(bundle);
+ }
+ context.startActivity(intent);
+ }
+
+ /**
+ * 启动Activity
+ *
+ * @param context
+ * @param clz
+ */
+ public static void startActivity(@NonNull Context context, @NonNull Class> clz) {
+ startActivity(context, clz, null);
+ }
+
+ /**
+ * 启动Activity
+ *
+ * @param activity
+ * @param clz
+ * @param bundle
+ */
+ public static void startActivityForResult(@NonNull Activity activity, @NonNull Class> clz, Bundle bundle, int requestCode) {
+ Intent intent = new Intent(activity, clz);
+ if (null != bundle) intent.putExtras(bundle);
+ activity.startActivityForResult(intent, requestCode);
+ }
+
+ /**
+ * 启动Activity
+ *
+ * @param activity
+ * @param clz
+ */
+ public static void startActivityForResult(@NonNull Activity activity, @NonNull Class> clz, int requestCode) {
+ startActivityForResult(activity, clz, null, requestCode);
+ }
+
+
+// /**
+// * 跳转登录界面
+// *
+// * @param context
+// * @param finishOthers 是否结束其他的activity true结束 false 不结束
+// */
+// public static void openLoginActivity(@NonNull Context context, boolean finishOthers) {
+// Intent intent = new Intent(context, LoginMainActivity.class);
+// Bundle bundle = new Bundle();
+// bundle.putBoolean("finishOthers", finishOthers);
+// intent.putExtras(bundle);
+// context.startActivity(intent);
+// }
+
+// /**
+// * 启动前必须登录Activity
+// *
+// * @param context
+// * @param clz
+// */
+// public static void startActivityByLogin(@NonNull Context context, @NonNull Class> clz) {
+// startActivityByLogin(context, clz, null);
+// }
+
+
+ /**
+ * 回到桌面
+ */
+ public static void startHomeActivity(Context context) {
+ Intent homeIntent = new Intent(Intent.ACTION_MAIN);
+ homeIntent.addCategory(Intent.CATEGORY_HOME);
+ context.startActivity(homeIntent);
+ }
+
+ /**
+ * 获取Activity栈链表
+ *
+ * @return Activity栈链表
+ */
+ public static List getActivityList() {
+ return CommonBaseLibrary.activityList;
+ }
+
+ /**
+ * 获取启动项Activity
+ *
+ * @param packageName 包名
+ * @return 启动项Activity
+ */
+ public static String getLauncherActivity(@NonNull final String packageName) {
+ Intent intent = new Intent(Intent.ACTION_MAIN, null);
+ intent.addCategory(Intent.CATEGORY_LAUNCHER);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager();
+ List info = pm.queryIntentActivities(intent, 0);
+ for (ResolveInfo aInfo : info) {
+ if (aInfo.activityInfo.packageName.equals(packageName)) {
+ return aInfo.activityInfo.name;
+ }
+ }
+ return "no " + packageName;
+ }
+
+ /**
+ * 获取栈顶Activity
+ *
+ * @return 栈顶Activity
+ */
+ public static Activity getTopActivity() {
+ if (CommonBaseLibrary.topActivity != null) {
+ Activity activity = CommonBaseLibrary.topActivity.get();
+ if (activity != null) {
+ return activity;
+ }
+ }
+ List activities = CommonBaseLibrary.activityList;
+ int size = activities.size();
+ return size > 0 ? activities.get(size - 1) : null;
+ }
+
+ /**
+ * 判断Activity是否存在栈中
+ *
+ * @param activity activity
+ * @return {@code true}: 存在 {@code false}: 不存在
+ */
+ public static boolean isActivityExistsInStack(@NonNull final Activity activity) {
+ List activities = CommonBaseLibrary.activityList;
+ for (Activity aActivity : activities) {
+ if (aActivity.equals(activity)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 判断Activity是否存在栈中
+ *
+ * @param clz activity类
+ * @return {@code true}: 存在 {@code false}: 不存在
+ */
+ public static boolean isActivityExistsInStack(@NonNull final Class> clz) {
+ List activities = CommonBaseLibrary.activityList;
+ for (Activity aActivity : activities) {
+ if (aActivity.getClass().equals(clz)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 结束Activity
+ *
+ * @param activity activity
+ */
+ public static void finishActivity(@NonNull final Activity activity) {
+ activity.finish();
+ }
+
+
+ /**
+ * 结束Activity
+ *
+ * @param clz activity类
+ */
+ public static void finishActivity(@NonNull final Class> clz) {
+ List activities = CommonBaseLibrary.activityList;
+ for (Activity activity : activities) {
+ if (activity.getClass().equals(clz)) {
+ activity.finish();
+ }
+ }
+ }
+
+ /**
+ * 结束到指定Activity
+ *
+ * @param activity activity
+ * @param isIncludeSelf 是否结束该activity自己
+ */
+ public static boolean finishToActivity(@NonNull final Activity activity,
+ final boolean isIncludeSelf) {
+ List activities = CommonBaseLibrary.activityList;
+ for (int i = activities.size() - 1; i >= 0; --i) {
+ Activity aActivity = activities.get(i);
+ if (aActivity.equals(activity)) {
+ if (isIncludeSelf) {
+ finishActivity(aActivity);
+ }
+ return true;
+ }
+ finishActivity(aActivity);
+ }
+ return false;
+ }
+
+ /**
+ * 结束到指定Activity
+ *
+ * @param isIncludeSelf 是否结束该activity自己
+ */
+ public static boolean finishToActivity(@NonNull final Class> clz,
+ final boolean isIncludeSelf) {
+ List activities = CommonBaseLibrary.activityList;
+ for (int i = activities.size() - 1; i >= 0; --i) {
+ Activity aActivity = activities.get(i);
+ if (aActivity.getClass().equals(clz)) {
+ if (isIncludeSelf) {
+ finishActivity(aActivity);
+ }
+ return true;
+ }else{
+ finishActivity(aActivity);
+ }
+// finishActivity(aActivity);
+ }
+ return false;
+ }
+
+ /**
+ * 结束除最新之外的同类型Activity
+ * 也就是让栈中最多只剩下一种类型的Activity
+ *
+ * @param clz activity类
+ */
+ public static void finishOtherActivitiesExceptNewest(@NonNull final Class> clz) {
+ List activities = CommonBaseLibrary.activityList;
+ boolean flag = false;
+ for (int i = activities.size() - 1; i >= 0; i--) {
+ Activity activity = activities.get(i);
+ if (activity.getClass().equals(clz)) {
+ if (flag) {
+ finishActivity(activity);
+ } else {
+ flag = true;
+ }
+ } else {
+ finishActivity(activity);
+ }
+ }
+ }
+
+ /**
+ * 清除除本activity之外所有的activity
+ *
+ * @param clz 本activity的类名
+ */
+ public static void finishOtherActivities(@NonNull final Class> clz) {
+ List activities = CommonBaseLibrary.activityList;
+ for (Activity activity : activities) {
+ if (!activity.getClass().equals(clz)) {
+ finishActivity(activity);
+ }
+ }
+ }
+
+ /**
+ * 结束所有activity
+ */
+ public static void finishAllActivities() {
+ List activityList = CommonBaseLibrary.activityList;
+ for (int i = activityList.size() - 1; i >= 0; --i) {// 从栈顶开始移除
+ Activity activity = activityList.get(i);
+ activity.finish();// 在onActivityDestroyed发生remove
+ }
+ }
+
+ private static Context getActivityOrApp() {
+ Activity topActivity = getTopActivity();
+ return topActivity == null ? CommonBaseLibrary.getApplication() : topActivity;
+ }
+
+
+}
\ No newline at end of file
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/AppUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/AppUtils.java
new file mode 100644
index 0000000..e556926
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/AppUtils.java
@@ -0,0 +1,1062 @@
+package com.dahe.mylibrary.utils;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.app.usage.UsageStats;
+import android.app.usage.UsageStatsManager;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.Signature;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Build;
+import android.provider.Settings;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.core.content.FileProvider;
+
+
+import com.dahe.mylibrary.CommonBaseLibrary;
+
+import java.io.File;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/08/02
+ * desc : utils about app
+ *
+ * registerAppStatusChangedListener : 注册 App 前后台切换监听器
+ * unregisterAppStatusChangedListener: 注销 App 前后台切换监听器
+ * installApp : 安装 App(支持 8.0)
+ * installAppSilent : 静默安装 App
+ * uninstallApp : 卸载 App
+ * uninstallAppSilent : 静默卸载 App
+ * isAppInstalled : 判断 App 是否安装
+ * isAppRoot : 判断 App 是否有 root 权限
+ * isAppDebug : 判断 App 是否是 Debug 版本
+ * isAppSystem : 判断 App 是否是系统应用
+ * isAppForeground : 判断 App 是否处于前台
+ * launchApp : 打开 App
+ * relaunchApp : 重启 App
+ * launchAppDetailsSettings : 打开 App 具体设置
+ * exitApp : 关闭应用
+ * getAppIcon : 获取 App 图标
+ * getAppPackageName : 获取 App 包名
+ * getAppName : 获取 App 名称
+ * getAppPath : 获取 App 路径
+ * getAppVersionName : 获取 App 版本号
+ * getAppVersionCode : 获取 App 版本码
+ * getAppSignature : 获取 App 签名
+ * getAppSignatureSHA1 : 获取应用签名的的 SHA1 值
+ * getAppSignatureSHA256 : 获取应用签名的的 SHA256 值
+ * getAppSignatureMD5 : 获取应用签名的的 MD5 值
+ * getAppInfo : 获取 App 信息
+ * getAppsInfo : 获取所有已安装 App 信息
+ * getApkInfo : 获取 Apk 信息
+ */
+public final class AppUtils {
+
+ private AppUtils() {
+ throw new UnsupportedOperationException("u can't instantiate me...");
+ }
+
+ /**
+ * Install the app.
+ * Target APIs greater than 25 must hold
+ * {@code }
+ *
+ * @param filePath The path of file.
+ */
+ public static void installApp(final String filePath) {
+ installApp(getFileByPath(filePath));
+ }
+
+ /**
+ * Install the app.
+ * Target APIs greater than 25 must hold
+ * {@code }
+ *
+ * @param file The file.
+ */
+ public static void installApp(final File file) {
+ if (!isFileExists(file)) return;
+ CommonBaseLibrary.getApplication().startActivity(getInstallAppIntent(file, true));
+ }
+
+ /**
+ * Install the app.
+ * Target APIs greater than 25 must hold
+ * {@code }
+ *
+ * @param activity The activity.
+ * @param filePath The path of file.
+ * @param requestCode If >= 0, this code will be returned in
+ * onActivityResult() when the activity exits.
+ */
+ public static void installApp(final Activity activity,
+ final String filePath,
+ final int requestCode) {
+ installApp(activity, getFileByPath(filePath), requestCode);
+ }
+
+ /**
+ * Install the app.
+ * Target APIs greater than 25 must hold
+ * {@code }
+ *
+ * @param activity The activity.
+ * @param file The file.
+ * @param requestCode If >= 0, this code will be returned in
+ * onActivityResult() when the activity exits.
+ */
+ public static void installApp(final Activity activity,
+ final File file,
+ final int requestCode) {
+ if (!isFileExists(file)) return;
+ activity.startActivityForResult(getInstallAppIntent(file), requestCode);
+ }
+
+ /**
+ * Install the app silently.
+ * Without root permission must hold
+ * {@code android:sharedUserId="android.uid.shell"} and
+ * {@code }
+ *
+ * @param filePath The path of file.
+ * @return {@code true}: success {@code false}: fail
+ */
+ public static boolean installAppSilent(final String filePath) {
+ return installAppSilent(getFileByPath(filePath), null);
+ }
+
+ /**
+ * Install the app silently.
+ * Without root permission must hold
+ * {@code android:sharedUserId="android.uid.shell"} and
+ * {@code }
+ *
+ * @param file The file.
+ * @return {@code true}: success {@code false}: fail
+ */
+ public static boolean installAppSilent(final File file) {
+ return installAppSilent(file, null);
+ }
+
+
+ /**
+ * Install the app silently.
+ * Without root permission must hold
+ * {@code android:sharedUserId="android.uid.shell"} and
+ * {@code }
+ *
+ * @param filePath The path of file.
+ * @param params The params of installation(e.g.,-r, -s).
+ * @return {@code true}: success {@code false}: fail
+ */
+ public static boolean installAppSilent(final String filePath, final String params) {
+ return installAppSilent(getFileByPath(filePath), params);
+ }
+
+ /**
+ * Install the app silently.
+ * Without root permission must hold
+ * {@code android:sharedUserId="android.uid.shell"} and
+ * {@code }
+ *
+ * @param file The file.
+ * @param params The params of installation(e.g.,-r, -s).
+ * @return {@code true}: success {@code false}: fail
+ */
+ public static boolean installAppSilent(final File file, final String params) {
+ return installAppSilent(file, params, isDeviceRooted());
+ }
+
+ /**
+ * Install the app silently.
+ * Without root permission must hold
+ * {@code android:sharedUserId="android.uid.shell"} and
+ * {@code }
+ *
+ * @param file The file.
+ * @param params The params of installation(e.g.,-r, -s).
+ * @param isRooted True to use root, false otherwise.
+ * @return {@code true}: success {@code false}: fail
+ */
+ public static boolean installAppSilent(final File file,
+ final String params,
+ final boolean isRooted) {
+ if (!isFileExists(file)) return false;
+ String filePath = '"' + file.getAbsolutePath() + '"';
+ String command = "LD_LIBRARY_PATH=/vendor/lib*:/system/lib* pm install " +
+ (params == null ? "" : params + " ")
+ + filePath;
+ ShellUtils.CommandResult commandResult = ShellUtils.execCmd(command, isRooted);
+ if (commandResult.successMsg != null
+ && commandResult.successMsg.toLowerCase().contains("success")) {
+ return true;
+ } else {
+ Log.e("AppUtils", "installAppSilent successMsg: " + commandResult.successMsg +
+ ", errorMsg: " + commandResult.errorMsg);
+ return false;
+ }
+ }
+
+ /**
+ * Uninstall the app.
+ *
+ * @param packageName The name of the package.
+ */
+ public static void uninstallApp(final String packageName) {
+ if (isSpace(packageName)) return;
+ CommonBaseLibrary.getApplication().startActivity(getUninstallAppIntent(packageName, true));
+ }
+
+ /**
+ * Uninstall the app.
+ *
+ * @param activity The activity.
+ * @param packageName The name of the package.
+ * @param requestCode If >= 0, this code will be returned in
+ * onActivityResult() when the activity exits.
+ */
+ public static void uninstallApp(final Activity activity,
+ final String packageName,
+ final int requestCode) {
+ if (isSpace(packageName)) return;
+ activity.startActivityForResult(getUninstallAppIntent(packageName), requestCode);
+ }
+
+ /**
+ * Uninstall the app silently.
+ * Without root permission must hold
+ * {@code android:sharedUserId="android.uid.shell"} and
+ * {@code }
+ *
+ * @param packageName The name of the package.
+ * @return {@code true}: success {@code false}: fail
+ */
+ public static boolean uninstallAppSilent(final String packageName) {
+ return uninstallAppSilent(packageName, false);
+ }
+
+ /**
+ * Uninstall the app silently.
+ * Without root permission must hold
+ * {@code android:sharedUserId="android.uid.shell"} and
+ * {@code }
+ *
+ * @param packageName The name of the package.
+ * @param isKeepData Is keep the data.
+ * @return {@code true}: success {@code false}: fail
+ */
+ public static boolean uninstallAppSilent(final String packageName, final boolean isKeepData) {
+ return uninstallAppSilent(packageName, isKeepData, isDeviceRooted());
+ }
+
+ /**
+ * Uninstall the app silently.
+ * Without root permission must hold
+ * {@code android:sharedUserId="android.uid.shell"} and
+ * {@code }
+ *
+ * @param packageName The name of the package.
+ * @param isKeepData Is keep the data.
+ * @param isRooted True to use root, false otherwise.
+ * @return {@code true}: success {@code false}: fail
+ */
+ public static boolean uninstallAppSilent(final String packageName,
+ final boolean isKeepData,
+ final boolean isRooted) {
+ if (isSpace(packageName)) return false;
+ String command = "LD_LIBRARY_PATH=/vendor/lib*:/system/lib* pm uninstall "
+ + (isKeepData ? "-k " : "")
+ + packageName;
+ ShellUtils.CommandResult commandResult = ShellUtils.execCmd(command, isRooted);
+ if (commandResult.successMsg != null
+ && commandResult.successMsg.toLowerCase().contains("success")) {
+ return true;
+ } else {
+ Log.e("AppUtils", "uninstallAppSilent successMsg: " + commandResult.successMsg +
+ ", errorMsg: " + commandResult.errorMsg);
+ return false;
+ }
+ }
+
+ /**
+ * Return whether the app is installed.
+ *
+ * @param packageName The name of the package.
+ * @return {@code true}: yes {@code false}: no
+ */
+ public static boolean isAppInstalled(@NonNull final String packageName) {
+ PackageManager packageManager = CommonBaseLibrary.getApplication().getPackageManager();
+ try {
+ return packageManager.getApplicationInfo(packageName, 0) != null;
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * Return whether the application with root permission.
+ *
+ * @return {@code true}: yes {@code false}: no
+ */
+ public static boolean isAppRoot() {
+ ShellUtils.CommandResult result = ShellUtils.execCmd("echo root", true);
+ if (result.result == 0) return true;
+ if (result.errorMsg != null) {
+ Log.d("AppUtils", "isAppRoot() called" + result.errorMsg);
+ }
+ return false;
+ }
+
+ /**
+ * Return whether it is a debug application.
+ *
+ * @return {@code true}: yes {@code false}: no
+ */
+ public static boolean isAppDebug() {
+ return isAppDebug(CommonBaseLibrary.getApplication().getPackageName());
+ }
+
+ /**
+ * Return whether it is a debug application.
+ *
+ * @param packageName The name of the package.
+ * @return {@code true}: yes {@code false}: no
+ */
+ public static boolean isAppDebug(final String packageName) {
+ if (isSpace(packageName)) return false;
+ try {
+ PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager();
+ ApplicationInfo ai = pm.getApplicationInfo(packageName, 0);
+ return ai != null && (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * Return whether it is a system application.
+ *
+ * @return {@code true}: yes {@code false}: no
+ */
+ public static boolean isAppSystem() {
+ return isAppSystem(CommonBaseLibrary.getApplication().getPackageName());
+ }
+
+ /**
+ * Return whether it is a system application.
+ *
+ * @param packageName The name of the package.
+ * @return {@code true}: yes {@code false}: no
+ */
+ public static boolean isAppSystem(final String packageName) {
+ if (isSpace(packageName)) return false;
+ try {
+ PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager();
+ ApplicationInfo ai = pm.getApplicationInfo(packageName, 0);
+ return ai != null && (ai.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+
+ /**
+ * Return whether application is foreground.
+ * Target APIs greater than 21 must hold
+ * {@code }
+ *
+ * @param packageName The name of the package.
+ * @return {@code true}: yes {@code false}: no
+ */
+ public static boolean isAppForeground(@NonNull final String packageName) {
+ return !isSpace(packageName) && packageName.equals(getForegroundProcessName());
+ }
+
+ /**
+ * Launch the application.
+ *
+ * @param packageName The name of the package.
+ */
+ public static void launchApp(final String packageName) {
+ if (isSpace(packageName)) return;
+ CommonBaseLibrary.getApplication().startActivity(getLaunchAppIntent(packageName, true));
+ }
+
+ /**
+ * Launch the application.
+ *
+ * @param activity The activity.
+ * @param packageName The name of the package.
+ * @param requestCode If >= 0, this code will be returned in
+ * onActivityResult() when the activity exits.
+ */
+ public static void launchApp(final Activity activity,
+ final String packageName,
+ final int requestCode) {
+ if (isSpace(packageName)) return;
+ activity.startActivityForResult(getLaunchAppIntent(packageName), requestCode);
+ }
+
+ /**
+ * Relaunch the application.
+ */
+ public static void relaunchApp() {
+ relaunchApp(false);
+ }
+
+ /**
+ * Relaunch the application.
+ *
+ * @param isKillProcess True to kill the process, false otherwise.
+ */
+ public static void relaunchApp(final boolean isKillProcess) {
+ PackageManager packageManager = CommonBaseLibrary.getApplication().getPackageManager();
+ Intent intent = packageManager.getLaunchIntentForPackage(CommonBaseLibrary.getApplication().getPackageName());
+ if (intent == null) return;
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ CommonBaseLibrary.getApplication().startActivity(intent);
+ if (!isKillProcess) return;
+ android.os.Process.killProcess(android.os.Process.myPid());
+ System.exit(0);
+ }
+
+ /**
+ * Launch the application's details settings.
+ */
+ public static void launchAppDetailsSettings() {
+ launchAppDetailsSettings(CommonBaseLibrary.getApplication().getPackageName());
+ }
+
+ /**
+ * Launch the application's details settings.
+ *
+ * @param packageName The name of the package.
+ */
+ public static void launchAppDetailsSettings(final String packageName) {
+ if (isSpace(packageName)) return;
+ Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
+ intent.setData(Uri.parse("package:" + packageName));
+ CommonBaseLibrary.getApplication().startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ }
+
+
+ /**
+ * Return the application's icon.
+ *
+ * @return the application's icon
+ */
+ public static Drawable getAppIcon() {
+ return getAppIcon(CommonBaseLibrary.getApplication().getPackageName());
+ }
+
+ /**
+ * Return the application's icon.
+ *
+ * @param packageName The name of the package.
+ * @return the application's icon
+ */
+ public static Drawable getAppIcon(final String packageName) {
+ if (isSpace(packageName)) return null;
+ try {
+ PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager();
+ PackageInfo pi = pm.getPackageInfo(packageName, 0);
+ return pi == null ? null : pi.applicationInfo.loadIcon(pm);
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Return the application's package name.
+ *
+ * @return the application's package name
+ */
+ public static String getAppPackageName() {
+ return CommonBaseLibrary.getApplication().getPackageName();
+ }
+
+ /**
+ * Return the application's name.
+ *
+ * @return the application's name
+ */
+ public static String getAppName() {
+ return getAppName(CommonBaseLibrary.getApplication().getPackageName());
+ }
+
+ /**
+ * Return the application's name.
+ *
+ * @param packageName The name of the package.
+ * @return the application's name
+ */
+ public static String getAppName(final String packageName) {
+ if (isSpace(packageName)) return "";
+ try {
+ PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager();
+ PackageInfo pi = pm.getPackageInfo(packageName, 0);
+ return pi == null ? null : pi.applicationInfo.loadLabel(pm).toString();
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ return "";
+ }
+ }
+
+ /**
+ * Return the application's path.
+ *
+ * @return the application's path
+ */
+ public static String getAppPath() {
+ return getAppPath(CommonBaseLibrary.getApplication().getPackageName());
+ }
+
+ /**
+ * Return the application's path.
+ *
+ * @param packageName The name of the package.
+ * @return the application's path
+ */
+ public static String getAppPath(final String packageName) {
+ if (isSpace(packageName)) return "";
+ try {
+ PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager();
+ PackageInfo pi = pm.getPackageInfo(packageName, 0);
+ return pi == null ? null : pi.applicationInfo.sourceDir;
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ return "";
+ }
+ }
+
+ /**
+ * Return the application's version name.
+ *
+ * @return the application's version name
+ */
+ public static String getAppVersionName() {
+ return getAppVersionName(CommonBaseLibrary.getApplication().getPackageName());
+ }
+
+ /**
+ * Return the application's version name.
+ *
+ * @param packageName The name of the package.
+ * @return the application's version name
+ */
+ public static String getAppVersionName(final String packageName) {
+ if (isSpace(packageName)) return "";
+ try {
+ PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager();
+ PackageInfo pi = pm.getPackageInfo(packageName, 0);
+ return pi == null ? null : pi.versionName;
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ return "";
+ }
+ }
+
+ /**
+ * Return the application's version code.
+ *
+ * @return the application's version code
+ */
+ public static int getAppVersionCode() {
+ return getAppVersionCode(CommonBaseLibrary.getApplication().getPackageName());
+ }
+
+ /**
+ * Return the application's version code.
+ *
+ * @param packageName The name of the package.
+ * @return the application's version code
+ */
+ public static int getAppVersionCode(final String packageName) {
+ if (isSpace(packageName)) return -1;
+ try {
+ PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager();
+ PackageInfo pi = pm.getPackageInfo(packageName, 0);
+ return pi == null ? -1 : pi.versionCode;
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ return -1;
+ }
+ }
+
+ /**
+ * Return the application's signature.
+ *
+ * @return the application's signature
+ */
+ public static Signature[] getAppSignature() {
+ return getAppSignature(CommonBaseLibrary.getApplication().getPackageName());
+ }
+
+ /**
+ * Return the application's signature.
+ *
+ * @param packageName The name of the package.
+ * @return the application's signature
+ */
+ public static Signature[] getAppSignature(final String packageName) {
+ if (isSpace(packageName)) return null;
+ try {
+ PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager();
+ @SuppressLint("PackageManagerGetSignatures")
+ PackageInfo pi = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
+ return pi == null ? null : pi.signatures;
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Return the application's signature for SHA1 value.
+ *
+ * @return the application's signature for SHA1 value
+ */
+ public static String getAppSignatureSHA1() {
+ return getAppSignatureSHA1(CommonBaseLibrary.getApplication().getPackageName());
+ }
+
+ /**
+ * Return the application's signature for SHA1 value.
+ *
+ * @param packageName The name of the package.
+ * @return the application's signature for SHA1 value
+ */
+ public static String getAppSignatureSHA1(final String packageName) {
+ return getAppSignatureHash(packageName, "SHA1");
+ }
+
+ /**
+ * Return the application's signature for SHA256 value.
+ *
+ * @return the application's signature for SHA256 value
+ */
+ public static String getAppSignatureSHA256() {
+ return getAppSignatureSHA256(CommonBaseLibrary.getApplication().getPackageName());
+ }
+
+ /**
+ * Return the application's signature for SHA256 value.
+ *
+ * @param packageName The name of the package.
+ * @return the application's signature for SHA256 value
+ */
+ public static String getAppSignatureSHA256(final String packageName) {
+ return getAppSignatureHash(packageName, "SHA256");
+ }
+
+ /**
+ * Return the application's signature for MD5 value.
+ *
+ * @return the application's signature for MD5 value
+ */
+ public static String getAppSignatureMD5() {
+ return getAppSignatureMD5(CommonBaseLibrary.getApplication().getPackageName());
+ }
+
+ /**
+ * Return the application's signature for MD5 value.
+ *
+ * @param packageName The name of the package.
+ * @return the application's signature for MD5 value
+ */
+ public static String getAppSignatureMD5(final String packageName) {
+ return getAppSignatureHash(packageName, "MD5");
+ }
+
+ private static String getAppSignatureHash(final String packageName, final String algorithm) {
+ if (isSpace(packageName)) return "";
+ Signature[] signature = getAppSignature(packageName);
+ if (signature == null || signature.length <= 0) return "";
+ return bytes2HexString(hashTemplate(signature[0].toByteArray(), algorithm))
+ .replaceAll("(?<=[0-9A-F]{2})[0-9A-F]{2}", ":$0");
+ }
+
+ /**
+ * Return the application's information.
+ *
+ * name of package
+ * icon
+ * name
+ * path of package
+ * version name
+ * version code
+ * is system
+ *
+ *
+ * @return the application's information
+ */
+ public static AppInfo getAppInfo() {
+ return getAppInfo(CommonBaseLibrary.getApplication().getPackageName());
+ }
+
+ /**
+ * Return the application's information.
+ *
+ * name of package
+ * icon
+ * name
+ * path of package
+ * version name
+ * version code
+ * is system
+ *
+ *
+ * @param packageName The name of the package.
+ * @return the application's information
+ */
+ public static AppInfo getAppInfo(final String packageName) {
+ try {
+ PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager();
+ PackageInfo pi = pm.getPackageInfo(packageName, 0);
+ return getBean(pm, pi);
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Return the applications' information.
+ *
+ * @return the applications' information
+ */
+ public static List getAppsInfo() {
+ List list = new ArrayList<>();
+ PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager();
+ List installedPackages = pm.getInstalledPackages(0);
+ for (PackageInfo pi : installedPackages) {
+ AppInfo ai = getBean(pm, pi);
+ if (ai == null) continue;
+ list.add(ai);
+ }
+ return list;
+ }
+
+ /**
+ * Return the application's package information.
+ *
+ * @return the application's package information
+ */
+ public static AppInfo getApkInfo(final File apkFile) {
+ if (apkFile == null || !apkFile.isFile() || !apkFile.exists()) return null;
+ return getApkInfo(apkFile.getAbsolutePath());
+ }
+
+ /**
+ * Return the application's package information.
+ *
+ * @return the application's package information
+ */
+ public static AppInfo getApkInfo(final String apkFilePath) {
+ if (isSpace(apkFilePath)) return null;
+ PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager();
+ PackageInfo pi = pm.getPackageArchiveInfo(apkFilePath, 0);
+ ApplicationInfo appInfo = pi.applicationInfo;
+ appInfo.sourceDir = apkFilePath;
+ return getBean(pm, pi);
+ }
+
+ private static AppInfo getBean(final PackageManager pm, final PackageInfo pi) {
+ if (pm == null || pi == null) return null;
+ ApplicationInfo ai = pi.applicationInfo;
+ String packageName = pi.packageName;
+ String name = ai.loadLabel(pm).toString();
+ Drawable icon = ai.loadIcon(pm);
+ String packagePath = ai.sourceDir;
+ String versionName = pi.versionName;
+ int versionCode = pi.versionCode;
+ boolean isSystem = (ApplicationInfo.FLAG_SYSTEM & ai.flags) != 0;
+ return new AppInfo(packageName, name, icon, packagePath, versionName, versionCode, isSystem);
+ }
+
+ /**
+ * The application's information.
+ */
+ public static class AppInfo {
+
+ private String packageName;
+ private String name;
+ private Drawable icon;
+ private String packagePath;
+ private String versionName;
+ private int versionCode;
+ private boolean isSystem;
+
+ public Drawable getIcon() {
+ return icon;
+ }
+
+ public void setIcon(final Drawable icon) {
+ this.icon = icon;
+ }
+
+ public boolean isSystem() {
+ return isSystem;
+ }
+
+ public void setSystem(final boolean isSystem) {
+ this.isSystem = isSystem;
+ }
+
+ public String getPackageName() {
+ return packageName;
+ }
+
+ public void setPackageName(final String packageName) {
+ this.packageName = packageName;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ public String getPackagePath() {
+ return packagePath;
+ }
+
+ public void setPackagePath(final String packagePath) {
+ this.packagePath = packagePath;
+ }
+
+ public int getVersionCode() {
+ return versionCode;
+ }
+
+ public void setVersionCode(final int versionCode) {
+ this.versionCode = versionCode;
+ }
+
+ public String getVersionName() {
+ return versionName;
+ }
+
+ public void setVersionName(final String versionName) {
+ this.versionName = versionName;
+ }
+
+ public AppInfo(String packageName, String name, Drawable icon, String packagePath,
+ String versionName, int versionCode, boolean isSystem) {
+ this.setName(name);
+ this.setIcon(icon);
+ this.setPackageName(packageName);
+ this.setPackagePath(packagePath);
+ this.setVersionName(versionName);
+ this.setVersionCode(versionCode);
+ this.setSystem(isSystem);
+ }
+
+ @Override
+ public String toString() {
+ return "{" +
+ "\n pkg name: " + getPackageName() +
+ "\n app icon: " + getIcon() +
+ "\n app name: " + getName() +
+ "\n app path: " + getPackagePath() +
+ "\n app v name: " + getVersionName() +
+ "\n app v code: " + getVersionCode() +
+ "\n is system: " + isSystem() +
+ "}";
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // other utils methods
+ ///////////////////////////////////////////////////////////////////////////
+
+ private static boolean isFileExists(final File file) {
+ return file != null && file.exists();
+ }
+
+ private static File getFileByPath(final String filePath) {
+ return isSpace(filePath) ? null : new File(filePath);
+ }
+
+ private static boolean isSpace(final String s) {
+ if (s == null) return true;
+ for (int i = 0, len = s.length(); i < len; ++i) {
+ if (!Character.isWhitespace(s.charAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static boolean isDeviceRooted() {
+ String su = "su";
+ String[] locations = {"/system/bin/", "/system/xbin/", "/sbin/", "/system/sd/xbin/",
+ "/system/bin/failsafe/", "/data/local/xbin/", "/data/local/bin/", "/data/local/",
+ "/system/sbin/", "/usr/bin/", "/vendor/bin/"};
+ for (String location : locations) {
+ if (new File(location + su).exists()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private static final char HEX_DIGITS[] =
+ {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+ private static byte[] hashTemplate(final byte[] data, final String algorithm) {
+ if (data == null || data.length <= 0) return null;
+ try {
+ MessageDigest md = MessageDigest.getInstance(algorithm);
+ md.update(data);
+ return md.digest();
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ private static String bytes2HexString(final byte[] bytes) {
+ if (bytes == null) return "";
+ int len = bytes.length;
+ if (len <= 0) return "";
+ char[] ret = new char[len << 1];
+ for (int i = 0, j = 0; i < len; i++) {
+ ret[j++] = HEX_DIGITS[bytes[i] >> 4 & 0x0f];
+ ret[j++] = HEX_DIGITS[bytes[i] & 0x0f];
+ }
+ return new String(ret);
+ }
+
+ private static Intent getInstallAppIntent(final File file) {
+ return getInstallAppIntent(file, false);
+ }
+
+ private static Intent getInstallAppIntent(final File file, final boolean isNewTask) {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ Uri data;
+ String type = "application/vnd.android.package-archive";
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
+ data = Uri.fromFile(file);
+ } else {
+ String authority = CommonBaseLibrary.getApplication().getPackageName() + ".utilcode.provider";
+ data = FileProvider.getUriForFile(CommonBaseLibrary.getApplication(), authority, file);
+ intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ }
+ CommonBaseLibrary.getApplication().grantUriPermission(CommonBaseLibrary.getApplication().getPackageName(), data, Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ intent.setDataAndType(data, type);
+ return isNewTask ? intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) : intent;
+ }
+
+ private static Intent getUninstallAppIntent(final String packageName) {
+ return getUninstallAppIntent(packageName, false);
+ }
+
+ private static Intent getUninstallAppIntent(final String packageName, final boolean isNewTask) {
+ Intent intent = new Intent(Intent.ACTION_DELETE);
+ intent.setData(Uri.parse("package:" + packageName));
+ return isNewTask ? intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) : intent;
+ }
+
+ private static Intent getLaunchAppIntent(final String packageName) {
+ return getLaunchAppIntent(packageName, false);
+ }
+
+ private static Intent getLaunchAppIntent(final String packageName, final boolean isNewTask) {
+ Intent intent = CommonBaseLibrary.getApplication().getPackageManager().getLaunchIntentForPackage(packageName);
+ if (intent == null) return null;
+ return isNewTask ? intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) : intent;
+ }
+
+ private static String getForegroundProcessName() {
+ ActivityManager am =
+ (ActivityManager) CommonBaseLibrary.getApplication().getSystemService(Context.ACTIVITY_SERVICE);
+ //noinspection ConstantConditions
+ List pInfo = am.getRunningAppProcesses();
+ if (pInfo != null && pInfo.size() > 0) {
+ for (ActivityManager.RunningAppProcessInfo aInfo : pInfo) {
+ if (aInfo.importance
+ == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
+ return aInfo.processName;
+ }
+ }
+ }
+ if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
+ PackageManager pm = CommonBaseLibrary.getApplication().getPackageManager();
+ Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS);
+ List list =
+ pm.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
+ Log.i("ProcessUtils", list.toString());
+ if (list.size() <= 0) {
+ Log.i("ProcessUtils",
+ "getForegroundProcessName: noun of access to usage information.");
+ return "";
+ }
+ try {// Access to usage information.
+ ApplicationInfo info =
+ pm.getApplicationInfo(CommonBaseLibrary.getApplication().getPackageName(), 0);
+ AppOpsManager aom =
+ (AppOpsManager) CommonBaseLibrary.getApplication().getSystemService(Context.APP_OPS_SERVICE);
+ //noinspection ConstantConditions
+ if (aom.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
+ info.uid,
+ info.packageName) != AppOpsManager.MODE_ALLOWED) {
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ CommonBaseLibrary.getApplication().startActivity(intent);
+ }
+ if (aom.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS,
+ info.uid,
+ info.packageName) != AppOpsManager.MODE_ALLOWED) {
+ Log.i("ProcessUtils",
+ "getForegroundProcessName: refuse to device usage stats.");
+ return "";
+ }
+ UsageStatsManager usageStatsManager = (UsageStatsManager) CommonBaseLibrary.getApplication()
+ .getSystemService(Context.USAGE_STATS_SERVICE);
+ List usageStatsList = null;
+ if (usageStatsManager != null) {
+ long endTime = System.currentTimeMillis();
+ long beginTime = endTime - 86400000 * 7;
+ usageStatsList = usageStatsManager
+ .queryUsageStats(UsageStatsManager.INTERVAL_BEST,
+ beginTime, endTime);
+ }
+ if (usageStatsList == null || usageStatsList.isEmpty()) return null;
+ UsageStats recentStats = null;
+ for (UsageStats usageStats : usageStatsList) {
+ if (recentStats == null
+ || usageStats.getLastTimeUsed() > recentStats.getLastTimeUsed()) {
+ recentStats = usageStats;
+ }
+ }
+ return recentStats == null ? null : recentStats.getPackageName();
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ }
+ return "";
+ }
+}
\ No newline at end of file
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/BarUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/BarUtils.java
new file mode 100644
index 0000000..30ccf39
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/BarUtils.java
@@ -0,0 +1,678 @@
+package com.dahe.mylibrary.utils;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.Point;
+import android.os.Build;
+import android.util.Log;
+import android.util.TypedValue;
+import android.view.Display;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+import android.view.ViewGroup.MarginLayoutParams;
+import android.view.Window;
+import android.view.WindowManager;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.annotation.RequiresPermission;
+import androidx.drawerlayout.widget.DrawerLayout;
+
+
+import com.dahe.mylibrary.CommonBaseLibrary;
+
+import java.lang.reflect.Method;
+
+import static android.Manifest.permission.EXPAND_STATUS_BAR;
+
+/**
+ * getStatusBarHeight : 获取状态栏高度(px)
+ * setStatusBarVisibility : 设置状态栏是否可见
+ * isStatusBarVisible : 判断状态栏是否可见
+ * setStatusBarLightMode : 设置状态栏是否为浅色模式
+ * addMarginTopEqualStatusBarHeight : 为 view 增加 MarginTop 为状态栏高度
+ * subtractMarginTopEqualStatusBarHeight: 为 view 减少 MarginTop 为状态栏高度
+ * setStatusBarColor : 设置状态栏颜色
+ * setStatusBarColor4Drawer : 为 DrawerLayout 设置状态栏颜色
+ * getActionBarHeight : 获取 ActionBar 高度
+ * setNotificationBarVisibility : 设置通知栏是否可见
+ * getNavBarHeight : 获取导航栏高度
+ * setNavBarVisibility : 设置导航栏是否可见
+ * isNavBarVisible : 判断导航栏是否可见
+ * setNavBarColor : 设置导航栏颜色
+ * getNavBarColor : 获取导航栏颜色
+ * isSupportNavBar : 判断是否支持导航栏
+ */
+public final class BarUtils {
+
+ ///////////////////////////////////////////////////////////////////////////
+ // status bar
+ ///////////////////////////////////////////////////////////////////////////
+
+ private static final String TAG_STATUS_BAR = "TAG_STATUS_BAR";
+ private static final String TAG_OFFSET = "TAG_OFFSET";
+ private static final int KEY_OFFSET = -123;
+
+ private BarUtils() {
+ throw new UnsupportedOperationException("u can't instantiate me...");
+ }
+
+ /**
+ * Return the status bar's height.
+ *
+ * @return the status bar's height
+ */
+ public static int getStatusBarHeight() {
+ Resources resources = Resources.getSystem();
+ int resourceId = resources.getIdentifier("status_bar_height", "dimen", "android");
+ return resources.getDimensionPixelSize(resourceId);
+ }
+
+ /**
+ * Set the status bar's visibility.
+ *
+ * @param activity The activity.
+ * @param isVisible True to set status bar visible, false otherwise.
+ */
+ public static void setStatusBarVisibility(@NonNull final Activity activity,
+ final boolean isVisible) {
+ setStatusBarVisibility(activity.getWindow(), isVisible);
+ }
+
+ /**
+ * Set the status bar's visibility.
+ *
+ * @param window The window.
+ * @param isVisible True to set status bar visible, false otherwise.
+ */
+ public static void setStatusBarVisibility(@NonNull final Window window,
+ final boolean isVisible) {
+ if (isVisible) {
+ window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ showStatusBarView(window);
+ addMarginTopEqualStatusBarHeight(window);
+ } else {
+ window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
+ hideStatusBarView(window);
+ subtractMarginTopEqualStatusBarHeight(window);
+ }
+ }
+
+ /**
+ * Return whether the status bar is visible.
+ *
+ * @param activity The activity.
+ * @return {@code true}: yes {@code false}: no
+ */
+ public static boolean isStatusBarVisible(@NonNull final Activity activity) {
+ int flags = activity.getWindow().getAttributes().flags;
+ return (flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) == 0;
+ }
+
+ /**
+ * Set the status bar's light mode.
+ *
+ * @param activity The activity.
+ * @param isLightMode True to set status bar light mode, false otherwise.
+ */
+ public static void setStatusBarLightMode(@NonNull final Activity activity,
+ final boolean isLightMode) {
+ setStatusBarLightMode(activity.getWindow(), isLightMode);
+ }
+
+ /**
+ * Set the status bar's light mode.
+ *
+ * @param window The window.
+ * @param isLightMode True to set status bar light mode, false otherwise.
+ */
+ public static void setStatusBarLightMode(@NonNull final Window window,
+ final boolean isLightMode) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ View decorView = window.getDecorView();
+ if (decorView != null) {
+ int vis = decorView.getSystemUiVisibility();
+ if (isLightMode) {
+ vis |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+ } else {
+ vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+ }
+ decorView.setSystemUiVisibility(vis);
+ }
+ }
+ }
+
+ /**
+ * Is the status bar light mode.
+ *
+ * @param activity The activity.
+ * @return {@code true}: yes {@code false}: no
+ */
+ public static boolean isStatusBarLightMode(@NonNull final Activity activity) {
+ return isStatusBarLightMode(activity.getWindow());
+ }
+
+ /**
+ * Is the status bar light mode.
+ *
+ * @param window The window.
+ * @return {@code true}: yes {@code false}: no
+ */
+ public static boolean isStatusBarLightMode(@NonNull final Window window) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ View decorView = window.getDecorView();
+ if (decorView != null) {
+ int vis = decorView.getSystemUiVisibility();
+ return (vis & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Add the top margin size equals status bar's height for view.
+ *
+ * @param view The view.
+ */
+ public static void addMarginTopEqualStatusBarHeight(@NonNull View view) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return;
+ view.setTag(TAG_OFFSET);
+ Object haveSetOffset = view.getTag(KEY_OFFSET);
+ if (haveSetOffset != null && (Boolean) haveSetOffset) return;
+ MarginLayoutParams layoutParams = (MarginLayoutParams) view.getLayoutParams();
+ layoutParams.setMargins(layoutParams.leftMargin,
+ layoutParams.topMargin + getStatusBarHeight(),
+ layoutParams.rightMargin,
+ layoutParams.bottomMargin);
+ view.setTag(KEY_OFFSET, true);
+ }
+
+ /**
+ * Subtract the top margin size equals status bar's height for view.
+ *
+ * @param view The view.
+ */
+ public static void subtractMarginTopEqualStatusBarHeight(@NonNull View view) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return;
+ Object haveSetOffset = view.getTag(KEY_OFFSET);
+ if (haveSetOffset == null || !(Boolean) haveSetOffset) return;
+ MarginLayoutParams layoutParams = (MarginLayoutParams) view.getLayoutParams();
+ layoutParams.setMargins(layoutParams.leftMargin,
+ layoutParams.topMargin - getStatusBarHeight(),
+ layoutParams.rightMargin,
+ layoutParams.bottomMargin);
+ view.setTag(KEY_OFFSET, false);
+ }
+
+ private static void addMarginTopEqualStatusBarHeight(final Window window) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return;
+ View withTag = window.getDecorView().findViewWithTag(TAG_OFFSET);
+ if (withTag == null) return;
+ addMarginTopEqualStatusBarHeight(withTag);
+ }
+
+ private static void subtractMarginTopEqualStatusBarHeight(final Window window) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return;
+ View withTag = window.getDecorView().findViewWithTag(TAG_OFFSET);
+ if (withTag == null) return;
+ subtractMarginTopEqualStatusBarHeight(withTag);
+ }
+
+ /**
+ * Set the status bar's color.
+ *
+ * @param activity The activity.
+ * @param color The status bar's color.
+ */
+ public static View setStatusBarColor(@NonNull final Activity activity,
+ @ColorInt final int color) {
+ return setStatusBarColor(activity, color, false);
+ }
+
+ /**
+ * Set the status bar's color.
+ *
+ * @param activity The activity.
+ * @param color The status bar's color.
+ * @param isDecor True to add fake status bar in DecorView,
+ * false to add fake status bar in ContentView.
+ */
+ public static View setStatusBarColor(@NonNull final Activity activity,
+ @ColorInt final int color,
+ final boolean isDecor) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return null;
+ transparentStatusBar(activity);
+ return applyStatusBarColor(activity, color, isDecor);
+ }
+
+ /**
+ * Set the status bar's color.
+ *
+ * @param fakeStatusBar The fake status bar view.
+ * @param color The status bar's color.
+ */
+ public static void setStatusBarColor(@NonNull final View fakeStatusBar,
+ @ColorInt final int color) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return;
+ Activity activity = getActivityByView(fakeStatusBar);
+ if (activity == null) return;
+ transparentStatusBar(activity);
+ fakeStatusBar.setVisibility(View.VISIBLE);
+ ViewGroup.LayoutParams layoutParams = fakeStatusBar.getLayoutParams();
+ layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
+ layoutParams.height = getStatusBarHeight();
+ fakeStatusBar.setBackgroundColor(color);
+ }
+
+ /**
+ * Set the custom status bar.
+ *
+ * @param fakeStatusBar The fake status bar view.
+ */
+ public static void setStatusBarCustom(@NonNull final View fakeStatusBar) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return;
+ Activity activity = getActivityByView(fakeStatusBar);
+ if (activity == null) return;
+ transparentStatusBar(activity);
+ fakeStatusBar.setVisibility(View.VISIBLE);
+ ViewGroup.LayoutParams layoutParams = fakeStatusBar.getLayoutParams();
+ if (layoutParams == null) {
+ layoutParams = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ getStatusBarHeight()
+ );
+ fakeStatusBar.setLayoutParams(layoutParams);
+ } else {
+ layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
+ layoutParams.height = getStatusBarHeight();
+ }
+ }
+
+ /**
+ * Set the status bar's color for DrawerLayout.
+ * DrawLayout must add {@code android:fitsSystemWindows="true"}
+ *
+ * @param drawer The DrawLayout.
+ * @param fakeStatusBar The fake status bar view.
+ * @param color The status bar's color.
+ */
+ public static void setStatusBarColor4Drawer(@NonNull final DrawerLayout drawer,
+ @NonNull final View fakeStatusBar,
+ @ColorInt final int color) {
+ setStatusBarColor4Drawer(drawer, fakeStatusBar, color, false);
+ }
+
+ /**
+ * Set the status bar's color for DrawerLayout.
+ * DrawLayout must add {@code android:fitsSystemWindows="true"}
+ *
+ * @param drawer The DrawLayout.
+ * @param fakeStatusBar The fake status bar view.
+ * @param color The status bar's color.
+ * @param isTop True to set DrawerLayout at the top layer, false otherwise.
+ */
+ public static void setStatusBarColor4Drawer(@NonNull final DrawerLayout drawer,
+ @NonNull final View fakeStatusBar,
+ @ColorInt final int color,
+ final boolean isTop) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return;
+ Activity activity = getActivityByView(fakeStatusBar);
+ if (activity == null) return;
+ transparentStatusBar(activity);
+ drawer.setFitsSystemWindows(false);
+ setStatusBarColor(fakeStatusBar, color);
+ for (int i = 0, count = drawer.getChildCount(); i < count; i++) {
+ drawer.getChildAt(i).setFitsSystemWindows(false);
+ }
+ if (isTop) {
+ hideStatusBarView(activity);
+ } else {
+ setStatusBarColor(activity, color, false);
+ }
+ }
+
+ private static View applyStatusBarColor(final Activity activity,
+ final int color,
+ boolean isDecor) {
+ ViewGroup parent = isDecor ?
+ (ViewGroup) activity.getWindow().getDecorView() :
+ (ViewGroup) activity.findViewById(android.R.id.content);
+ View fakeStatusBarView = parent.findViewWithTag(TAG_STATUS_BAR);
+ if (fakeStatusBarView != null) {
+ if (fakeStatusBarView.getVisibility() == View.GONE) {
+ fakeStatusBarView.setVisibility(View.VISIBLE);
+ }
+ fakeStatusBarView.setBackgroundColor(color);
+ } else {
+ fakeStatusBarView = createStatusBarView(activity, color);
+ parent.addView(fakeStatusBarView);
+ }
+ return fakeStatusBarView;
+ }
+
+ private static void hideStatusBarView(final Activity activity) {
+ hideStatusBarView(activity.getWindow());
+ }
+
+ private static void hideStatusBarView(final Window window) {
+ ViewGroup decorView = (ViewGroup) window.getDecorView();
+ View fakeStatusBarView = decorView.findViewWithTag(TAG_STATUS_BAR);
+ if (fakeStatusBarView == null) return;
+ fakeStatusBarView.setVisibility(View.GONE);
+ }
+
+ private static void showStatusBarView(final Window window) {
+ ViewGroup decorView = (ViewGroup) window.getDecorView();
+ View fakeStatusBarView = decorView.findViewWithTag(TAG_STATUS_BAR);
+ if (fakeStatusBarView == null) return;
+ fakeStatusBarView.setVisibility(View.VISIBLE);
+ }
+
+ private static View createStatusBarView(final Activity activity,
+ final int color) {
+ View statusBarView = new View(activity);
+ statusBarView.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, getStatusBarHeight()));
+ statusBarView.setBackgroundColor(color);
+ statusBarView.setTag(TAG_STATUS_BAR);
+ return statusBarView;
+ }
+
+ private static void transparentStatusBar(final Activity activity) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return;
+ Window window = activity.getWindow();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+ int option = View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
+ window.getDecorView().setSystemUiVisibility(option);
+ window.setStatusBarColor(Color.TRANSPARENT);
+ } else {
+ window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // action bar
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Return the action bar's height.
+ *
+ * @return the action bar's height
+ */
+ public static int getActionBarHeight() {
+ TypedValue tv = new TypedValue();
+ if (CommonBaseLibrary.getApplication().getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
+ return TypedValue.complexToDimensionPixelSize(
+ tv.data, CommonBaseLibrary.getApplication().getResources().getDisplayMetrics()
+ );
+ }
+ return 0;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // notification bar
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Set the notification bar's visibility.
+ * Must hold {@code }
+ *
+ * @param isVisible True to set notification bar visible, false otherwise.
+ */
+ @RequiresPermission(EXPAND_STATUS_BAR)
+ public static void setNotificationBarVisibility(final boolean isVisible) {
+ String methodName;
+ if (isVisible) {
+ methodName = (Build.VERSION.SDK_INT <= 16) ? "expand" : "expandNotificationsPanel";
+ } else {
+ methodName = (Build.VERSION.SDK_INT <= 16) ? "collapse" : "collapsePanels";
+ }
+ invokePanels(methodName);
+ }
+
+ private static void invokePanels(final String methodName) {
+ try {
+ @SuppressLint("WrongConstant")
+ Object service = CommonBaseLibrary.getApplication().getSystemService("statusbar");
+ @SuppressLint("PrivateApi")
+ Class> statusBarManager = Class.forName("android.app.StatusBarManager");
+ Method expand = statusBarManager.getMethod(methodName);
+ expand.invoke(service);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // navigation bar
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Return the navigation bar's height.
+ *
+ * @return the navigation bar's height
+ */
+ public static int getNavBarHeight() {
+ Resources res = Resources.getSystem();
+ int resourceId = res.getIdentifier("navigation_bar_height", "dimen", "android");
+ if (resourceId != 0) {
+ return res.getDimensionPixelSize(resourceId);
+ } else {
+ return 0;
+ }
+ }
+
+ /**
+ * Set the navigation bar's visibility.
+ *
+ * @param activity The activity.
+ * @param isVisible True to set navigation bar visible, false otherwise.
+ */
+ public static void setNavBarVisibility(@NonNull final Activity activity, boolean isVisible) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return;
+ setNavBarVisibility(activity.getWindow(), isVisible);
+
+ }
+
+ /**
+ * Set the navigation bar's visibility.
+ *
+ * @param window The window.
+ * @param isVisible True to set navigation bar visible, false otherwise.
+ */
+ public static void setNavBarVisibility(@NonNull final Window window, boolean isVisible) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return;
+ final ViewGroup decorView = (ViewGroup) window.getDecorView();
+ for (int i = 0, count = decorView.getChildCount(); i < count; i++) {
+ final View child = decorView.getChildAt(i);
+ final int id = child.getId();
+ if (id != View.NO_ID) {
+ String resourceEntryName = CommonBaseLibrary.getApplication()
+ .getResources()
+ .getResourceEntryName(id);
+ if ("navigationBarBackground".equals(resourceEntryName)) {
+ child.setVisibility(isVisible ? View.VISIBLE : View.INVISIBLE);
+ }
+ }
+ }
+ final int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+ if (isVisible) {
+ decorView.setSystemUiVisibility(decorView.getSystemUiVisibility() & ~uiOptions);
+ } else {
+ decorView.setSystemUiVisibility(decorView.getSystemUiVisibility() | uiOptions);
+ }
+ }
+
+ /**
+ * Return whether the navigation bar visible.
+ * Call it in onWindowFocusChanged will get right result.
+ *
+ * @param activity The activity.
+ * @return {@code true}: yes {@code false}: no
+ */
+ public static boolean isNavBarVisible(@NonNull final Activity activity) {
+ return isNavBarVisible(activity.getWindow());
+ }
+
+
+
+ /**
+ * 判断是否显示了导航栏
+ * (说明这里的context 一定要是activity的context 否则类型转换失败)
+ *
+ * @param context
+ * @return
+ */
+// public static boolean isShowNavBar(Context context) {
+// if (null == context) {
+// node_return false;
+// }
+// /**
+// * 获取应用区域高度
+// */
+// Rect outRect1 = new Rect();
+// try {
+// ((Activity) context).getWindow().getDecorView().getWindowVisibleDisplayFrame(outRect1);
+// } catch (ClassCastException e) {
+// e.printStackTrace();
+// node_return false;
+// }
+// int activityHeight = outRect1.height();
+// /**
+// * 获取状态栏高度
+// */
+// int statuBarHeight = WindowDispaly.getStatusBarHeight();
+// /**
+// * 屏幕物理高度 减去 状态栏高度
+// */
+// int remainHeight = WindowDispaly.getRealHeight() - statuBarHeight;
+// /**
+// * 剩余高度跟应用区域高度相等 说明导航栏没有显示 否则相反
+// */
+// if (activityHeight == remainHeight) {
+// node_return false;
+// } else {
+// node_return true;
+// }
+//
+// }
+
+ /**
+ * Return whether the navigation bar visible.
+ * Call it in onWindowFocusChanged will get right result.
+ *
+ * @param window The window.
+ * @return {@code true}: yes {@code false}: no
+ */
+ public static boolean isNavBarVisible(@NonNull final Window window) {
+ boolean isVisible = false;
+ ViewGroup decorView = (ViewGroup) window.getDecorView();
+ for (int i = 0, count = decorView.getChildCount(); i < count; i++) {
+ final View child = decorView.getChildAt(i);
+ final int id = child.getId();
+ if (id != View.NO_ID) {
+ String resourceEntryName = CommonBaseLibrary.getApplication()
+ .getResources()
+ .getResourceEntryName(id);
+ if ("navigationBarBackground".equals(resourceEntryName)
+ && child.getVisibility() == View.VISIBLE) {
+ isVisible = true;
+ break;
+ }
+ }
+ }
+ if (isVisible) {
+ int visibility = decorView.getSystemUiVisibility();
+ isVisible = (visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0;
+ }
+ return isVisible;
+ }
+
+ /**
+ * Set the navigation bar's color.
+ *
+ * @param activity The activity.
+ * @param color The navigation bar's color.
+ */
+ @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
+ public static void setNavBarColor(@NonNull final Activity activity, @ColorInt final int color) {
+ setNavBarColor(activity.getWindow(), color);
+ }
+
+ /**
+ * Set the navigation bar's color.
+ *
+ * @param window The window.
+ * @param color The navigation bar's color.
+ */
+ @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
+ public static void setNavBarColor(@NonNull final Window window, @ColorInt final int color) {
+ window.setNavigationBarColor(color);
+ }
+
+ /**
+ * Return the color of navigation bar.
+ *
+ * @param activity The activity.
+ * @return the color of navigation bar
+ */
+ @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
+ public static int getNavBarColor(@NonNull final Activity activity) {
+ return getNavBarColor(activity.getWindow());
+ }
+
+ /**
+ * Return the color of navigation bar.
+ *
+ * @param window The window.
+ * @return the color of navigation bar
+ */
+ @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
+ public static int getNavBarColor(@NonNull final Window window) {
+ return window.getNavigationBarColor();
+ }
+
+ /**
+ * Return whether the navigation bar visible.
+ *
+ * @return {@code true}: yes {@code false}: no
+ */
+ public static boolean isSupportNavBar() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ WindowManager wm = (WindowManager) CommonBaseLibrary.getApplication().getSystemService(Context.WINDOW_SERVICE);
+ if (wm == null) return false;
+ Display display = wm.getDefaultDisplay();
+ Point size = new Point();
+ Point realSize = new Point();
+ display.getSize(size);
+ display.getRealSize(realSize);
+ return realSize.y != size.y || realSize.x != size.x;
+ }
+ boolean menu = ViewConfiguration.get(CommonBaseLibrary.getApplication()).hasPermanentMenuKey();
+ boolean back = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
+ return !menu && !back;
+ }
+
+ private static Activity getActivityByView(@NonNull final View view) {
+ Context context = view.getContext();
+ while (context instanceof ContextWrapper) {
+ if (context instanceof Activity) {
+ return (Activity) context;
+ }
+ context = ((ContextWrapper) context).getBaseContext();
+ }
+ Log.e("BarUtils", "the view's Context is not an Activity.");
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/Base64Utils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/Base64Utils.java
new file mode 100644
index 0000000..8278fda
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/Base64Utils.java
@@ -0,0 +1,13 @@
+package com.dahe.mylibrary.utils;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.util.Base64;
+
+public class Base64Utils {
+
+ public static Bitmap asdf(String imageBase64){
+ byte[] decodedString = Base64.decode(imageBase64, Base64.DEFAULT);
+ return BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/BaseSPUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/BaseSPUtils.java
new file mode 100644
index 0000000..9450e59
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/BaseSPUtils.java
@@ -0,0 +1,193 @@
+package com.dahe.mylibrary.utils;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Map;
+
+/**
+ * 轻量级数据存储工具类
+ *
+ * @author Administrator
+ */
+public class BaseSPUtils {
+ /**
+ * 保存在手机里面的文件名
+ */
+ public static final String FILE_NAME = "sp_data";
+ public static final String USER_INFO_KEY = "user_info_key";
+ public static final String NET_SERVICE_TEST = "net_service_test";
+ public static final String SEARRH_CACHE = "search_cache";
+ public static final String NAVI_PH_EDIT_CACHE = "navi_ph_edit_cache";
+ public static final String FIRST_OPEN = "first_open";
+ public static final String KEY_PRIVACY_AGREEMENT = "privacy_agreement";
+
+ /**
+ * 保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法
+ *
+ * @param context
+ * @param key
+ * @param object
+ */
+ public static void put(Context context, String key, Object object) {
+ SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sp.edit();
+ if (object instanceof String) {
+ editor.putString(key, (String) object);
+ } else if (object instanceof Integer) {
+ editor.putInt(key, (Integer) object);
+ } else if (object instanceof Boolean) {
+ editor.putBoolean(key, (Boolean) object);
+ } else if (object instanceof Float) {
+ editor.putFloat(key, (Float) object);
+ } else if (object instanceof Long) {
+ editor.putLong(key, (Long) object);
+ } else {
+ editor.putString(key, object.toString());
+ }
+
+ SharedPreferencesCompat.apply(editor);
+ }
+
+ /**
+ * 得到保存数据的方法,我们根据默认值得到保存的数据的具体类型,然后调用相对于的方法获取值
+ *
+ * @param context
+ * @param key
+ * @param defaultObject
+ * @return
+ */
+ public static Object get(Context context, String key, Object defaultObject) {
+ SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
+
+ if (defaultObject instanceof String) {
+ return sp.getString(key, (String) defaultObject);
+ } else if (defaultObject instanceof Integer) {
+ return sp.getInt(key, (Integer) defaultObject);
+ } else if (defaultObject instanceof Boolean) {
+ return sp.getBoolean(key, (Boolean) defaultObject);
+ } else if (defaultObject instanceof Float) {
+ return sp.getFloat(key, (Float) defaultObject);
+ } else if (defaultObject instanceof Long) {
+ return sp.getLong(key, (Long) defaultObject);
+ }
+
+ return null;
+ }
+
+ /**
+ * 移除某个key值已经对应的值
+ *
+ * @param context
+ * @param key
+ */
+ public static void remove(Context context, String key) {
+ SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sp.edit();
+ editor.remove(key);
+ SharedPreferencesCompat.apply(editor);
+ }
+
+ /**
+ * 清除所有数据
+ *
+ * @param context
+ */
+ public static void clear(Context context) {
+ SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sp.edit();
+ editor.clear();
+ SharedPreferencesCompat.apply(editor);
+ }
+
+ /**
+ * 查询某个key是否已经存在
+ *
+ * @param context
+ * @param key
+ * @return
+ */
+ public static boolean contains(Context context, String key) {
+ SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
+ return sp.contains(key);
+ }
+
+ /**
+ * 返回所有的键值对
+ *
+ * @param context
+ * @return
+ */
+ public static Map getAll(Context context) {
+ SharedPreferences sp = context.getSharedPreferences(FILE_NAME, Context.MODE_PRIVATE);
+ return sp.getAll();
+ }
+
+ /**
+ * 创建一个解决SharedPreferencesCompat.apply方法的一个兼容类
+ *
+ * @author zhy
+ */
+ private static class SharedPreferencesCompat {
+ private static final Method sApplyMethod = findApplyMethod();
+
+ /**
+ * 反射查找apply的方法
+ *
+ * @return
+ */
+ @SuppressWarnings(
+ {"unchecked", "rawtypes"})
+ private static Method findApplyMethod() {
+ try {
+ Class clz = SharedPreferences.Editor.class;
+ return clz.getMethod("apply");
+ } catch (NoSuchMethodException e) {
+ }
+
+ return null;
+ }
+
+ /**
+ * 如果找到则使用apply执行,否则使用commit
+ *
+ * @param editor
+ */
+ public static void apply(SharedPreferences.Editor editor) {
+ try {
+ if (sApplyMethod != null) {
+ sApplyMethod.invoke(editor);
+ return;
+ }
+ } catch (IllegalArgumentException e) {
+ } catch (IllegalAccessException e) {
+ } catch (InvocationTargetException e) {
+ }
+ editor.commit();
+ }
+ }
+
+ /*****---------------------------------------------***/
+ /**
+ * 是否含有用户信息
+ *
+ * @param context
+ * @return
+ */
+ public static boolean hasUserInfo(Context context) {
+ return contains(context, USER_INFO_KEY);
+ }
+
+ /**
+ * 清除用户信息
+ *
+ * @param context
+ * @return
+ */
+ public static void cleanUserInfo(Context context) {
+ remove(context, USER_INFO_KEY);
+ }
+
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/BaseUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/BaseUtils.java
new file mode 100644
index 0000000..da2d6de
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/BaseUtils.java
@@ -0,0 +1,243 @@
+package com.dahe.mylibrary.utils;
+
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Build;
+import android.provider.ContactsContract;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+
+import androidx.appcompat.app.AppCompatActivity;
+
+import com.dahe.mylibrary.R;
+import com.shehuan.nicedialog.BaseNiceDialog;
+import com.shehuan.nicedialog.NiceDialog;
+import com.shehuan.nicedialog.ViewConvertListener;
+import com.shehuan.nicedialog.ViewHolder;
+
+import java.util.Locale;
+
+public class BaseUtils {
+ /**
+ * 验证手机格式
+ */
+ public static boolean isMobileNO(String mobiles) {
+ String telRegex = "[1][3456789]\\d{9}";
+ // "[1]"代表第1位为数字1,"[358]"代表第二位可以为3、5、8中的一个,"\\d{9}"代表后面是可以是0~9的数字,有9位。
+ if (TextUtils.isEmpty(mobiles)) return false;
+ else return mobiles.matches(telRegex);
+ }
+
+
+ /**
+ * 获取语言
+ *
+ * @param context
+ * @return
+ */
+ public static int getLanguage(Context context) {
+ Locale curLocale = getLocale(context);
+ String language = curLocale.getLanguage();
+ String country = curLocale.getCountry();
+ if (language.equals(Locale.CHINA.getLanguage())) {
+ //0是简体中文,1是繁体中文
+ return country.equals(Locale.SIMPLIFIED_CHINESE.getCountry()) ? 0 : 1;
+ } else if (language.equals(Locale.ENGLISH.getLanguage())) {
+ //英语
+ return 2;
+ } else if (language.equals("th")) {
+ //泰文
+ return 3;
+ } else if (language.equals(Locale.KOREAN.getLanguage())) {
+ //韩文
+ return 4;
+ } else if (language.equals("vi")) {
+ //越南语
+ return 5;
+ } else if (language.equals(Locale.JAPAN.getLanguage())) {
+ //日语
+ return 6;
+ } else if (language.equals("in")) {
+ //印尼语
+ return 7;
+ } else {
+ return 2;
+ }
+ }
+
+ //获取Locale
+ private static Locale getLocale(Context context) {
+ Locale locale;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
+ locale = context.getResources().getConfiguration().getLocales().get(0);
+ } else {
+ locale = context.getResources().getConfiguration().locale;
+ }
+ return locale;
+ }
+
+
+ /**
+ * 拨打电话(直接拨打电话)
+ * @param phoneNum 电话号码
+ */
+ public static void callPhone(AppCompatActivity context , String phoneNum){
+
+ NiceDialog.init()
+ .setLayoutId(R.layout.dialog_phone)
+ .setConvertListener(new ViewConvertListener() {
+ @Override
+ protected void convertView(ViewHolder viewHolder, BaseNiceDialog baseNiceDialog) {
+ viewHolder.setText(R.id.message, phoneNum);
+ viewHolder.setOnClickListener(R.id.ok, new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Intent intent = new Intent(Intent.ACTION_CALL);
+ Uri data = Uri.parse("tel:" + phoneNum);
+ intent.setData(data);
+ context.startActivity(intent);
+ baseNiceDialog.dismiss();
+ }
+ });
+ viewHolder.setOnClickListener(R.id.cancel, new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ baseNiceDialog.dismiss();
+ }
+ });
+ }
+ })
+ .setWidth(260).show(context.getSupportFragmentManager());
+
+ }
+
+ /**
+ * 获取VersionCode
+ *
+ * @param context
+ * @return
+ */
+ public static String geVersionCode(Context context) {
+ try {
+ PackageInfo packageInfo = context.getPackageManager()
+ .getPackageInfo(context.getPackageName(), 0);
+ return packageInfo.versionName;
+ } catch (Exception e) {
+ return "1.0.0";
+ }
+ }
+
+ /**
+ * 跳转qq
+ *
+ * @param context
+ * @return
+ */
+ public static String goToQQ(Context context, String qqNumber) {
+ try {
+ context.getPackageManager().getApplicationInfo("com.tencent.mobileqq",
+ PackageManager.GET_UNINSTALLED_PACKAGES);
+ context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("mqqwpa://im/chat?chat_type=wpa&uin=" + qqNumber + "&version=1")));
+ } catch (PackageManager.NameNotFoundException e) {
+ return "客服为qq在线,联系客服请先安装qq";
+ }
+ return "";
+ }
+
+ /**
+ * 跳转手机通讯录 选择联系人 并返回联系人信息
+ *
+ * @param context
+ * @param uri
+ * @return
+ */
+ public static String[] getPhoneContacts(Context context, Uri uri) {
+ String[] contact = new String[2];
+ ContentResolver cr = context.getContentResolver();
+ Cursor cursor = cr.query(uri, null, null, null, null);
+ if (cursor != null && cursor.getCount() != 0) {
+ cursor.moveToFirst();
+ int nameFieldColumnIndex = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
+ contact[0] = cursor.getString(nameFieldColumnIndex);
+ String ContactId = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
+ Cursor phone = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
+ ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + ContactId, null, null);
+ if (phone != null && phone.getCount() != 0) {
+ phone.moveToFirst();
+ contact[1] = phone.getString(phone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)).trim().replace(" ", "").toString();
+ } else {
+ contact[1] = "";
+ }
+ phone.close();
+ cursor.close();
+ } else {
+ return null;
+ }
+ return contact;
+ }
+
+ /**
+ * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
+ */
+ public static int dip2px(Context context, float dpValue) {
+ final float scale = context.getResources().getDisplayMetrics().density;
+ return (int) (dpValue * scale + 0.5f);
+ }
+
+ /**
+ * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
+ */
+ public static int px2dip(Context context, float pxValue) {
+ final float scale = context.getResources().getDisplayMetrics().density;
+ return (int) (pxValue / scale + 0.5f);
+ }
+
+ /**
+ * 将sp值转换为px值,保证文字大小不变
+ *
+ * @param spValue
+ * @param spValue (DisplayMetrics类中属性scaledDensity)
+ * @return
+ */
+ public static int sp2px(Context context, float spValue) {
+ final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
+ return (int) (spValue * fontScale + 0.5f);
+ }
+
+ /**
+ * 强制隐藏输入法键盘
+ *
+ * @param context Context
+ * @param view EditText
+ */
+ public static void hideInput(Context context, View view) {
+ InputMethodManager inputMethodManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
+ inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
+ }
+
+ /**
+ * 隐藏软键盘(只适用于Activity,不适用于Fragment)
+ */
+ public static void hideSoftKeyboard(Activity activity) {
+ View view = activity.getCurrentFocus();
+ if (view != null) {
+ InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
+ inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
+ }
+ }
+
+ //view为接受软键盘输入的视图,SHOW_FORCED表示强制显示
+ public static void hideSoftKeyboard(Activity activity, View view) {
+ InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.showSoftInput(view, InputMethodManager.SHOW_FORCED);
+ imm.hideSoftInputFromWindow(view.getWindowToken(), 0); //强制隐藏键盘
+ }
+
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/CNPinyinIndex.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/CNPinyinIndex.java
new file mode 100644
index 0000000..d55d146
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/CNPinyinIndex.java
@@ -0,0 +1,76 @@
+package com.dahe.mylibrary.utils;
+
+import java.io.UnsupportedEncodingException;
+
+public class CNPinyinIndex {
+
+
+ //自动获取汉子的首字母
+ static final int GB_SP_DIFF = 160;
+ // 存放国标一级汉字不同读音的起始区位码
+ static final int[] secPosValueList = {1601, 1637, 1833, 2078, 2274, 2302,
+ 2433, 2594, 2787, 3106, 3212, 3472, 3635, 3722, 3730, 3858, 4027,
+ 4086, 4390, 4558, 4684, 4925, 5249, 5600};
+ // 存放国标一级汉字不同读音的起始区位码对应读音
+ static final char[] firstLetter = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
+ 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'w', 'x',
+ 'y', 'z'};
+
+
+
+ public static String getSpells(String characters) {
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < characters.length(); i++) {
+
+ char ch = characters.charAt(i);
+ if ((ch >> 7) == 0) {
+ // 判断是否为汉字,如果左移7为为0就不是汉字,否则是汉字
+ } else {
+ char spell = getFirstLetter(ch);
+ buffer.append(String.valueOf(spell));
+ }
+ }
+ return buffer.toString();
+ }
+
+ // 获取一个汉字的首字母
+ public static Character getFirstLetter(char ch) {
+
+ byte[] uniCode = null;
+ try {
+ uniCode = String.valueOf(ch).getBytes("GBK");
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ return null;
+ }
+ if (uniCode[0] < 128 && uniCode[0] > 0) { // 非汉字
+ return null;
+ } else {
+ return convert(uniCode);
+ }
+ }
+
+ /**
+ * 获取一个汉字的拼音首字母。 GB码两个字节分别减去160,转换成10进制码组合就可以得到区位码
+ * 例如汉字“你”的GB码是0xC4/0xE3,分别减去0xA0(160)就是0x24/0x43
+ * 0x24转成10进制就是36,0x43是67,那么它的区位码就是3667,在对照表中读音为‘n’
+ */
+ static char convert(byte[] bytes) {
+ char result = '-';
+ int secPosValue = 0;
+ int i;
+ for (i = 0; i < bytes.length; i++) {
+ bytes[i] -= GB_SP_DIFF;
+ }
+ secPosValue = bytes[0] * 100 + bytes[1];
+ for (i = 0; i < 23; i++) {
+ if (secPosValue >= secPosValueList[i]
+ && secPosValue < secPosValueList[i + 1]) {
+ result = firstLetter[i];
+ break;
+ }
+ }
+ return result;
+ }
+
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/ConvertUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ConvertUtils.java
new file mode 100644
index 0000000..a45c471
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ConvertUtils.java
@@ -0,0 +1,645 @@
+package com.dahe.mylibrary.utils;
+
+
+import android.annotation.SuppressLint;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+
+
+import com.dahe.mylibrary.CommonBaseLibrary;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * bytes2Bits, bits2Bytes : bytes 与 bits 互转
+ * bytes2Chars, chars2Bytes : bytes 与 chars 互转
+ * bytes2HexString, hexString2Bytes : bytes 与 hexString 互转
+ * memorySize2Byte, byte2MemorySize : 以 unit 为单位的内存大小与字节数互转
+ * byte2FitMemorySize : 字节数转合适内存大小
+ * timeSpan2Millis, millis2TimeSpan : 以 unit 为单位的时间长度与毫秒时间戳互转
+ * millis2FitTimeSpan : 毫秒时间戳转合适时间长度
+ * input2OutputStream, output2InputStream : inputStream 与 outputStream 互转
+ * inputStream2Bytes, bytes2InputStream : inputStream 与 bytes 互转
+ * outputStream2Bytes, bytes2OutputStream : outputStream 与 bytes 互转
+ * inputStream2String, string2InputStream : inputStream 与 string 按编码互转
+ * outputStream2String, string2OutputStream: outputStream 与 string 按编码互转
+ * bitmap2Bytes, bytes2Bitmap : bitmap 与 bytes 互转
+ * drawable2Bitmap, bitmap2Drawable : drawable 与 bitmap 互转
+ * drawable2Bytes, bytes2Drawable : drawable 与 bytes 互转
+ * view2Bitmap : view 转 Bitmap
+ * dp2px, px2dp : dp 与 px 互转
+ * sp2px, px2sp : sp 与 px 互转
+ */
+public final class ConvertUtils {
+
+ private ConvertUtils() {
+ throw new UnsupportedOperationException("u can't instantiate me...");
+ }
+
+ private static final char hexDigits[] =
+ {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+ /**
+ * Bytes to bits.
+ *
+ * @param bytes The bytes.
+ * @return bits
+ */
+ public static String bytes2Bits(final byte[] bytes) {
+ if (bytes == null || bytes.length == 0) return "";
+ StringBuilder sb = new StringBuilder();
+ for (byte aByte : bytes) {
+ for (int j = 7; j >= 0; --j) {
+ sb.append(((aByte >> j) & 0x01) == 0 ? '0' : '1');
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Bits to bytes.
+ *
+ * @param bits The bits.
+ * @return bytes
+ */
+ public static byte[] bits2Bytes(String bits) {
+ int lenMod = bits.length() % 8;
+ int byteLen = bits.length() / 8;
+ // add "0" until length to 8 times
+ if (lenMod != 0) {
+ for (int i = lenMod; i < 8; i++) {
+ bits = "0" + bits;
+ }
+ byteLen++;
+ }
+ byte[] bytes = new byte[byteLen];
+ for (int i = 0; i < byteLen; ++i) {
+ for (int j = 0; j < 8; ++j) {
+ bytes[i] <<= 1;
+ bytes[i] |= bits.charAt(i * 8 + j) - '0';
+ }
+ }
+ return bytes;
+ }
+
+ /**
+ * Bytes to chars.
+ *
+ * @param bytes The bytes.
+ * @return chars
+ */
+ public static char[] bytes2Chars(final byte[] bytes) {
+ if (bytes == null) return null;
+ int len = bytes.length;
+ if (len <= 0) return null;
+ char[] chars = new char[len];
+ for (int i = 0; i < len; i++) {
+ chars[i] = (char) (bytes[i] & 0xff);
+ }
+ return chars;
+ }
+
+ /**
+ * Chars to bytes.
+ *
+ * @param chars The chars.
+ * @return bytes
+ */
+ public static byte[] chars2Bytes(final char[] chars) {
+ if (chars == null || chars.length <= 0) return null;
+ int len = chars.length;
+ byte[] bytes = new byte[len];
+ for (int i = 0; i < len; i++) {
+ bytes[i] = (byte) (chars[i]);
+ }
+ return bytes;
+ }
+
+ /**
+ * Bytes to hex string.
+ * e.g. bytes2HexString(new byte[] { 0, (byte) 0xa8 }) returns "00A8"
+ *
+ * @param bytes The bytes.
+ * @return hex string
+ */
+ public static String bytes2HexString(final byte[] bytes) {
+ if (bytes == null) return "";
+ int len = bytes.length;
+ if (len <= 0) return "";
+ char[] ret = new char[len << 1];
+ for (int i = 0, j = 0; i < len; i++) {
+ ret[j++] = hexDigits[bytes[i] >> 4 & 0x0f];
+ ret[j++] = hexDigits[bytes[i] & 0x0f];
+ }
+ return new String(ret);
+ }
+
+ /**
+ * Hex string to bytes.
+ * e.g. hexString2Bytes("00A8") returns { 0, (byte) 0xA8 }
+ *
+ * @param hexString The hex string.
+ * @return the bytes
+ */
+ public static byte[] hexString2Bytes(String hexString) {
+ if (isSpace(hexString)) return null;
+ int len = hexString.length();
+ if (len % 2 != 0) {
+ hexString = "0" + hexString;
+ len = len + 1;
+ }
+ char[] hexBytes = hexString.toUpperCase().toCharArray();
+ byte[] ret = new byte[len >> 1];
+ for (int i = 0; i < len; i += 2) {
+ ret[i >> 1] = (byte) (hex2Int(hexBytes[i]) << 4 | hex2Int(hexBytes[i + 1]));
+ }
+ return ret;
+ }
+
+ private static int hex2Int(final char hexChar) {
+ if (hexChar >= '0' && hexChar <= '9') {
+ return hexChar - '0';
+ } else if (hexChar >= 'A' && hexChar <= 'F') {
+ return hexChar - 'A' + 10;
+ } else {
+ throw new IllegalArgumentException();
+ }
+ }
+
+ /**
+ * Size of memory in unit to size of byte.
+ *
+ * @param memorySize Size of memory.
+ * @param unit The unit of memory size.
+ *
+ * {@link MemoryConstants#BYTE}
+ * {@link MemoryConstants#KB}
+ * {@link MemoryConstants#MB}
+ * {@link MemoryConstants#GB}
+ *
+ * @return size of byte
+ */
+ public static long memorySize2Byte(final long memorySize,
+ @MemoryConstants.Unit final int unit) {
+ if (memorySize < 0) return -1;
+ return memorySize * unit;
+ }
+
+ /**
+ * Size of byte to size of memory in unit.
+ *
+ * @param byteSize Size of byte.
+ * @param unit The unit of memory size.
+ *
+ * {@link MemoryConstants#BYTE}
+ * {@link MemoryConstants#KB}
+ * {@link MemoryConstants#MB}
+ * {@link MemoryConstants#GB}
+ *
+ * @return size of memory in unit
+ */
+ public static double byte2MemorySize(final long byteSize,
+ @MemoryConstants.Unit final int unit) {
+ if (byteSize < 0) return -1;
+ return (double) byteSize / unit;
+ }
+
+ /**
+ * Size of byte to fit size of memory.
+ * to three decimal places
+ *
+ * @param byteSize Size of byte.
+ * @return fit size of memory
+ */
+ @SuppressLint("DefaultLocale")
+ public static String byte2FitMemorySize(final long byteSize) {
+ if (byteSize < 0) {
+ return "shouldn't be less than zero!";
+ } else if (byteSize < MemoryConstants.KB) {
+ return String.format("%.3fB", (double) byteSize);
+ } else if (byteSize < MemoryConstants.MB) {
+ return String.format("%.3fKB", (double) byteSize / MemoryConstants.KB);
+ } else if (byteSize < MemoryConstants.GB) {
+ return String.format("%.3fMB", (double) byteSize / MemoryConstants.MB);
+ } else {
+ return String.format("%.3fGB", (double) byteSize / MemoryConstants.GB);
+ }
+ }
+
+ /**
+ * Time span in unit to milliseconds.
+ *
+ * @param timeSpan The time span.
+ * @param unit The unit of time span.
+ *
+ * {@link TimeConstants#MSEC}
+ * {@link TimeConstants#SEC }
+ * {@link TimeConstants#MIN }
+ * {@link TimeConstants#HOUR}
+ * {@link TimeConstants#DAY }
+ *
+ * @return milliseconds
+ */
+ public static long timeSpan2Millis(final long timeSpan, @TimeConstants.Unit final int unit) {
+ return timeSpan * unit;
+ }
+
+ /**
+ * Milliseconds to time span in unit.
+ *
+ * @param millis The milliseconds.
+ * @param unit The unit of time span.
+ *
+ * {@link TimeConstants#MSEC}
+ * {@link TimeConstants#SEC }
+ * {@link TimeConstants#MIN }
+ * {@link TimeConstants#HOUR}
+ * {@link TimeConstants#DAY }
+ *
+ * @return time span in unit
+ */
+ public static long millis2TimeSpan(final long millis, @TimeConstants.Unit final int unit) {
+ return millis / unit;
+ }
+
+ /**
+ * Milliseconds to fit time span.
+ *
+ * @param millis The milliseconds.
+ * millis <= 0, node_return null
+ * @param precision The precision of time span.
+ *
+ * precision = 0, node_return null
+ * precision = 1, node_return 天
+ * precision = 2, node_return 天, 小时
+ * precision = 3, node_return 天, 小时, 分钟
+ * precision = 4, node_return 天, 小时, 分钟, 秒
+ * precision >= 5,node_return 天, 小时, 分钟, 秒, 毫秒
+ *
+ * @return fit time span
+ */
+ @SuppressLint("DefaultLocale")
+ public static String millis2FitTimeSpan(long millis, int precision) {
+ if (millis <= 0 || precision <= 0) return null;
+ StringBuilder sb = new StringBuilder();
+ String[] units = {"天", "小时", "分钟", "秒", "毫秒"};
+ int[] unitLen = {86400000, 3600000, 60000, 1000, 1};
+ precision = Math.min(precision, 5);
+ for (int i = 0; i < precision; i++) {
+ if (millis >= unitLen[i]) {
+ long mode = millis / unitLen[i];
+ millis -= mode * unitLen[i];
+ sb.append(mode).append(units[i]);
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Input stream to output stream.
+ *
+ * @param is The input stream.
+ * @return output stream
+ */
+ public static ByteArrayOutputStream input2OutputStream(final InputStream is) {
+ if (is == null) return null;
+ try {
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ byte[] b = new byte[MemoryConstants.KB];
+ int len;
+ while ((len = is.read(b, 0, MemoryConstants.KB)) != -1) {
+ os.write(b, 0, len);
+ }
+ return os;
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ } finally {
+ try {
+ is.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Output stream to input stream.
+ *
+ * @param out The output stream.
+ * @return input stream
+ */
+ public ByteArrayInputStream output2InputStream(final OutputStream out) {
+ if (out == null) return null;
+ return new ByteArrayInputStream(((ByteArrayOutputStream) out).toByteArray());
+ }
+
+ /**
+ * Input stream to bytes.
+ *
+ * @param is The input stream.
+ * @return bytes
+ */
+ public static byte[] inputStream2Bytes(final InputStream is) {
+ if (is == null) return null;
+ return input2OutputStream(is).toByteArray();
+ }
+
+ /**
+ * Bytes to input stream.
+ *
+ * @param bytes The bytes.
+ * @return input stream
+ */
+ public static InputStream bytes2InputStream(final byte[] bytes) {
+ if (bytes == null || bytes.length <= 0) return null;
+ return new ByteArrayInputStream(bytes);
+ }
+
+ /**
+ * Output stream to bytes.
+ *
+ * @param out The output stream.
+ * @return bytes
+ */
+ public static byte[] outputStream2Bytes(final OutputStream out) {
+ if (out == null) return null;
+ return ((ByteArrayOutputStream) out).toByteArray();
+ }
+
+ /**
+ * Bytes to output stream.
+ *
+ * @param bytes The bytes.
+ * @return output stream
+ */
+ public static OutputStream bytes2OutputStream(final byte[] bytes) {
+ if (bytes == null || bytes.length <= 0) return null;
+ ByteArrayOutputStream os = null;
+ try {
+ os = new ByteArrayOutputStream();
+ os.write(bytes);
+ return os;
+ } catch (IOException e) {
+ e.printStackTrace();
+ return null;
+ } finally {
+ try {
+ if (os != null) {
+ os.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Input stream to string.
+ *
+ * @param is The input stream.
+ * @param charsetName The name of charset.
+ * @return string
+ */
+ public static String inputStream2String(final InputStream is, final String charsetName) {
+ if (is == null || isSpace(charsetName)) return "";
+ try {
+ return new String(inputStream2Bytes(is), charsetName);
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ return "";
+ }
+ }
+
+ /**
+ * String to input stream.
+ *
+ * @param string The string.
+ * @param charsetName The name of charset.
+ * @return input stream
+ */
+ public static InputStream string2InputStream(final String string, final String charsetName) {
+ if (string == null || isSpace(charsetName)) return null;
+ try {
+ return new ByteArrayInputStream(string.getBytes(charsetName));
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Output stream to string.
+ *
+ * @param out The output stream.
+ * @param charsetName The name of charset.
+ * @return string
+ */
+ public static String outputStream2String(final OutputStream out, final String charsetName) {
+ if (out == null || isSpace(charsetName)) return "";
+ try {
+ return new String(outputStream2Bytes(out), charsetName);
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ return "";
+ }
+ }
+
+ /**
+ * String to output stream.
+ *
+ * @param string The string.
+ * @param charsetName The name of charset.
+ * @return output stream
+ */
+ public static OutputStream string2OutputStream(final String string, final String charsetName) {
+ if (string == null || isSpace(charsetName)) return null;
+ try {
+ return bytes2OutputStream(string.getBytes(charsetName));
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Bitmap to bytes.
+ *
+ * @param bitmap The bitmap.
+ * @param format The format of bitmap.
+ * @return bytes
+ */
+ public static byte[] bitmap2Bytes(final Bitmap bitmap, final Bitmap.CompressFormat format) {
+ if (bitmap == null) return null;
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ bitmap.compress(format, 100, baos);
+ return baos.toByteArray();
+ }
+
+ /**
+ * Bytes to bitmap.
+ *
+ * @param bytes The bytes.
+ * @return bitmap
+ */
+ public static Bitmap bytes2Bitmap(final byte[] bytes) {
+ return (bytes == null || bytes.length == 0)
+ ? null
+ : BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
+ }
+
+ /**
+ * Drawable to bitmap.
+ *
+ * @param drawable The drawable.
+ * @return bitmap
+ */
+ public static Bitmap drawable2Bitmap(final Drawable drawable) {
+ if (drawable instanceof BitmapDrawable) {
+ BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
+ if (bitmapDrawable.getBitmap() != null) {
+ return bitmapDrawable.getBitmap();
+ }
+ }
+ Bitmap bitmap;
+ if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) {
+ bitmap = Bitmap.createBitmap(1, 1,
+ drawable.getOpacity() != PixelFormat.OPAQUE
+ ? Bitmap.Config.ARGB_8888
+ : Bitmap.Config.RGB_565);
+ } else {
+ bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(),
+ drawable.getIntrinsicHeight(),
+ drawable.getOpacity() != PixelFormat.OPAQUE
+ ? Bitmap.Config.ARGB_8888
+ : Bitmap.Config.RGB_565);
+ }
+ Canvas canvas = new Canvas(bitmap);
+ drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ drawable.draw(canvas);
+ return bitmap;
+ }
+
+ /**
+ * Bitmap to drawable.
+ *
+ * @param bitmap The bitmap.
+ * @return drawable
+ */
+ public static Drawable bitmap2Drawable(final Bitmap bitmap) {
+ return bitmap == null ? null : new BitmapDrawable(CommonBaseLibrary.getApplication().getResources(), bitmap);
+ }
+
+ /**
+ * Drawable to bytes.
+ *
+ * @param drawable The drawable.
+ * @param format The format of bitmap.
+ * @return bytes
+ */
+ public static byte[] drawable2Bytes(final Drawable drawable,
+ final Bitmap.CompressFormat format) {
+ return drawable == null ? null : bitmap2Bytes(drawable2Bitmap(drawable), format);
+ }
+
+ /**
+ * Bytes to drawable.
+ *
+ * @param bytes The bytes.
+ * @return drawable
+ */
+ public static Drawable bytes2Drawable(final byte[] bytes) {
+ return bytes == null ? null : bitmap2Drawable(bytes2Bitmap(bytes));
+ }
+
+ /**
+ * View to bitmap.
+ *
+ * @param view The view.
+ * @return bitmap
+ */
+ public static Bitmap view2Bitmap(final View view) {
+ if (view == null) return null;
+ Bitmap ret =
+ Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(ret);
+ Drawable bgDrawable = view.getBackground();
+ if (bgDrawable != null) {
+ bgDrawable.draw(canvas);
+ } else {
+ canvas.drawColor(Color.WHITE);
+ }
+ view.draw(canvas);
+ return ret;
+ }
+
+ /**
+ * Value of dp to value of px.
+ *
+ * @param dpValue The value of dp.
+ * @return value of px
+ */
+ public static int dp2px(final float dpValue) {
+ final float scale = Resources.getSystem().getDisplayMetrics().density;
+ return (int) (dpValue * scale + 0.5f);
+ }
+
+ /**
+ * Value of px to value of dp.
+ *
+ * @param pxValue The value of px.
+ * @return value of dp
+ */
+ public static int px2dp(final float pxValue) {
+ final float scale = Resources.getSystem().getDisplayMetrics().density;
+ return (int) (pxValue / scale + 0.5f);
+ }
+
+ /**
+ * Value of sp to value of px.
+ *
+ * @param spValue The value of sp.
+ * @return value of px
+ */
+ public static int sp2px(final float spValue) {
+ final float fontScale = Resources.getSystem().getDisplayMetrics().scaledDensity;
+ return (int) (spValue * fontScale + 0.5f);
+ }
+
+ /**
+ * Value of px to value of sp.
+ *
+ * @param pxValue The value of px.
+ * @return value of sp
+ */
+ public static int px2sp(final float pxValue) {
+ final float fontScale = Resources.getSystem().getDisplayMetrics().scaledDensity;
+ return (int) (pxValue / fontScale + 0.5f);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // other utils methods
+ ///////////////////////////////////////////////////////////////////////////
+
+ private static boolean isSpace(final String s) {
+ if (s == null) return true;
+ for (int i = 0, len = s.length(); i < len; ++i) {
+ if (!Character.isWhitespace(s.charAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/CountDownTimerUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/CountDownTimerUtils.java
new file mode 100644
index 0000000..faf18ab
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/CountDownTimerUtils.java
@@ -0,0 +1,38 @@
+package com.dahe.mylibrary.utils;
+
+import android.os.CountDownTimer;
+import android.widget.TextView;
+
+public class CountDownTimerUtils extends CountDownTimer {
+
+ private TextView mTextView;
+ /**
+ * @param millisInFuture The number of millis in the future from the call
+ * to {@link #start()} until the countdown is done and {@link #onFinish()}
+ * is called.
+ * @param countDownInterval The interval along the way to receive
+ * {@link #onTick(long)} callbacks.
+ */
+ public CountDownTimerUtils(TextView textView, long millisInFuture, long countDownInterval) {
+ super(millisInFuture, countDownInterval);
+ this.mTextView = textView;
+ }
+
+ @Override
+ public void onTick(long millisUntilFinished) {
+ mTextView.setClickable(false); //设置不可点击
+ mTextView.setText(millisUntilFinished / 1000 + "秒后重新发送"); //设置倒计时时间
+// mTextView.setBackgroundResource(R.drawable.bg_identify_code_press); //设置按钮为灰色,这时是不能点击的
+// SpannableString spannableString = new SpannableString(mTextView.getText().toString()); //获取按钮上的文字
+// ForegroundColorSpan span = new ForegroundColorSpan(Color.RED);
+// spannableString.setSpan(span, 0, 2, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);//将倒计时的时间设置为红色
+// mTextView.setText(spannableString);
+ }
+
+ @Override
+ public void onFinish() {
+ mTextView.setText("获取验证码");
+ mTextView.setClickable(true);//重新获得点击
+// mTextView.setBackgroundResource(R.drawable.bg_identify_code_normal); //还原背景色
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/CrashHandler.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/CrashHandler.java
new file mode 100644
index 0000000..928d308
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/CrashHandler.java
@@ -0,0 +1,243 @@
+package com.dahe.mylibrary.utils;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.Environment;
+import android.os.Looper;
+import android.os.SystemClock;
+import android.util.Log;
+import android.widget.Toast;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FilenameFilter;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.lang.reflect.Field;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import static android.os.Environment.DIRECTORY_ALARMS;
+
+/**
+ * 全局捕获异常
+ *
+ * 当程序发生Uncaught异常的时候,有该类来接管程序,并记录错误日志
+ *
+ */
+@SuppressLint("SimpleDateFormat")
+public class CrashHandler implements Thread.UncaughtExceptionHandler {
+
+ public static String TAG = "MyCrash";
+ // 系统默认的UncaughtException处理类
+ private Thread.UncaughtExceptionHandler mDefaultHandler;
+
+ private static CrashHandler instance = new CrashHandler();
+ private Context mContext;
+
+ // 用来存储设备信息和异常信息
+ private Map infos = new HashMap();
+
+ // 用于格式化日期,作为日志文件名的一部分
+ private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+ /** 保证只有一个CrashHandler实例 */
+ private CrashHandler() {
+ }
+
+ /** 获取CrashHandler实例 ,单例模式 */
+ public static CrashHandler getInstance() {
+ return instance;
+ }
+
+ /**
+ * 初始化
+ *
+ * @param context
+ */
+ public void init(Context context) {
+ mContext = context;
+ // 获取系统默认的UncaughtException处理器
+ mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
+ // 设置该CrashHandler为程序的默认处理器
+ Thread.setDefaultUncaughtExceptionHandler(this);
+ FileUtil.removeFileByTime(getGlobalpath());
+// autoClear(5);
+ }
+
+ /**
+ * 当UncaughtException发生时会转入该函数来处理
+ */
+ @Override
+ public void uncaughtException(Thread thread, Throwable ex) {
+ if (!handleException(ex) && mDefaultHandler != null) {
+ // 如果用户没有处理则让系统默认的异常处理器来处理
+ mDefaultHandler.uncaughtException(thread, ex);
+ } else {
+ SystemClock.sleep(3000);
+ // 退出程序
+ android.os.Process.killProcess(android.os.Process.myPid());
+ System.exit(1);
+ }
+ }
+
+ /**
+ * 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成.
+ *
+ * @param ex
+ * @return true:如果处理了该异常信息; 否则返回false.
+ */
+ private boolean handleException(Throwable ex) {
+ if (ex == null)
+ return false;
+ try {
+ // 使用Toast来显示异常信息
+ new Thread() {
+
+ @Override
+ public void run() {
+ Looper.prepare();
+ Toast.makeText(mContext, "很抱歉,程序出现异常,即将重启.",
+ Toast.LENGTH_LONG).show();
+ Looper.loop();
+ }
+ }.start();
+ // 收集设备参数信息
+ collectDeviceInfo(mContext);
+ // 保存日志文件
+ saveCrashInfoFile(ex);
+ SystemClock.sleep(3000);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return true;
+ }
+
+ /**
+ * 收集设备参数信息
+ *
+ * @param ctx
+ */
+ public void collectDeviceInfo(Context ctx) {
+ try {
+ PackageManager pm = ctx.getPackageManager();
+ PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(),
+ PackageManager.GET_ACTIVITIES);
+ if (pi != null) {
+ String versionName = pi.versionName + "";
+ String versionCode = pi.versionCode + "";
+ infos.put("versionName", versionName);
+ infos.put("versionCode", versionCode);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "an error occured when collect package info", e);
+ }
+ Field[] fields = Build.class.getDeclaredFields();
+ for (Field field : fields) {
+ try {
+ field.setAccessible(true);
+ infos.put(field.getName(), field.get(null).toString());
+ } catch (Exception e) {
+ Log.e(TAG, "an error occured when collect crash info", e);
+ }
+ }
+ }
+
+ /**
+ * 保存错误信息到文件中
+ * @param ex
+ * @return 返回文件名称,便于将文件传送到服务器
+ * @throws Exception
+ */
+ private String saveCrashInfoFile(Throwable ex) throws Exception {
+ StringBuffer sb = new StringBuffer();
+ try {
+ SimpleDateFormat sDateFormat = new SimpleDateFormat(
+ "yyyy-MM-dd HH:mm:ss");
+ String date = sDateFormat.format(new java.util.Date());
+ sb.append("\r\n" + date + "\n");
+ for (Map.Entry entry : infos.entrySet()) {
+ String key = entry.getKey();
+ String value = entry.getValue();
+ sb.append(key + "=" + value + "\n");
+ }
+
+ Writer writer = new StringWriter();
+ PrintWriter printWriter = new PrintWriter(writer);
+ ex.printStackTrace(printWriter);
+ Throwable cause = ex.getCause();
+ while (cause != null) {
+ cause.printStackTrace(printWriter);
+ cause = cause.getCause();
+ }
+ printWriter.flush();
+ printWriter.close();
+ String result = writer.toString();
+ sb.append(result);
+
+ String fileName = writeFile(sb.toString());
+ return fileName;
+ } catch (Exception e) {
+ Log.e(TAG, "an error occured while writing file...", e);
+ sb.append("an error occured while writing file...\r\n");
+ writeFile(sb.toString());
+ }
+ return null;
+ }
+
+ private String writeFile(String sb) throws Exception {
+ String time = formatter.format(new Date());
+ String fileName = "crash-" + time + ".log";
+// if (FileUtil.hasSdcard()) {
+ String path = getGlobalpath();
+ File dir = new File(path);
+ if (!dir.exists())
+ dir.mkdirs();
+
+ String filePath = path + fileName;
+ File txtFile = new File(filePath);
+ if (!txtFile.exists())
+ txtFile.createNewFile();
+
+ FileOutputStream fos = new FileOutputStream(txtFile, true);
+ fos.write(sb.getBytes());
+ fos.flush();
+ fos.close();
+// }
+ return fileName;
+ }
+
+ public static String getGlobalpath() {
+ return Environment.getExternalStorageDirectory().getAbsolutePath()
+ + File.separator + "crash" + File.separator;
+ }
+
+ public static void setTag(String tag) {
+ TAG = tag;
+ }
+
+ /**
+ * 文件删除
+ * @param day 文件保存天数
+ */
+// public void autoClear(final int autoClearDay) {
+// FileUtil.delete(getGlobalpath(), new FilenameFilter() {
+//
+// @Override
+// public boolean accept(File file, String filename) {
+// String s = FileUtil.getFileNameWithoutExtension(filename);
+// int day = autoClearDay < 0 ? autoClearDay : -1 * autoClearDay;
+// String date = "crash-" + DateUtil.getOtherDay(day);
+// return date.compareTo(s) >= 0;
+// }
+// });
+// }
+}
\ No newline at end of file
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/FileUtil.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/FileUtil.java
new file mode 100644
index 0000000..1eda86f
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/FileUtil.java
@@ -0,0 +1,89 @@
+package com.dahe.mylibrary.utils;
+
+import android.util.Log;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+
+import static com.dahe.mylibrary.utils.CrashHandler.TAG;
+
+public class FileUtil {
+
+
+
+
+ //移除文件,获取文件时间与当前时间对比,我这时间定位5天,删除五天前的文件
+ public static void removeFileByTime(String dirPath) {
+ //获取目录下所有文件
+ List allFile = getDirAllFile(new File(dirPath));
+ SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ //获取当前时间
+ Date end = new Date(System.currentTimeMillis());
+ try {
+ end = dateFormat.parse(dateFormat.format(new Date(System.currentTimeMillis())));
+ } catch (Exception e){
+ Log.d(TAG, "dataformat exeption e " + e.toString());
+ }
+ Log.d(TAG, "getNeedRemoveFile dirPath = " +dirPath);
+ for (File file : allFile) {//ComDef
+ try {
+ //文件时间减去当前时间
+ Date start = dateFormat.parse(dateFormat.format(new Date(file.lastModified())));
+ long diff = end.getTime() - start.getTime();//这样得到的差值是微秒级别
+ long days = diff / (1000 * 60 * 60 * 24);
+// if(ComDef.LOGMAXKEEPTIME <= days){
+ if(5 <= days){
+ deleteFile(file);
+ }
+
+ } catch (Exception e){
+ Log.d(TAG, "dataformat exeption e " + e.toString());
+ }
+ }
+ }
+
+ //删除文件夹及文件夹下所有文件
+ public static void deleteFile(File file) {
+ if (file.isDirectory()) {
+ File[] files = file.listFiles();
+ for (int i = 0; i < files.length; i++) {
+ File f = files[i];
+ deleteFile(f);
+ }
+ file.delete();
+ } else if (file.exists()) {
+ file.delete();
+ }
+ }
+
+ //获取指定目录下一级文件
+ public static List getDirAllFile(File file) {
+ List fileList = new ArrayList<>();
+ File[] fileArray = file.listFiles();
+ if(fileArray == null)
+ return fileList;
+ for (File f : fileArray) {
+ fileList.add(f);
+ }
+ fileSortByTime(fileList);
+ return fileList;
+ }
+
+
+ //对文件进行时间排序
+ public static void fileSortByTime(List fileList) {
+ Collections.sort(fileList, new Comparator() {
+ public int compare(File p1, File p2) {
+ if (p1.lastModified() < p2.lastModified()) {
+ return -1;
+ }
+ return 1;
+ }
+ });
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/ImageLoader.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ImageLoader.java
new file mode 100644
index 0000000..1890f38
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ImageLoader.java
@@ -0,0 +1,204 @@
+package com.dahe.mylibrary.utils;
+
+import android.content.Context;
+import android.widget.ImageView;
+
+import androidx.core.content.ContextCompat;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.MultiTransformation;
+import com.bumptech.glide.load.resource.bitmap.CenterCrop;
+import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
+import com.bumptech.glide.request.RequestOptions;
+import com.dahe.mylibrary.weight.GlideCircleWithBorder;
+
+/**
+ * Created by Administrator on 2017/11/27 0027.
+ * 图片加载工具类
+ */
+
+public class ImageLoader {
+ public static ImageLoader mInstance = null;
+
+ public static ImageLoader getInstance() {
+ if (null == mInstance) {
+ synchronized (ImageLoader.class) {
+ if (null == mInstance) {
+ mInstance = new ImageLoader();
+ }
+ }
+ }
+ return mInstance;
+ }
+
+ /**
+ * 普通的加载图片 带占位图
+ *
+ * @param context
+ * @param url
+ * @param imageView
+ * @param multiTransformation 同时设置scaleType在设置圆角或者圆形
+ */
+ public void loadingImage(Context context, final Object url, final ImageView imageView, MultiTransformation multiTransformation, int placeholder) {
+ RequestOptions requestOptions = new RequestOptions();
+ if (null != context) {
+ if (placeholder != -1)
+ requestOptions = requestOptions.placeholder(placeholder).error(placeholder);
+ if (null != multiTransformation)
+ requestOptions = requestOptions.transform(multiTransformation);
+ Glide.with(context).load(url).apply(requestOptions).into(imageView);
+ }
+ }
+
+ /**
+ * 普通的加载图片
+ *
+ * @param context
+ * @param url
+ * @param imageView
+ */
+ public void loadingImage(Context context, final Object url, final ImageView imageView) {
+ loadingImage(context, url, imageView, null, -1);
+ }
+
+ /**
+ * 普通的加载图片 带展位图
+ *
+ * @param context
+ * @param url
+ * @param imageView
+ */
+ public void loadImage(Context context, final Object url, final ImageView imageView, RequestOptions requestOptions, int placeholder) {
+ if (null != context) {
+ if (placeholder != -1)
+ requestOptions = requestOptions.placeholder(placeholder).error(placeholder);
+ Glide.with(context).load(url).centerCrop().apply(requestOptions).into(imageView);
+ }
+ }
+
+ /**
+ * 普通的加载图片 不带占位图的
+ *
+ * @param context
+ * @param url
+ * @param imageView
+ */
+ @Deprecated
+ public void loadImage(Context context, final Object url, final ImageView imageView) {
+ loadImage(context, url, imageView, -1);
+ }
+
+ /**
+ * 普通的加载图片 不带占位图的
+ *
+ * @param context
+ * @param url
+ * @param imageView
+ */
+ public void loadImage(Context context, final Object url, final ImageView imageView, int placeholder) {
+ RequestOptions requestOptions = new RequestOptions();
+ loadImage(context, url, imageView, requestOptions, placeholder);
+ }
+
+ /**
+ * 加载圆形图片
+ *
+ * @param context
+ * @param url
+ * @param imageView
+ */
+ public void loadCircleImage(Context context, Object url, ImageView imageView, int placeholder) {
+ if (null != context) {
+ loadImage(context, url, imageView, RequestOptions.circleCropTransform(), placeholder);
+ }
+ }
+
+ /**
+ * 加载圆形图片
+ *
+ * @param context
+ * @param url
+ * @param imageView
+ */
+ public void loadCircleImage(Context context, Object url, ImageView imageView) {
+ if (null != context) {
+ loadCircleImage(context, url, imageView, -1);
+ }
+ }
+
+ /**
+ * 加载圆角图片
+ *
+ * @param context
+ * @param url
+ * @param round
+ * @param imageView
+ */
+ public void loadRoundImage(Context context, Object url, int round, ImageView imageView, int placeholder) {
+ if (null != context) {
+ RequestOptions requestOptions = RequestOptions.fitCenterTransform().transform(new CenterCrop(), new RoundedCorners(round));
+// RequestOptions requestOptions = new RequestOptions();
+// requestOptions.transform(new GlideRoundTransform(context, round));
+ loadImage(context, url, imageView, requestOptions, placeholder);
+ }
+ }
+
+ /**
+ * 加载圆角图片
+ *
+ * @param context
+ * @param url
+ * @param round
+ * @param imageView
+ */
+ public void loadRoundImage(Context context, Object url, int round, ImageView imageView) {
+ if (null != context) {
+ loadRoundImage(context, url, round, imageView, -1);
+ }
+ }
+
+ /**
+ * 加载圆形带圆环图片
+ *
+ * @param context
+ * @param url
+ * @param imageView
+ */
+ public void loadCircleWithBorderImage(Context context, Object url, int borderWidth, int borderColor, ImageView imageView, int placeholder) {
+ if (null != context) {
+ RequestOptions requestOptions = new RequestOptions();
+ requestOptions.transform(new GlideCircleWithBorder(context, borderWidth, ContextCompat.getColor(context, borderColor)));
+ loadImage(context, url, imageView, requestOptions, placeholder);
+ }
+ }
+
+
+ /**
+ * 加载圆形带圆环图片
+ *
+ * @param context
+ * @param url
+ * @param imageView
+ */
+ public void loadCircleWithBorderImage(Context context, Object url,RequestOptions requestOptions, int borderWidth, int borderColor, ImageView imageView, int placeholder) {
+ if (null != context) {
+ requestOptions.transform(new GlideCircleWithBorder(context, borderWidth, ContextCompat.getColor(context, borderColor)));
+ loadImage(context, url, imageView, requestOptions, placeholder);
+ }
+ }
+
+ /**
+ * 加载圆形带圆环图片
+ *
+ * @param context
+ * @param url
+ * @param imageView
+ */
+ public void loadCircleWithBorderImage(Context context, Object url, int borderWidth, int borderColor, ImageView imageView) {
+ if (null != context) {
+ loadCircleWithBorderImage(context, url, borderWidth, borderColor, imageView, -1);
+ }
+ }
+
+
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/MD5Utils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/MD5Utils.java
new file mode 100644
index 0000000..4c2afac
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/MD5Utils.java
@@ -0,0 +1,60 @@
+package com.dahe.mylibrary.utils;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.security.MessageDigest;
+
+public class MD5Utils {
+
+ private static final int BUFFERSIZE = 8196;
+ private static final String ALGORITHM = "MD5";
+ private static final String CHARSET = "UTF-8";
+
+ public MD5Utils() {
+ }
+
+ public static String md5(String input) {
+ return md5(input, CHARSET);
+ }
+
+ private static String md5(String input, String charsetName) {
+ try {
+ MessageDigest md5 = MessageDigest.getInstance(ALGORITHM);
+ byte md5Bytes[] = md5.digest(input.getBytes(charsetName));
+ return StringUtils.byte2hex(md5Bytes);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return input;
+ }
+
+ public static String md5file(File filename) {
+ BufferedInputStream bufferedInputStream = null;
+ MessageDigest md;
+ try {
+ bufferedInputStream = new BufferedInputStream(new FileInputStream(filename), BUFFERSIZE);
+ md = MessageDigest.getInstance(ALGORITHM);
+ byte[] buffer = new byte[BUFFERSIZE];
+ int i = 0;
+ while ((i = bufferedInputStream.read(buffer)) != -1) {
+ md.update(buffer, 0, i);
+ }
+ return StringUtils.byte2hex(md.digest());
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ } finally {
+ try {
+ bufferedInputStream.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public static String md5reverse(String md5) {
+ return "";
+ }
+
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/MemoryConstants.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/MemoryConstants.java
new file mode 100644
index 0000000..7566d70
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/MemoryConstants.java
@@ -0,0 +1,28 @@
+package com.dahe.mylibrary.utils;
+
+
+import androidx.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2017/03/13
+ * desc : constants of memory
+ *
+ */
+public final class MemoryConstants {
+
+ public static final int BYTE = 1;
+ public static final int KB = 1024;
+ public static final int MB = 1048576;
+ public static final int GB = 1073741824;
+
+ @IntDef({BYTE, KB, MB, GB})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Unit {
+ }
+}
\ No newline at end of file
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/PatternUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/PatternUtils.java
new file mode 100644
index 0000000..f3ec6fa
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/PatternUtils.java
@@ -0,0 +1,28 @@
+package com.dahe.mylibrary.utils;
+
+import java.util.regex.Pattern;
+
+public class PatternUtils {
+
+
+ /**
+ * 正则表达式:验证密码(包含大小写,数字,特殊字符,6-12位)
+ */
+// public static final String REGEX_PASSWORD = "^(?=.*[0-9])(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*,\\.])[0-9a-zA-Z!@#$%^&*,\\\\.]{6,12}$";
+ public static final String REGEX_PASSWORD = "^(?=.*[0-9])(?=.*[a-z])(?=.*[!@#$%^&*,\\.])[0-9a-zA-Z!@#$%^&*,\\\\.]{6,12}$";
+ public static final String REGEX_WORD = "^[A-Za-z]+$";
+
+ /**
+ * 校验密码
+ *
+ * @param password
+ * @return 校验通过返回true,否则返回false
+ */
+ public static boolean isPassword(String password) {
+ return Pattern.matches(REGEX_PASSWORD, password);
+ }
+
+ public static boolean isLetter(String password){
+ return Pattern.matches(REGEX_WORD, password);
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/PhoneFormatCheckUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/PhoneFormatCheckUtils.java
new file mode 100644
index 0000000..2ab5ba1
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/PhoneFormatCheckUtils.java
@@ -0,0 +1,55 @@
+package com.dahe.mylibrary.utils;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+public class PhoneFormatCheckUtils {
+
+ /**
+ * 大陆号码或香港号码均可
+ */
+ public static boolean isPhoneLegal(String str) throws PatternSyntaxException {
+ return isChinaPhoneLegal(str) || isHKPhoneLegal(str);
+ }
+
+ /**
+ * 大陆手机号码11位数,匹配格式:前三位固定格式+后8位任意数
+ * 此方法中前三位格式有:
+ * 13+任意数
+ * 145,147,149
+ * 15+除4的任意数(不要写^4,这样的话字母也会被认为是正确的)
+ * 166
+ * 17+3,5,6,7,8
+ * 18+任意数
+ * 198,199
+ */
+ public static boolean isChinaPhoneLegal(String str) throws PatternSyntaxException {
+ // ^ 匹配输入字符串开始的位置
+ // \d 匹配一个或多个数字,其中 \ 要转义,所以是 \\d
+ // $ 匹配输入字符串结尾的位置
+ String regExp = "^((13[0-9])|(14[5,7,9])|(15[0-3,5-9])|(166)|(17[3,5,6,7,8])" +
+ "|(18[0-9])|(19[8,9]))\\d{8}$";
+ Pattern p = Pattern.compile(regExp);
+ Matcher m = p.matcher(str);
+ return m.matches();
+ }
+
+ /**
+ * 香港手机号码8位数,5|6|8|9开头+7位任意数
+ */
+ public static boolean isHKPhoneLegal(String str) throws PatternSyntaxException {
+ // ^ 匹配输入字符串开始的位置
+ // \d 匹配一个或多个数字,其中 \ 要转义,所以是 \\d
+ // $ 匹配输入字符串结尾的位置
+ String regExp = "^(5|6|8|9)\\d{7}$";
+ Pattern p = Pattern.compile(regExp);
+ Matcher m = p.matcher(str);
+ return m.matches();
+ }
+
+ public static String hintPhone(String phone){
+ return phone.substring(0, 3) + "****" + phone.substring(7, 11);
+ }
+
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/SelectPhotoUtils4.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/SelectPhotoUtils4.java
new file mode 100644
index 0000000..a77622a
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/SelectPhotoUtils4.java
@@ -0,0 +1,366 @@
+package com.dahe.mylibrary.utils;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.view.View;
+import android.widget.ImageView;
+
+import androidx.core.content.ContextCompat;
+
+import com.dahe.mylibrary.R;
+import com.dahe.mylibrary.adapter.GridImageAdapter;
+import com.dahe.mylibrary.dialog.DialogPhotoSelect;
+import com.dahe.mylibrary.net.CommonResponseBean;
+import com.dahe.mylibrary.weight.GlideEngine;
+import com.luck.picture.lib.PictureSelector;
+import com.luck.picture.lib.config.PictureConfig;
+import com.luck.picture.lib.config.PictureMimeType;
+import com.luck.picture.lib.entity.LocalMedia;
+import com.luck.picture.lib.listener.OnResultCallbackListener;
+import com.luck.picture.lib.style.PictureCropParameterStyle;
+import com.luck.picture.lib.style.PictureParameterStyle;
+import com.luck.picture.lib.style.PictureSelectorUIStyle;
+import com.luck.picture.lib.tools.SdkVersionUtils;
+
+import java.lang.ref.WeakReference;
+import java.util.List;
+
+public class SelectPhotoUtils4 implements View.OnClickListener {
+
+
+
+ private Activity ctx;
+ private OnResultCallbackListener listener;
+ private GridImageAdapter mAdapter;
+
+ public void selectSimple(Activity ctx,ImageView imageView, OnResultCallbackListener callbackListener){
+ this.ctx = ctx;
+ this.listener = callbackListener;
+ imageView.setOnClickListener(this);
+ imageView.performClick();
+ }
+
+
+ private final GridImageAdapter.onAddPicClickListener onAddPicClickListener = new GridImageAdapter.onAddPicClickListener() {
+ @Override
+ public void onAddPicClick() {
+ PictureSelector.create(ctx)
+ .openGallery(PictureMimeType.ofImage())
+ .imageEngine(GlideEngine.createGlideEngine())
+ .selectionMode(PictureConfig.MULTIPLE)// 多选 or 单选 PictureConfig.MULTIPLE or PictureConfig.SINGLE
+ .maxSelectNum(6)
+ .isPreviewImage(true)// 是否可预览图片 true or fals
+ .isGif(false)// 是否显示gif图片 true or false
+ .isCamera(true)// 是否显示拍照按钮 true or false
+ .isEnableCrop(true)// 是否裁剪 true or false
+ .selectionData(mAdapter.getData())// 是否传入已选图片
+ .circleDimmedLayer(false)// 是否圆形裁剪 true or false
+ .freeStyleCropEnabled(true)// 裁剪框是否可拖拽 true or false
+
+ .minimumCompressSize(30)// 小于100kb的图片不压缩
+ .showCropFrame(true)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false true or false
+ .showCropGrid(true)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false true or false
+// .rotateEnabled(true) // 裁剪是否可旋转图片 true or false
+ .scaleEnabled(true)// 裁剪是否可放大缩小图片 true or false
+ .forResult(new MyResultCallback(mAdapter));
+ }
+
+ @Override
+ public void onDelPicClick(int postion, LocalMedia localMedia) {
+// DataManager.getInstance().remove(localMedia.getId()+"")
+// .compose(DataManager.setThread())
+// .subscribe(new BaseObserver(ctx, new RxHttpCallBack(ctx) {
+// @Override
+// public void onSuccess(CommonResponseBean t) {
+// super.onSuccess(t);
+//// list.remove(index);
+// mAdapter.getData().remove(postion);
+// mAdapter.notifyItemRemoved(postion);
+// mAdapter.notifyItemRangeChanged(postion, mAdapter.getData().size());
+// }
+// }));
+ }
+ };
+
+ /**
+ * 返回结果回调
+ */
+ private class MyResultCallback implements OnResultCallbackListener {
+ private WeakReference mAdapterWeakReference;
+
+ public MyResultCallback(GridImageAdapter adapter) {
+ super();
+ this.mAdapterWeakReference = new WeakReference<>(adapter);
+ }
+
+ @Override
+ public void onResult(List result) {
+// for (LocalMedia media : result) {
+// Log.i(TAG, "是否压缩:" + media.isCompressed());
+// Log.i(TAG, "压缩:" + media.getCompressPath());
+// Log.i(TAG, "原图:" + media.getPath());
+// Log.i(TAG, "绝对路径:" + media.getRealPath());
+// Log.i(TAG, "是否裁剪:" + media.isCut());
+// Log.i(TAG, "裁剪:" + media.getCutPath());
+// Log.i(TAG, "是否开启原图:" + media.isOriginal());
+// Log.i(TAG, "原图路径:" + media.getOriginalPath());
+// Log.i(TAG, "Android Q 特有Path:" + media.getAndroidQToPath());
+// Log.i(TAG, "宽高: " + media.getWidth() + "x" + media.getHeight());
+// Log.i(TAG, "Size: " + media.getSize());
+//
+// Log.i("MMM", "onResult: " + media.toString());
+// // TODO 可以通过PictureSelectorExternalUtils.getExifInterface();方法获取一些额外的资源信息,如旋转角度、经纬度等信息
+// }
+ listener.onResult(result);
+ if (mAdapterWeakReference.get() != null) {
+ mAdapterWeakReference.get().setList(result);
+ mAdapterWeakReference.get().notifyDataSetChanged();
+ }
+ }
+
+ @Override
+ public void onCancel() {
+// Log.i(TAG, "PictureSelector Cancel");
+ }
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+ private PictureCropParameterStyle mCropParameterStyle;
+
+ private PictureParameterStyle getDefaultStyle() {
+ // 相册主题
+ PictureParameterStyle mPictureParameterStyle = new PictureParameterStyle();
+ // 是否改变状态栏字体颜色(黑白切换)
+ mPictureParameterStyle.isChangeStatusBarFontColor = false;
+ // 是否开启右下角已完成(0/9)风格
+ mPictureParameterStyle.isOpenCompletedNumStyle = false;
+ // 是否开启类似QQ相册带数字选择风格
+ mPictureParameterStyle.isOpenCheckNumStyle = false;
+ // 相册状态栏背景色
+ mPictureParameterStyle.pictureStatusBarColor = Color.parseColor("#393a3e");
+ // 相册列表标题栏背景色
+ mPictureParameterStyle.pictureTitleBarBackgroundColor = Color.parseColor("#393a3e");
+ // 相册父容器背景色
+ mPictureParameterStyle.pictureContainerBackgroundColor = ContextCompat.getColor(ctx, R.color.black);
+ // 相册列表标题栏右侧上拉箭头
+ mPictureParameterStyle.pictureTitleUpResId = R.drawable.picture_icon_arrow_up;
+ // 相册列表标题栏右侧下拉箭头
+ mPictureParameterStyle.pictureTitleDownResId = R.drawable.picture_icon_arrow_down;
+ // 相册文件夹列表选中圆点
+ mPictureParameterStyle.pictureFolderCheckedDotStyle = R.drawable.picture_orange_oval;
+ // 相册返回箭头
+ mPictureParameterStyle.pictureLeftBackIcon = R.drawable.picture_icon_back;
+ // 标题栏字体颜色
+ mPictureParameterStyle.pictureTitleTextColor = ContextCompat.getColor(ctx, R.color.picture_color_white);
+ // 相册右侧取消按钮字体颜色 废弃 改用.pictureRightDefaultTextColor和.pictureRightDefaultTextColor
+ mPictureParameterStyle.pictureCancelTextColor = ContextCompat.getColor(ctx, R.color.picture_color_white);
+ // 选择相册目录背景样式
+// mPictureParameterStyle.pictureAlbumStyle = R.drawable.picture_new_item_select_bg;
+ // 相册列表勾选图片样式
+ mPictureParameterStyle.pictureCheckedStyle = R.drawable.picture_checkbox_selector;
+ // 相册列表底部背景色
+ mPictureParameterStyle.pictureBottomBgColor = ContextCompat.getColor(ctx, R.color.picture_color_grey);
+ // 已选数量圆点背景样式
+ mPictureParameterStyle.pictureCheckNumBgStyle = R.drawable.picture_num_oval;
+ // 相册列表底下预览文字色值(预览按钮可点击时的色值)
+ mPictureParameterStyle.picturePreviewTextColor = ContextCompat.getColor(ctx, R.color.picture_color_fa632d);
+ // 相册列表底下不可预览文字色值(预览按钮不可点击时的色值)
+ mPictureParameterStyle.pictureUnPreviewTextColor = ContextCompat.getColor(ctx, R.color.picture_color_white);
+ // 相册列表已完成色值(已完成 可点击色值)
+ mPictureParameterStyle.pictureCompleteTextColor = ContextCompat.getColor(ctx, R.color.picture_color_fa632d);
+ // 相册列表未完成色值(请选择 不可点击色值)
+ mPictureParameterStyle.pictureUnCompleteTextColor = ContextCompat.getColor(ctx, R.color.picture_color_white);
+ // 预览界面底部背景色
+ mPictureParameterStyle.picturePreviewBottomBgColor = ContextCompat.getColor(ctx, R.color.picture_color_grey);
+ // 外部预览界面删除按钮样式
+ mPictureParameterStyle.pictureExternalPreviewDeleteStyle = R.drawable.picture_icon_delete;
+ // 原图按钮勾选样式 需设置.isOriginalImageControl(true); 才有效
+ mPictureParameterStyle.pictureOriginalControlStyle = R.drawable.picture_original_wechat_checkbox;
+ // 原图文字颜色 需设置.isOriginalImageControl(true); 才有效
+ mPictureParameterStyle.pictureOriginalFontColor = ContextCompat.getColor(ctx, R.color.white);
+ // 外部预览界面是否显示删除按钮
+ mPictureParameterStyle.pictureExternalPreviewGonePreviewDelete = true;
+ // 设置NavBar Color SDK Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP有效
+ mPictureParameterStyle.pictureNavBarColor = Color.parseColor("#393a3e");
+ // 文件夹字体颜色
+ mPictureParameterStyle.folderTextColor = Color.parseColor("#4d4d4d");
+ // 文件夹字体大小
+ mPictureParameterStyle.folderTextSize = 16;
+// // 自定义相册右侧文本内容设置
+// mPictureParameterStyle.pictureRightDefaultText = "";
+// // 自定义相册未完成文本内容
+// mPictureParameterStyle.pictureUnCompleteText = "";
+// // 自定义相册完成文本内容
+// mPictureParameterStyle.pictureCompleteText = "";
+// // 自定义相册列表不可预览文字
+// mPictureParameterStyle.pictureUnPreviewText = "";
+// // 自定义相册列表预览文字
+// mPictureParameterStyle.picturePreviewText = "";
+//
+// // 自定义相册标题字体大小
+// mPictureParameterStyle.pictureTitleTextSize = 18;
+// // 自定义相册右侧文字大小
+// mPictureParameterStyle.pictureRightTextSize = 14;
+// // 自定义相册预览文字大小
+// mPictureParameterStyle.picturePreviewTextSize = 14;
+// // 自定义相册完成文字大小
+// mPictureParameterStyle.pictureCompleteTextSize = 14;
+// // 自定义原图文字大小
+// mPictureParameterStyle.pictureOriginalTextSize = 14;
+
+ // 裁剪主题
+ mCropParameterStyle = new PictureCropParameterStyle(
+ ContextCompat.getColor(ctx, R.color.picture_color_grey),
+ ContextCompat.getColor(ctx, R.color.picture_color_grey),
+ Color.parseColor("#393a3e"),
+ ContextCompat.getColor(ctx, R.color.white),
+ mPictureParameterStyle.isChangeStatusBarFontColor);
+
+ return mPictureParameterStyle;
+ }
+
+ /**
+ * 相机拍照
+ */
+ private void doTakePhoto(Activity ctx) {
+
+ // 裁剪主题
+ mCropParameterStyle = new PictureCropParameterStyle(
+ ContextCompat.getColor(ctx, R.color.picture_color_grey),
+ ContextCompat.getColor(ctx, R.color.picture_color_grey),
+ Color.parseColor("#393a3e"),
+ ContextCompat.getColor(ctx, R.color.white),
+ false);
+
+ PictureSelector.create(ctx)
+ .openCamera(PictureMimeType.ofImage())
+ .imageEngine(GlideEngine.createGlideEngine())
+ .setPictureCropStyle(mCropParameterStyle)// 动态自定义裁剪主题
+ .minSelectNum(1)
+ .maxSelectNum(1)
+ .isSingleDirectReturn(true)// 单选模式下是否直接返回,PictureConfig.SINGLE模式下有效
+// .setPictureUIStyle(PictureSelectorUIStyle.ofDefaultStyle())
+ .isEnableCrop(true)// 是否裁剪 true or false
+ .isCompress(true)// 是否压缩 true or false
+ .isGif(false)// 是否显示gif图片 true or false
+ .circleDimmedLayer(false)// 是否圆形裁剪 true or false
+ .freeStyleCropEnabled(true)// 裁剪框是否可拖拽 true or false
+ .cutOutQuality(30)// 裁剪压缩质量 默认90 int
+ .minimumCompressSize(30)// 小于100kb的图片不压缩
+ .showCropFrame(true)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false true or false
+ .showCropGrid(true)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false true or false
+ .rotateEnabled(true) // 裁剪是否可旋转图片 true or false
+ .scaleEnabled(true)// 裁剪是否可放大缩小图片 true or false
+ .forResult(listener);
+
+
+
+ // 单独拍照
+// PictureSelector.create(ctx)
+// .openCamera(PictureMimeType.ofAll())// 单独拍照,也可录像或也可音频 看你传入的类型是图片or视频
+// .theme(R.style.picture_default_style)// 主题样式设置 具体参考 values/styles
+// .imageEngine(GlideEngine.createGlideEngine())// 外部传入图片加载引擎,必传项
+// .maxSelectNum(1)// 最大图片选择数量
+// .minSelectNum(1)// 最小选择数量
+// .closeAndroidQChangeWH(true)//如果图片有旋转角度则对换宽高,默认为true
+// .closeAndroidQChangeVideoWH(!SdkVersionUtils.checkedAndroid_Q())// 如果视频有旋转角度则对换宽高,默认false
+// .selectionMode(cb_choose_mode.isChecked() ?
+// PictureConfig.MULTIPLE : PictureConfig.SINGLE)// 多选 or 单选
+// .loadCacheResourcesCallback(GlideCacheEngine.createCacheEngine())// 获取图片资源缓存,主要是解决华为10部分机型在拷贝文件过多时会出现卡的问题,这里可以判断只在会出现一直转圈问题机型上使用
+// .isPreviewImage(cb_preview_img.isChecked())// 是否可预览图片
+// .isPreviewVideo(cb_preview_video.isChecked())// 是否可预览视频
+// .isEnablePreviewAudio(cb_preview_audio.isChecked()) // 是否可播放音频
+// .isCamera(cb_isCamera.isChecked())// 是否显示拍照按钮
+// .isEnableCrop(cb_crop.isChecked())// 是否裁剪
+// .isCompress(cb_compress.isChecked())// 是否压缩
+// .compressQuality(60)// 图片压缩后输出质量
+// .glideOverride(160, 160)// glide 加载宽高,越小图片列表越流畅,但会影响列表图片浏览的清晰度
+// .withAspectRatio(aspect_ratio_x, aspect_ratio_y)// 裁剪比例 如16:9 3:2 3:4 1:1 可自定义
+// .hideBottomControls(!cb_hide.isChecked())// 是否显示uCrop工具栏,默认不显示
+// .isGif(cb_isGif.isChecked())// 是否显示gif图片
+// .freeStyleCropEnabled(cb_styleCrop.isChecked())// 裁剪框是否可拖拽
+// .circleDimmedLayer(cb_crop_circular.isChecked())// 是否圆形裁剪
+// .showCropFrame(cb_showCropFrame.isChecked())// 是否显示裁剪矩形边框 圆形裁剪时建议设为false
+// .showCropGrid(cb_showCropGrid.isChecked())// 是否显示裁剪矩形网格 圆形裁剪时建议设为false
+// .isOpenClickSound(cb_voice.isChecked())// 是否开启点击声音
+// .selectionData(mAdapter.getData())// 是否传入已选图片
+// .cutOutQuality(90)// 裁剪输出质量 默认100
+// .minimumCompressSize(100)// 小于100kb的图片不压缩
+// .forResult(new MyResultCallback(mAdapter));
+ }
+
+ //从本地相册中选择
+ private void doSelectPhoto(Activity ctx) {
+ PictureSelector.create(ctx)
+ .openGallery(PictureMimeType.ofImage())
+ .imageEngine(GlideEngine.createGlideEngine())
+ .selectionMode(PictureConfig.SINGLE)// 多选 or 单选 PictureConfig.MULTIPLE or PictureConfig.SINGLE
+ .isPreviewImage(true)// 是否可预览图片 true or fals
+ .isGif(false)// 是否显示gif图片 true or false
+ .isCamera(false)// 是否显示拍照按钮 true or false
+ .isEnableCrop(true)// 是否裁剪 true or false
+ .isCompress(true)// 是否压缩 true or false
+ .circleDimmedLayer(false)// 是否圆形裁剪 true or false
+ .freeStyleCropEnabled(true)// 裁剪框是否可拖拽 true or false
+ .cutOutQuality(30)// 裁剪压缩质量 默认90 int
+ .minimumCompressSize(30)// 小于100kb的图片不压缩
+ .showCropFrame(true)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false true or false
+ .showCropGrid(true)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false true or false
+ .rotateEnabled(true) // 裁剪是否可旋转图片 true or false
+ .scaleEnabled(true)// 裁剪是否可放大缩小图片 true or false
+ .forResult(listener);
+// .forResult(PictureConfig.CHOOSE_REQUEST);
+ }
+
+
+ @Override
+ public void onClick(View view) {
+
+// PictureSelector.create(ctx)
+// .openGallery(PictureMimeType.ofImage())
+// .imageEngine(GlideEngine.createGlideEngine())
+// .selectionMode(PictureConfig.SINGLE)// 多选 or 单选 PictureConfig.MULTIPLE or PictureConfig.SINGLE
+// .isSingleDirectReturn(true)
+// .maxSelectNum(1)
+// .minSelectNum(1)
+// .isPreviewImage(true)// 是否可预览图片 true or fals
+// .isGif(false)// 是否显示gif图片 true or false
+// .isCamera(true)// 是否显示拍照按钮 true or false
+// .isEnableCrop(true)// 是否裁剪 true or false
+// .isCompress(true)// 是否压缩 true or false
+// .circleDimmedLayer(false)// 是否圆形裁剪 true or false
+// .freeStyleCropEnabled(true)// 裁剪框是否可拖拽 true or false
+// .cutOutQuality(30)// 裁剪压缩质量 默认90 int
+// .minimumCompressSize(100)// 小于100kb的图片不压缩
+// .showCropFrame(true)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false true or false
+// .showCropGrid(true)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false true or false
+// .rotateEnabled(true) // 裁剪是否可旋转图片 true or false
+// .scaleEnabled(true)// 裁剪是否可放大缩小图片 true or false
+// .forResult(listener);
+
+
+ DialogPhotoSelect dialogPhotoSelect = new DialogPhotoSelect(ctx);
+ dialogPhotoSelect.show();
+ dialogPhotoSelect.setOnSelectClickListener(new DialogPhotoSelect.onSelectClickListener() {
+ @Override
+ public void onTakePhoto() {
+ doTakePhoto(ctx);
+ }
+
+ @Override
+ public void onSelectPhoto() {
+ doSelectPhoto(ctx);
+ }
+ });
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/SelectPhotoUtils5.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/SelectPhotoUtils5.java
new file mode 100644
index 0000000..4eeb7a9
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/SelectPhotoUtils5.java
@@ -0,0 +1,353 @@
+package com.dahe.mylibrary.utils;
+
+import android.app.Activity;
+import android.graphics.Color;
+import android.view.View;
+import android.widget.ImageView;
+
+import androidx.core.content.ContextCompat;
+
+import com.dahe.mylibrary.R;
+import com.dahe.mylibrary.adapter.GridImageAdapter;
+import com.dahe.mylibrary.dialog.DialogPhotoSelect;
+import com.dahe.mylibrary.weight.GlideEngine;
+import com.luck.picture.lib.PictureSelector;
+import com.luck.picture.lib.config.PictureConfig;
+import com.luck.picture.lib.config.PictureMimeType;
+import com.luck.picture.lib.entity.LocalMedia;
+import com.luck.picture.lib.listener.OnResultCallbackListener;
+import com.luck.picture.lib.style.PictureCropParameterStyle;
+import com.luck.picture.lib.style.PictureParameterStyle;
+
+import java.lang.ref.WeakReference;
+import java.util.List;
+
+public class SelectPhotoUtils5 implements View.OnClickListener {
+
+ private SelectPhotoUtils5 selectPhotoUtils5;
+ private Activity ctx;
+ private OnResultCallbackListener listener;
+ private GridImageAdapter mAdapter;
+
+ public void selectSimple(Activity ctx, ImageView imageView, OnResultCallbackListener callbackListener) {
+ this.ctx = ctx;
+ this.listener = callbackListener;
+ imageView.setOnClickListener(this);
+ imageView.performClick();
+ }
+
+
+
+
+ private final GridImageAdapter.onAddPicClickListener onAddPicClickListener = new GridImageAdapter.onAddPicClickListener() {
+ @Override
+ public void onAddPicClick() {
+ PictureSelector.create(ctx)
+ .openGallery(PictureMimeType.ofImage())
+ .imageEngine(GlideEngine.createGlideEngine())
+ .selectionMode(PictureConfig.MULTIPLE)// 多选 or 单选 PictureConfig.MULTIPLE or PictureConfig.SINGLE
+ .maxSelectNum(6)
+ .isPreviewImage(true)// 是否可预览图片 true or fals
+ .isGif(false)// 是否显示gif图片 true or false
+ .isCamera(true)// 是否显示拍照按钮 true or false
+ .isEnableCrop(false)// 是否裁剪 true or false
+ .selectionData(mAdapter.getData())// 是否传入已选图片
+ .circleDimmedLayer(false)// 是否圆形裁剪 true or false
+ .freeStyleCropEnabled(true)// 裁剪框是否可拖拽 true or false
+
+ .minimumCompressSize(30)// 小于100kb的图片不压缩
+ .showCropFrame(true)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false true or false
+ .showCropGrid(true)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false true or false
+// .rotateEnabled(true) // 裁剪是否可旋转图片 true or false
+ .scaleEnabled(true)// 裁剪是否可放大缩小图片 true or false
+ .forResult(new MyResultCallback(mAdapter));
+ }
+
+ @Override
+ public void onDelPicClick(int postion, LocalMedia localMedia) {
+// DataManager.getInstance().remove(localMedia.getId()+"")
+// .compose(DataManager.setThread())
+// .subscribe(new BaseObserver(ctx, new RxHttpCallBack(ctx) {
+// @Override
+// public void onSuccess(CommonResponseBean t) {
+// super.onSuccess(t);
+//// list.remove(index);
+// mAdapter.getData().remove(postion);
+// mAdapter.notifyItemRemoved(postion);
+// mAdapter.notifyItemRangeChanged(postion, mAdapter.getData().size());
+// }
+// }));
+ }
+ };
+
+ /**
+ * 返回结果回调
+ */
+ private class MyResultCallback implements OnResultCallbackListener {
+ private WeakReference mAdapterWeakReference;
+
+ public MyResultCallback(GridImageAdapter adapter) {
+ super();
+ this.mAdapterWeakReference = new WeakReference<>(adapter);
+ }
+
+ @Override
+ public void onResult(List result) {
+// for (LocalMedia media : result) {
+// Log.i(TAG, "是否压缩:" + media.isCompressed());
+// Log.i(TAG, "压缩:" + media.getCompressPath());
+// Log.i(TAG, "原图:" + media.getPath());
+// Log.i(TAG, "绝对路径:" + media.getRealPath());
+// Log.i(TAG, "是否裁剪:" + media.isCut());
+// Log.i(TAG, "裁剪:" + media.getCutPath());
+// Log.i(TAG, "是否开启原图:" + media.isOriginal());
+// Log.i(TAG, "原图路径:" + media.getOriginalPath());
+// Log.i(TAG, "Android Q 特有Path:" + media.getAndroidQToPath());
+// Log.i(TAG, "宽高: " + media.getWidth() + "x" + media.getHeight());
+// Log.i(TAG, "Size: " + media.getSize());
+//
+// Log.i("MMM", "onResult: " + media.toString());
+// // TODO 可以通过PictureSelectorExternalUtils.getExifInterface();方法获取一些额外的资源信息,如旋转角度、经纬度等信息
+// }
+ listener.onResult(result);
+ if (mAdapterWeakReference.get() != null) {
+ mAdapterWeakReference.get().setList(result);
+ mAdapterWeakReference.get().notifyDataSetChanged();
+ }
+ }
+
+ @Override
+ public void onCancel() {
+// Log.i(TAG, "PictureSelector Cancel");
+ }
+ }
+
+
+ private PictureCropParameterStyle mCropParameterStyle;
+
+ private PictureParameterStyle getDefaultStyle() {
+ // 相册主题
+ PictureParameterStyle mPictureParameterStyle = new PictureParameterStyle();
+ // 是否改变状态栏字体颜色(黑白切换)
+ mPictureParameterStyle.isChangeStatusBarFontColor = false;
+ // 是否开启右下角已完成(0/9)风格
+ mPictureParameterStyle.isOpenCompletedNumStyle = false;
+ // 是否开启类似QQ相册带数字选择风格
+ mPictureParameterStyle.isOpenCheckNumStyle = false;
+ // 相册状态栏背景色
+ mPictureParameterStyle.pictureStatusBarColor = Color.parseColor("#393a3e");
+ // 相册列表标题栏背景色
+ mPictureParameterStyle.pictureTitleBarBackgroundColor = Color.parseColor("#393a3e");
+ // 相册父容器背景色
+ mPictureParameterStyle.pictureContainerBackgroundColor = ContextCompat.getColor(ctx, R.color.black);
+ // 相册列表标题栏右侧上拉箭头
+ mPictureParameterStyle.pictureTitleUpResId = R.drawable.picture_icon_arrow_up;
+ // 相册列表标题栏右侧下拉箭头
+ mPictureParameterStyle.pictureTitleDownResId = R.drawable.picture_icon_arrow_down;
+ // 相册文件夹列表选中圆点
+ mPictureParameterStyle.pictureFolderCheckedDotStyle = R.drawable.picture_orange_oval;
+ // 相册返回箭头
+ mPictureParameterStyle.pictureLeftBackIcon = R.drawable.picture_icon_back;
+ // 标题栏字体颜色
+ mPictureParameterStyle.pictureTitleTextColor = ContextCompat.getColor(ctx, R.color.picture_color_white);
+ // 相册右侧取消按钮字体颜色 废弃 改用.pictureRightDefaultTextColor和.pictureRightDefaultTextColor
+ mPictureParameterStyle.pictureCancelTextColor = ContextCompat.getColor(ctx, R.color.picture_color_white);
+ // 选择相册目录背景样式
+// mPictureParameterStyle.pictureAlbumStyle = R.drawable.picture_new_item_select_bg;
+ // 相册列表勾选图片样式
+ mPictureParameterStyle.pictureCheckedStyle = R.drawable.picture_checkbox_selector;
+ // 相册列表底部背景色
+ mPictureParameterStyle.pictureBottomBgColor = ContextCompat.getColor(ctx, R.color.picture_color_grey);
+ // 已选数量圆点背景样式
+ mPictureParameterStyle.pictureCheckNumBgStyle = R.drawable.picture_num_oval;
+ // 相册列表底下预览文字色值(预览按钮可点击时的色值)
+ mPictureParameterStyle.picturePreviewTextColor = ContextCompat.getColor(ctx, R.color.picture_color_fa632d);
+ // 相册列表底下不可预览文字色值(预览按钮不可点击时的色值)
+ mPictureParameterStyle.pictureUnPreviewTextColor = ContextCompat.getColor(ctx, R.color.picture_color_white);
+ // 相册列表已完成色值(已完成 可点击色值)
+ mPictureParameterStyle.pictureCompleteTextColor = ContextCompat.getColor(ctx, R.color.picture_color_fa632d);
+ // 相册列表未完成色值(请选择 不可点击色值)
+ mPictureParameterStyle.pictureUnCompleteTextColor = ContextCompat.getColor(ctx, R.color.picture_color_white);
+ // 预览界面底部背景色
+ mPictureParameterStyle.picturePreviewBottomBgColor = ContextCompat.getColor(ctx, R.color.picture_color_grey);
+ // 外部预览界面删除按钮样式
+ mPictureParameterStyle.pictureExternalPreviewDeleteStyle = R.drawable.picture_icon_delete;
+ // 原图按钮勾选样式 需设置.isOriginalImageControl(true); 才有效
+ mPictureParameterStyle.pictureOriginalControlStyle = R.drawable.picture_original_wechat_checkbox;
+ // 原图文字颜色 需设置.isOriginalImageControl(true); 才有效
+ mPictureParameterStyle.pictureOriginalFontColor = ContextCompat.getColor(ctx, R.color.white);
+ // 外部预览界面是否显示删除按钮
+ mPictureParameterStyle.pictureExternalPreviewGonePreviewDelete = true;
+ // 设置NavBar Color SDK Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP有效
+ mPictureParameterStyle.pictureNavBarColor = Color.parseColor("#393a3e");
+ // 文件夹字体颜色
+ mPictureParameterStyle.folderTextColor = Color.parseColor("#4d4d4d");
+ // 文件夹字体大小
+ mPictureParameterStyle.folderTextSize = 16;
+// // 自定义相册右侧文本内容设置
+// mPictureParameterStyle.pictureRightDefaultText = "";
+// // 自定义相册未完成文本内容
+// mPictureParameterStyle.pictureUnCompleteText = "";
+// // 自定义相册完成文本内容
+// mPictureParameterStyle.pictureCompleteText = "";
+// // 自定义相册列表不可预览文字
+// mPictureParameterStyle.pictureUnPreviewText = "";
+// // 自定义相册列表预览文字
+// mPictureParameterStyle.picturePreviewText = "";
+//
+// // 自定义相册标题字体大小
+// mPictureParameterStyle.pictureTitleTextSize = 18;
+// // 自定义相册右侧文字大小
+// mPictureParameterStyle.pictureRightTextSize = 14;
+// // 自定义相册预览文字大小
+// mPictureParameterStyle.picturePreviewTextSize = 14;
+// // 自定义相册完成文字大小
+// mPictureParameterStyle.pictureCompleteTextSize = 14;
+// // 自定义原图文字大小
+// mPictureParameterStyle.pictureOriginalTextSize = 14;
+
+ // 裁剪主题
+ mCropParameterStyle = new PictureCropParameterStyle(
+ ContextCompat.getColor(ctx, R.color.picture_color_grey),
+ ContextCompat.getColor(ctx, R.color.picture_color_grey),
+ Color.parseColor("#393a3e"),
+ ContextCompat.getColor(ctx, R.color.white),
+ mPictureParameterStyle.isChangeStatusBarFontColor);
+
+ return mPictureParameterStyle;
+ }
+
+ /**
+ * 相机拍照
+ */
+ private void doTakePhoto(Activity ctx) {
+
+ // 裁剪主题
+ mCropParameterStyle = new PictureCropParameterStyle(
+ ContextCompat.getColor(ctx, R.color.picture_color_grey),
+ ContextCompat.getColor(ctx, R.color.picture_color_grey),
+ Color.parseColor("#393a3e"),
+ ContextCompat.getColor(ctx, R.color.white),
+ false);
+
+ PictureSelector.create(ctx)
+ .openCamera(PictureMimeType.ofImage())
+ .imageEngine(GlideEngine.createGlideEngine())
+ .setPictureCropStyle(mCropParameterStyle)// 动态自定义裁剪主题
+ .minSelectNum(1)
+ .maxSelectNum(1)
+ .isSingleDirectReturn(true)// 单选模式下是否直接返回,PictureConfig.SINGLE模式下有效
+// .setPictureUIStyle(PictureSelectorUIStyle.ofDefaultStyle())
+ .isEnableCrop(false)// 是否裁剪 true or false
+ .isCompress(true)// 是否压缩 true or false
+ .isGif(false)// 是否显示gif图片 true or false
+ .circleDimmedLayer(false)// 是否圆形裁剪 true or false
+ .freeStyleCropEnabled(true)// 裁剪框是否可拖拽 true or false
+ .cutOutQuality(30)// 裁剪压缩质量 默认90 int
+ .minimumCompressSize(30)// 小于100kb的图片不压缩
+ .showCropFrame(true)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false true or false
+ .showCropGrid(true)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false true or false
+ .rotateEnabled(true) // 裁剪是否可旋转图片 true or false
+ .scaleEnabled(true)// 裁剪是否可放大缩小图片 true or false
+ .forResult(listener);
+
+
+ // 单独拍照
+// PictureSelector.create(ctx)
+// .openCamera(PictureMimeType.ofAll())// 单独拍照,也可录像或也可音频 看你传入的类型是图片or视频
+// .theme(R.style.picture_default_style)// 主题样式设置 具体参考 values/styles
+// .imageEngine(GlideEngine.createGlideEngine())// 外部传入图片加载引擎,必传项
+// .maxSelectNum(1)// 最大图片选择数量
+// .minSelectNum(1)// 最小选择数量
+// .closeAndroidQChangeWH(true)//如果图片有旋转角度则对换宽高,默认为true
+// .closeAndroidQChangeVideoWH(!SdkVersionUtils.checkedAndroid_Q())// 如果视频有旋转角度则对换宽高,默认false
+// .selectionMode(cb_choose_mode.isChecked() ?
+// PictureConfig.MULTIPLE : PictureConfig.SINGLE)// 多选 or 单选
+// .loadCacheResourcesCallback(GlideCacheEngine.createCacheEngine())// 获取图片资源缓存,主要是解决华为10部分机型在拷贝文件过多时会出现卡的问题,这里可以判断只在会出现一直转圈问题机型上使用
+// .isPreviewImage(cb_preview_img.isChecked())// 是否可预览图片
+// .isPreviewVideo(cb_preview_video.isChecked())// 是否可预览视频
+// .isEnablePreviewAudio(cb_preview_audio.isChecked()) // 是否可播放音频
+// .isCamera(cb_isCamera.isChecked())// 是否显示拍照按钮
+// .isEnableCrop(cb_crop.isChecked())// 是否裁剪
+// .isCompress(cb_compress.isChecked())// 是否压缩
+// .compressQuality(60)// 图片压缩后输出质量
+// .glideOverride(160, 160)// glide 加载宽高,越小图片列表越流畅,但会影响列表图片浏览的清晰度
+// .withAspectRatio(aspect_ratio_x, aspect_ratio_y)// 裁剪比例 如16:9 3:2 3:4 1:1 可自定义
+// .hideBottomControls(!cb_hide.isChecked())// 是否显示uCrop工具栏,默认不显示
+// .isGif(cb_isGif.isChecked())// 是否显示gif图片
+// .freeStyleCropEnabled(cb_styleCrop.isChecked())// 裁剪框是否可拖拽
+// .circleDimmedLayer(cb_crop_circular.isChecked())// 是否圆形裁剪
+// .showCropFrame(cb_showCropFrame.isChecked())// 是否显示裁剪矩形边框 圆形裁剪时建议设为false
+// .showCropGrid(cb_showCropGrid.isChecked())// 是否显示裁剪矩形网格 圆形裁剪时建议设为false
+// .isOpenClickSound(cb_voice.isChecked())// 是否开启点击声音
+// .selectionData(mAdapter.getData())// 是否传入已选图片
+// .cutOutQuality(90)// 裁剪输出质量 默认100
+// .minimumCompressSize(100)// 小于100kb的图片不压缩
+// .forResult(new MyResultCallback(mAdapter));
+ }
+
+ //从本地相册中选择
+ private void doSelectPhoto(Activity ctx) {
+ PictureSelector.create(ctx)
+ .openGallery(PictureMimeType.ofImage())
+ .imageEngine(GlideEngine.createGlideEngine())
+ .selectionMode(PictureConfig.SINGLE)// 多选 or 单选 PictureConfig.MULTIPLE or PictureConfig.SINGLE
+ .isPreviewImage(true)// 是否可预览图片 true or fals
+ .isGif(false)// 是否显示gif图片 true or false
+ .isCamera(false)// 是否显示拍照按钮 true or false
+ .isEnableCrop(false)// 是否裁剪 true or false
+ .isCompress(true)// 是否压缩 true or false
+ .circleDimmedLayer(false)// 是否圆形裁剪 true or false
+ .freeStyleCropEnabled(true)// 裁剪框是否可拖拽 true or false
+ .cutOutQuality(30)// 裁剪压缩质量 默认90 int
+ .minimumCompressSize(30)// 小于100kb的图片不压缩
+ .showCropFrame(true)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false true or false
+ .showCropGrid(true)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false true or false
+ .rotateEnabled(true) // 裁剪是否可旋转图片 true or false
+ .scaleEnabled(true)// 裁剪是否可放大缩小图片 true or false
+ .forResult(listener);
+// .forResult(PictureConfig.CHOOSE_REQUEST);
+ }
+
+
+ @Override
+ public void onClick(View view) {
+
+// PictureSelector.create(ctx)
+// .openGallery(PictureMimeType.ofImage())
+// .imageEngine(GlideEngine.createGlideEngine())
+// .selectionMode(PictureConfig.SINGLE)// 多选 or 单选 PictureConfig.MULTIPLE or PictureConfig.SINGLE
+// .isSingleDirectReturn(true)
+// .maxSelectNum(1)
+// .minSelectNum(1)
+// .isPreviewImage(true)// 是否可预览图片 true or fals
+// .isGif(false)// 是否显示gif图片 true or false
+// .isCamera(true)// 是否显示拍照按钮 true or false
+// .isEnableCrop(true)// 是否裁剪 true or false
+// .isCompress(true)// 是否压缩 true or false
+// .circleDimmedLayer(false)// 是否圆形裁剪 true or false
+// .freeStyleCropEnabled(true)// 裁剪框是否可拖拽 true or false
+// .cutOutQuality(30)// 裁剪压缩质量 默认90 int
+// .minimumCompressSize(100)// 小于100kb的图片不压缩
+// .showCropFrame(true)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false true or false
+// .showCropGrid(true)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false true or false
+// .rotateEnabled(true) // 裁剪是否可旋转图片 true or false
+// .scaleEnabled(true)// 裁剪是否可放大缩小图片 true or false
+// .forResult(listener);
+
+
+ DialogPhotoSelect dialogPhotoSelect = new DialogPhotoSelect(ctx);
+ dialogPhotoSelect.show();
+ dialogPhotoSelect.setOnSelectClickListener(new DialogPhotoSelect.onSelectClickListener() {
+ @Override
+ public void onTakePhoto() {
+ doTakePhoto(ctx);
+ }
+
+ @Override
+ public void onSelectPhoto() {
+ doSelectPhoto(ctx);
+ }
+ });
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/SelectPhotoUtils6.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/SelectPhotoUtils6.java
new file mode 100644
index 0000000..02b244c
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/SelectPhotoUtils6.java
@@ -0,0 +1,318 @@
+package com.dahe.mylibrary.utils;
+
+import android.app.Activity;
+import android.content.pm.ActivityInfo;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.ImageView;
+
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.dahe.mylibrary.R;
+import com.dahe.mylibrary.adapter.GridImageAdapter;
+import com.dahe.mylibrary.dialog.DialogPhotoSelect;
+import com.dahe.mylibrary.net.CommonResponseBean;
+import com.dahe.mylibrary.weight.FullyGridLayoutManager;
+import com.dahe.mylibrary.weight.GlideEngine;
+import com.luck.picture.lib.PictureSelector;
+import com.luck.picture.lib.config.PictureConfig;
+import com.luck.picture.lib.config.PictureMimeType;
+import com.luck.picture.lib.decoration.GridSpacingItemDecoration;
+import com.luck.picture.lib.entity.LocalMedia;
+import com.luck.picture.lib.listener.OnResultCallbackListener;
+import com.luck.picture.lib.tools.ScreenUtils;
+
+import java.lang.ref.WeakReference;
+import java.util.List;
+
+public class SelectPhotoUtils6 implements View.OnClickListener {
+ private Activity ctx;
+ private OnResultCallbackListener listener;
+ private GridImageAdapter mAdapter;
+ private Build build;
+
+ private SelectPhotoUtils6(Build build, Activity ctx) {
+ this.build = build;
+ this.ctx = ctx;
+ this.listener = build.listener;
+ if (null == listener) {
+ ToastUtils.showToast(ctx, "请初始化回调listener");
+ return;
+ }
+ if (build.isSingle) {//单选
+ if (null == build.imageView) {
+ ToastUtils.showToast(ctx, "请初始化ImageView");
+ return;
+ }
+ selectSimple(build.imageView);
+ } else {//多选
+ if (null == build.recyclerView || !(build.recyclerView instanceof RecyclerView)) {
+ ToastUtils.showToast(ctx, "请初始化RecycleView");
+ return;
+ }
+ selectMul(build.recyclerView);
+
+ }
+ }
+
+
+ public static class Build {
+ private int maxSelect;
+ private boolean isSingle;
+ private boolean isOnlyShow;
+ private ImageView imageView;
+ private RecyclerView recyclerView;
+ private List pics;
+ private OnResultCallbackListener listener;
+
+ public Build maxSelect(int max) {
+ this.maxSelect = max;
+ return this;
+ }
+
+ public Build isSingle(boolean isSingle) {
+ this.isSingle = isSingle;
+ return this;
+ }
+
+ public Build isOnlyShow(boolean isOnlyShow) {
+ this.isOnlyShow = isOnlyShow;
+ return this;
+ }
+
+ public Build imageview(ImageView imageView) {
+ this.imageView = imageView;
+ return this;
+ }
+
+ public Build recycleview(RecyclerView recyclerView) {
+ this.recyclerView = recyclerView;
+ return this;
+ }
+
+ public Build newPics(List pics) {
+ this.pics = pics;
+ return this;
+ }
+
+ public Build resultListener(OnResultCallbackListener listener) {
+ this.listener = listener;
+ return this;
+ }
+
+ public SelectPhotoUtils6 create(Activity ctx) {
+ return new SelectPhotoUtils6(this, ctx);
+ }
+ }
+
+ public GridImageAdapter getmAdapter() {
+ return mAdapter;
+ }
+
+
+ public void selectSimple(ImageView imageView) {
+ imageView.setOnClickListener(this);
+ }
+
+
+ public void selectMul(RecyclerView recyclerView) {
+ FullyGridLayoutManager manager = new FullyGridLayoutManager(ctx,
+ 4, GridLayoutManager.VERTICAL, false);
+
+ recyclerView.addItemDecoration(new GridSpacingItemDecoration(40,
+ ScreenUtils.dip2px(ctx, 8), true
+ ));
+ recyclerView.setLayoutManager(manager);
+ mAdapter = new GridImageAdapter(ctx, onAddPicClickListener);
+ mAdapter.setSelectMax(build.maxSelect);
+ mAdapter.setIsOnlyShow(build.isOnlyShow);
+ recyclerView.setAdapter(mAdapter);
+
+ mAdapter.setOnItemClickListener((v, position) -> {
+ List selectList = mAdapter.getData();
+ if (selectList.size() > 0) {
+ LocalMedia media = selectList.get(position);
+ String mimeType = media.getMimeType();
+ int mediaType = PictureMimeType.getMimeType(mimeType);
+ switch (mediaType) {
+ case PictureConfig.TYPE_VIDEO:
+ // 预览视频
+ PictureSelector.create(ctx)
+ .themeStyle(R.style.picture_default_style)
+// .setPictureStyle(mPictureParameterStyle)// 动态自定义相册主题
+ .externalPictureVideo(TextUtils.isEmpty(media.getAndroidQToPath()) ? media.getPath() : media.getAndroidQToPath());
+ break;
+ case PictureConfig.TYPE_AUDIO:
+ // 预览音频
+ PictureSelector.create(ctx)
+ .externalPictureAudio(PictureMimeType.isContent(media.getPath()) ? media.getAndroidQToPath() : media.getPath());
+ break;
+ default:
+ // 预览图片 可自定长按保存路径
+// PictureWindowAnimationStyle animationStyle = new PictureWindowAnimationStyle();
+// animationStyle.activityPreviewEnterAnimation = R.anim.picture_anim_up_in;
+// animationStyle.activityPreviewExitAnimation = R.anim.picture_anim_down_out;
+ PictureSelector.create(ctx)
+ .themeStyle(R.style.picture_default_style) // xml设置主题
+// .setPictureStyle(mPictureParameterStyle)// 动态自定义相册主题
+ //.setPictureWindowAnimationStyle(animationStyle)// 自定义页面启动动画
+ .setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED)// 设置相册Activity方向,不设置默认使用系统
+ .isNotPreviewDownload(true)// 预览图片长按是否可以下载
+ //.bindCustomPlayVideoCallback(new MyVideoSelectedPlayCallback(getContext()))// 自定义播放回调控制,用户可以使用自己的视频播放界面
+ .imageEngine(GlideEngine.createGlideEngine())// 外部传入图片加载引擎,必传项
+ .openExternalPreview(position, selectList);
+ break;
+ }
+ }
+ });
+ }
+
+
+ private final GridImageAdapter.onAddPicClickListener onAddPicClickListener = new GridImageAdapter.onAddPicClickListener() {
+ @Override
+ public void onAddPicClick() {
+ PictureSelector.create(ctx)
+ .openGallery(PictureMimeType.ofImage())
+ .imageEngine(GlideEngine.createGlideEngine())
+ .selectionMode(build.isSingle ? PictureConfig.SINGLE : PictureConfig.MULTIPLE)// 多选 or 单选 PictureConfig.MULTIPLE or PictureConfig.SINGLE
+ .maxSelectNum(build.maxSelect)
+ .isPreviewImage(true)// 是否可预览图片 true or fals
+ .isGif(false)// 是否显示gif图片 true or false
+ .isCamera(true)// 是否显示拍照按钮 true or false
+ .isEnableCrop(false)// 是否裁剪 true or false
+ .selectionData(mAdapter.getData())// 是否传入已选图片
+ .isCompress(true)// 是否压缩 true or false
+ .circleDimmedLayer(false)// 是否圆形裁剪 true or false
+ .freeStyleCropEnabled(false)// 裁剪框是否可拖拽 true or false
+ .cutOutQuality(30)// 裁剪压缩质量 默认90 int
+ .minimumCompressSize(30)// 小于100kb的图片不压缩
+ .showCropFrame(false)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false true or false
+ .showCropGrid(false)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false true or false
+// .rotateEnabled(true) // 裁剪是否可旋转图片 true or false
+ .scaleEnabled(false)// 裁剪是否可放大缩小图片 true or false
+ .forResult(new MyResultCallback(mAdapter));
+ }
+
+ @Override
+ public void onDelPicClick(int postion, LocalMedia localMedia) {
+// DataManager.getInstance().remove(localMedia.getId() + "")
+// .compose(DataManager.setThread())
+// .subscribe(new BaseObserver(ctx, new RxHttpCallBack(ctx) {
+// @Override
+// public void onSuccess(CommonResponseBean t) {
+// super.onSuccess(t);
+//// list.remove(index);
+// mAdapter.getData().remove(postion);
+// mAdapter.notifyItemRemoved(postion);
+// mAdapter.notifyItemRangeChanged(postion, mAdapter.getData().size());
+// }
+// }));
+ }
+ };
+
+ /**
+ * 返回结果回调
+ */
+ private class MyResultCallback implements OnResultCallbackListener {
+ private WeakReference mAdapterWeakReference;
+
+ public MyResultCallback(GridImageAdapter adapter) {
+ super();
+ this.mAdapterWeakReference = new WeakReference<>(adapter);
+ }
+
+ @Override
+ public void onResult(List result) {
+// for (LocalMedia media : result) {
+// Log.i(TAG, "是否压缩:" + media.isCompressed());
+// Log.i(TAG, "压缩:" + media.getCompressPath());
+// Log.i(TAG, "原图:" + media.getPath());
+// Log.i(TAG, "绝对路径:" + media.getRealPath());
+// Log.i(TAG, "是否裁剪:" + media.isCut());
+// Log.i(TAG, "裁剪:" + media.getCutPath());
+// Log.i(TAG, "是否开启原图:" + media.isOriginal());
+// Log.i(TAG, "原图路径:" + media.getOriginalPath());
+// Log.i(TAG, "Android Q 特有Path:" + media.getAndroidQToPath());
+// Log.i(TAG, "宽高: " + media.getWidth() + "x" + media.getHeight());
+// Log.i(TAG, "Size: " + media.getSize());
+//
+// Log.i("MMM", "onResult: " + media.toString());
+// // TODO 可以通过PictureSelectorExternalUtils.getExifInterface();方法获取一些额外的资源信息,如旋转角度、经纬度等信息
+// }
+ listener.onResult(result);
+ if (mAdapterWeakReference.get() != null) {
+ mAdapterWeakReference.get().setList(result);
+ mAdapterWeakReference.get().notifyDataSetChanged();
+ }
+ }
+
+ @Override
+ public void onCancel() {
+// Log.i(TAG, "PictureSelector Cancel");
+ }
+ }
+
+
+ /**
+ * 相机拍照
+ */
+ private void doTakePhoto(Activity ctx) {
+ PictureSelector.create(ctx)
+ .openCamera(PictureMimeType.ofImage())
+ .imageEngine(GlideEngine.createGlideEngine())
+ .isEnableCrop(false)// 是否裁剪 true or false
+ .isCompress(true)// 是否压缩 true or false
+ .isGif(false)// 是否显示gif图片 true or false
+ .circleDimmedLayer(false)// 是否圆形裁剪 true or false
+ .freeStyleCropEnabled(false)// 裁剪框是否可拖拽 true or false
+ .cutOutQuality(30)// 裁剪压缩质量 默认90 int
+ .minimumCompressSize(30)// 小于100kb的图片不压缩
+ .showCropFrame(false)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false true or false
+ .showCropGrid(false)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false true or false
+ .rotateEnabled(false) // 裁剪是否可旋转图片 true or false
+ .scaleEnabled(false)// 裁剪是否可放大缩小图片 true or false
+ .forResult(listener);
+ }
+
+ //从本地相册中选择
+ private void doSelectPhoto(Activity ctx) {
+ PictureSelector.create(ctx)
+ .openGallery(PictureMimeType.ofImage())
+ .imageEngine(GlideEngine.createGlideEngine())
+ .selectionMode(PictureConfig.SINGLE)// 多选 or 单选 PictureConfig.MULTIPLE or PictureConfig.SINGLE
+ .isPreviewImage(true)// 是否可预览图片 true or fals
+ .isGif(false)// 是否显示gif图片 true or false
+ .isCamera(false)// 是否显示拍照按钮 true or false
+ .isEnableCrop(false)// 是否裁剪 true or false
+ .isCompress(true)// 是否压缩 true or false
+ .circleDimmedLayer(false)// 是否圆形裁剪 true or false
+ .freeStyleCropEnabled(false)// 裁剪框是否可拖拽 true or false
+ .cutOutQuality(30)// 裁剪压缩质量 默认90 int
+ .minimumCompressSize(30)// 小于100kb的图片不压缩
+ .showCropFrame(false)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false true or false
+ .showCropGrid(false)// 是否显示裁剪矩形网格 圆形裁剪时建议设为false true or false
+// .rotateEnabled(true) // 裁剪是否可旋转图片 true or false
+ .scaleEnabled(false)// 裁剪是否可放大缩小图片 true or false
+ .forResult(listener);
+// .forResult(PictureConfig.CHOOSE_REQUEST);
+ }
+
+
+ @Override
+ public void onClick(View view) {
+ DialogPhotoSelect dialogPhotoSelect = new DialogPhotoSelect(ctx);
+ dialogPhotoSelect.show();
+ dialogPhotoSelect.setOnSelectClickListener(new DialogPhotoSelect.onSelectClickListener() {
+ @Override
+ public void onTakePhoto() {
+ doTakePhoto(ctx);
+ }
+
+ @Override
+ public void onSelectPhoto() {
+ doSelectPhoto(ctx);
+ }
+ });
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/ShellUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ShellUtils.java
new file mode 100644
index 0000000..caf3f45
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ShellUtils.java
@@ -0,0 +1,201 @@
+package com.dahe.mylibrary.utils;
+
+
+import java.io.BufferedReader;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.List;
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2016/08/07
+ * desc : utils about shell
+ *
+ */
+public final class ShellUtils {
+
+ private static final String LINE_SEP = System.getProperty("line.separator");
+
+ private ShellUtils() {
+ throw new UnsupportedOperationException("u can't instantiate me...");
+ }
+
+ /**
+ * Execute the command.
+ *
+ * @param command The command.
+ * @param isRooted True to use root, false otherwise.
+ * @return the single {@link CommandResult} instance
+ */
+ public static CommandResult execCmd(final String command, final boolean isRooted) {
+ return execCmd(new String[]{command}, isRooted, true);
+ }
+
+ /**
+ * Execute the command.
+ *
+ * @param commands The commands.
+ * @param isRooted True to use root, false otherwise.
+ * @return the single {@link CommandResult} instance
+ */
+ public static CommandResult execCmd(final List commands, final boolean isRooted) {
+ return execCmd(commands == null ? null : commands.toArray(new String[]{}), isRooted, true);
+ }
+
+ /**
+ * Execute the command.
+ *
+ * @param commands The commands.
+ * @param isRooted True to use root, false otherwise.
+ * @return the single {@link CommandResult} instance
+ */
+ public static CommandResult execCmd(final String[] commands, final boolean isRooted) {
+ return execCmd(commands, isRooted, true);
+ }
+
+ /**
+ * Execute the command.
+ *
+ * @param command The command.
+ * @param isRooted True to use root, false otherwise.
+ * @param isNeedResultMsg True to node_return the message of result, false otherwise.
+ * @return the single {@link CommandResult} instance
+ */
+ public static CommandResult execCmd(final String command,
+ final boolean isRooted,
+ final boolean isNeedResultMsg) {
+ return execCmd(new String[]{command}, isRooted, isNeedResultMsg);
+ }
+
+ /**
+ * Execute the command.
+ *
+ * @param commands The commands.
+ * @param isRooted True to use root, false otherwise.
+ * @param isNeedResultMsg True to node_return the message of result, false otherwise.
+ * @return the single {@link CommandResult} instance
+ */
+ public static CommandResult execCmd(final List commands,
+ final boolean isRooted,
+ final boolean isNeedResultMsg) {
+ return execCmd(commands == null ? null : commands.toArray(new String[]{}),
+ isRooted,
+ isNeedResultMsg);
+ }
+
+ /**
+ * Execute the command.
+ *
+ * @param commands The commands.
+ * @param isRooted True to use root, false otherwise.
+ * @param isNeedResultMsg True to node_return the message of result, false otherwise.
+ * @return the single {@link CommandResult} instance
+ */
+ public static CommandResult execCmd(final String[] commands,
+ final boolean isRooted,
+ final boolean isNeedResultMsg) {
+ int result = -1;
+ if (commands == null || commands.length == 0) {
+ return new CommandResult(result, "", "");
+ }
+ Process process = null;
+ BufferedReader successResult = null;
+ BufferedReader errorResult = null;
+ StringBuilder successMsg = null;
+ StringBuilder errorMsg = null;
+ DataOutputStream os = null;
+ try {
+ process = Runtime.getRuntime().exec(isRooted ? "su" : "sh");
+ os = new DataOutputStream(process.getOutputStream());
+ for (String command : commands) {
+ if (command == null) continue;
+ os.write(command.getBytes());
+ os.writeBytes(LINE_SEP);
+ os.flush();
+ }
+ os.writeBytes("exit" + LINE_SEP);
+ os.flush();
+ result = process.waitFor();
+ if (isNeedResultMsg) {
+ successMsg = new StringBuilder();
+ errorMsg = new StringBuilder();
+ successResult = new BufferedReader(
+ new InputStreamReader(process.getInputStream(), "UTF-8")
+ );
+ errorResult = new BufferedReader(
+ new InputStreamReader(process.getErrorStream(), "UTF-8")
+ );
+ String line;
+ if ((line = successResult.readLine()) != null) {
+ successMsg.append(line);
+ while ((line = successResult.readLine()) != null) {
+ successMsg.append(LINE_SEP).append(line);
+ }
+ }
+ if ((line = errorResult.readLine()) != null) {
+ errorMsg.append(line);
+ while ((line = errorResult.readLine()) != null) {
+ errorMsg.append(LINE_SEP).append(line);
+ }
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ if (os != null) {
+ os.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ try {
+ if (successResult != null) {
+ successResult.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ try {
+ if (errorResult != null) {
+ errorResult.close();
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ if (process != null) {
+ process.destroy();
+ }
+ }
+ return new CommandResult(
+ result,
+ successMsg == null ? "" : successMsg.toString(),
+ errorMsg == null ? "" : errorMsg.toString()
+ );
+ }
+
+ /**
+ * The result of command.
+ */
+ public static class CommandResult {
+ public int result;
+ public String successMsg;
+ public String errorMsg;
+
+ public CommandResult(final int result, final String successMsg, final String errorMsg) {
+ this.result = result;
+ this.successMsg = successMsg;
+ this.errorMsg = errorMsg;
+ }
+
+ @Override
+ public String toString() {
+ return "result: " + result + "\n" +
+ "successMsg: " + successMsg + "\n" +
+ "errorMsg: " + errorMsg;
+ }
+ }
+}
\ No newline at end of file
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/SmsTimeUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/SmsTimeUtils.java
new file mode 100644
index 0000000..4fcad9b
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/SmsTimeUtils.java
@@ -0,0 +1,148 @@
+package com.dahe.mylibrary.utils;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+import android.widget.TextView;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+/**
+ * 文件名:SmsTimeUtils
+ */
+public class SmsTimeUtils {
+
+ /*倒计时时长 单位:秒*/
+ private final static int COUNT = 60;
+ /*当前做*/
+ private static int CURR_COUNT = 0;
+ /*发送验证码*/
+ public final static int SETTING_FINANCE_ACCOUNT_TIME = 1;
+ public final static int WITHDRAW_CASH = 4;
+
+ private static long SETTING_FINANCE_ACCOUNT_TIME_END = 0;
+ private static long WITHDRAW_CASH_END = 0;
+
+ private static Timer countdownTimer;
+ private static TextView tvSendCode;
+ private static Context mContext;
+
+ public static String currPhone;//记录获取验证码的手机号,倒计时结束后清空
+
+ /**
+ * 检查是否超过60秒
+ * 给当前要从多少开始倒数赋值
+ *
+ * @param first true 表示第一次 false不是
+ * @return 是否需要调用startCountdown(TextView textView),主要用于判断在重新打开页,需不需要继续倒计时
+ */
+ public static boolean check(int type, boolean first) {
+ long data = System.currentTimeMillis();
+ long time = 0;
+ switch (type) {
+ case SETTING_FINANCE_ACCOUNT_TIME:
+ time = SETTING_FINANCE_ACCOUNT_TIME_END;
+ break;
+ case WITHDRAW_CASH:
+ time = WITHDRAW_CASH_END;
+ break;
+ }
+ if (data > time) {
+ /*主要是区别于是否是第一次进入。第一次进入不需要赋值*/
+ if (!first) {
+ CURR_COUNT = COUNT;
+ time = data + COUNT * 1000;
+ switch (type) {
+ case SETTING_FINANCE_ACCOUNT_TIME:
+ SETTING_FINANCE_ACCOUNT_TIME_END = time;
+ break;
+ case WITHDRAW_CASH:
+ WITHDRAW_CASH_END = time;
+ break;
+ }
+ }
+ return false;
+ } else {
+ int the_difference = ((int) (time - data)) / 1000;
+ CURR_COUNT = the_difference;
+ return true;
+ }
+ }
+
+ /**
+ * 开始倒计时
+ *
+ * @param textView 控制倒计时的view
+ */
+ public static void startCountdown(TextView textView, Context context) {
+ tvSendCode = textView;
+ mContext = context;
+ if (countdownTimer == null) {
+ countdownTimer = new Timer();
+ countdownTimer.schedule(new TimerTask() {
+ @Override
+ public void run() {
+ Message msg = new Message();
+ msg.what = CURR_COUNT--;
+ handler.sendMessage(msg);
+ }
+ }, 0, 1000);
+ }
+ }
+
+
+ /**
+ * 开始倒计时
+ *
+ * @param textView 控制倒计时的view
+ */
+ public static void startCountdown(TextView textView, Context context,String phone) {
+ currPhone = phone;
+ tvSendCode = textView;
+ mContext = context;
+ if (countdownTimer == null) {
+ countdownTimer = new Timer();
+ countdownTimer.schedule(new TimerTask() {
+ @Override
+ public void run() {
+ Message msg = new Message();
+ msg.what = CURR_COUNT--;
+ handler.sendMessage(msg);
+ }
+ }, 0, 1000);
+ }
+ }
+
+ private static Handler handler = new Handler() {
+ public void handleMessage(Message msg) {
+ if (msg.what <= 0) {
+ if (countdownTimer != null) {
+ countdownTimer.cancel();
+ countdownTimer = null;
+ }
+ currPhone="";
+ tvSendCode.setText("获取验证码");
+ tvSendCode.setEnabled(true);
+ } else {
+ tvSendCode.setText(msg.what + "s后重新获取");
+ tvSendCode.setEnabled(false);
+ }
+ super.handleMessage(msg);
+ }
+ };
+
+
+ public static void stopCountdown(TextView textView, Context context){
+ tvSendCode = textView;
+ mContext = context;
+ if (countdownTimer != null) {
+ countdownTimer.cancel();
+ countdownTimer=null;
+ currPhone="";
+ SETTING_FINANCE_ACCOUNT_TIME_END =0;
+ tvSendCode.setText("获取验证码");
+ tvSendCode.setEnabled(true);
+ }
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBar.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBar.java
new file mode 100644
index 0000000..d7bcaf4
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBar.java
@@ -0,0 +1,111 @@
+package com.dahe.mylibrary.utils;
+
+import android.app.Activity;
+import android.os.Build;
+import android.view.View;
+import android.view.Window;
+
+import androidx.annotation.ColorInt;
+import androidx.annotation.NonNull;
+import androidx.appcompat.widget.Toolbar;
+
+import com.google.android.material.appbar.AppBarLayout;
+import com.google.android.material.appbar.CollapsingToolbarLayout;
+
+
+/**
+ * Utils for status bar
+ * Created by qiu on 3/29/16.
+ */
+public class StatusBar {
+
+ //Get alpha color
+ static int calculateStatusBarColor(int color, int alpha) {
+ float a = 1 - alpha / 255f;
+ int red = color >> 16 & 0xff;
+ int green = color >> 8 & 0xff;
+ int blue = color & 0xff;
+ red = (int) (red * a + 0.5);
+ green = (int) (green * a + 0.5);
+ blue = (int) (blue * a + 0.5);
+ return 0xff << 24 | red << 16 | green << 8 | blue;
+ }
+
+ /**
+ * set statusBarColor
+ * @param statusColor color
+ * @param alpha 0 - 255
+ */
+ public static void setStatusBarColor(@NonNull Activity activity, @ColorInt int statusColor, int alpha) {
+ setStatusBarColor(activity, calculateStatusBarColor(statusColor, alpha));
+ }
+
+ public static void setStatusBarColor(@NonNull Activity activity, @ColorInt int statusColor) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ StatusBarCompatLollipop.setStatusBarColor(activity, statusColor);
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ StatusBarCompatKitKat.setStatusBarColor(activity, statusColor);
+ }
+ }
+
+ public static void translucentStatusBar(@NonNull Activity activity) {
+ translucentStatusBar(activity, false);
+ }
+
+ /**
+ * change to full screen mode
+ * @param hideStatusBarBackground hide status bar alpha Background when SDK > 21, true if hide it
+ */
+ public static void translucentStatusBar(@NonNull Activity activity, boolean hideStatusBarBackground) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ StatusBarCompatLollipop.translucentStatusBar(activity, hideStatusBarBackground);
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ StatusBarCompatKitKat.translucentStatusBar(activity);
+ }
+ }
+
+ public static void setStatusBarColorForCollapsingToolbar(@NonNull Activity activity, AppBarLayout appBarLayout, CollapsingToolbarLayout collapsingToolbarLayout,
+ Toolbar toolbar, @ColorInt int statusColor) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ StatusBarCompatLollipop.setStatusBarColorForCollapsingToolbar(activity, appBarLayout, collapsingToolbarLayout, toolbar, statusColor);
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
+ StatusBarCompatKitKat.setStatusBarColorForCollapsingToolbar(activity, appBarLayout, collapsingToolbarLayout, toolbar, statusColor);
+ }
+ }
+
+ public static void changeToLightStatusBar(@NonNull Activity activity) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ return;
+ }
+ if (activity == null) {
+ return;
+ }
+ Window window = activity.getWindow();
+ if (window == null) {
+ return;
+ }
+ View decorView = window.getDecorView();
+ if (decorView == null) {
+ return;
+ }
+ decorView.setSystemUiVisibility(decorView.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+ }
+
+ public static void cancelLightStatusBar(@NonNull Activity activity) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ return;
+ }
+ if (activity == null) {
+ return;
+ }
+ Window window = activity.getWindow();
+ if (window == null) {
+ return;
+ }
+ View decorView = window.getDecorView();
+ if (decorView == null) {
+ return;
+ }
+ decorView.setSystemUiVisibility(decorView.getSystemUiVisibility() ^ View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBarCompatKitKat.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBarCompatKitKat.java
new file mode 100644
index 0000000..5e9c98e
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBarCompatKitKat.java
@@ -0,0 +1,221 @@
+package com.dahe.mylibrary.utils;
+
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.Context;
+import android.os.Build;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.FrameLayout;
+
+import androidx.appcompat.widget.Toolbar;
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
+import androidx.core.view.ViewCompat;
+
+import com.google.android.material.appbar.AppBarLayout;
+import com.google.android.material.appbar.CollapsingToolbarLayout;
+
+
+/**
+ * After kitkat add fake status bar
+ * Created by qiu on 8/27/16.
+ */
+@TargetApi(Build.VERSION_CODES.KITKAT)
+class StatusBarCompatKitKat {
+
+ private static final String TAG_FAKE_STATUS_BAR_VIEW = "statusBarView";
+ private static final String TAG_MARGIN_ADDED = "marginAdded";
+
+ /**
+ * node_return statusBar's Height in pixels
+ */
+ private static int getStatusBarHeight(Context context) {
+ int result = 0;
+ int resId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
+ if (resId > 0) {
+ result = context.getResources().getDimensionPixelOffset(resId);
+ }
+ return result;
+ }
+
+ /**
+ * 1. Add fake statusBarView.
+ * 2. set tag to statusBarView.
+ */
+ private static View addFakeStatusBarView(Activity activity, int statusBarColor, int statusBarHeight) {
+ Window window = activity.getWindow();
+ ViewGroup mDecorView = (ViewGroup) window.getDecorView();
+
+ View mStatusBarView = new View(activity);
+ FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, statusBarHeight);
+ layoutParams.gravity = Gravity.TOP;
+ mStatusBarView.setLayoutParams(layoutParams);
+ mStatusBarView.setBackgroundColor(statusBarColor);
+ mStatusBarView.setTag(TAG_FAKE_STATUS_BAR_VIEW);
+
+ mDecorView.addView(mStatusBarView);
+ return mStatusBarView;
+ }
+
+ /**
+ * use reserved order to remove is more quickly.
+ */
+ private static void removeFakeStatusBarViewIfExist(Activity activity) {
+ Window window = activity.getWindow();
+ ViewGroup mDecorView = (ViewGroup) window.getDecorView();
+
+ View fakeView = mDecorView.findViewWithTag(TAG_FAKE_STATUS_BAR_VIEW);
+ if (fakeView != null) {
+ mDecorView.removeView(fakeView);
+ }
+ }
+
+ /**
+ * add marginTop to simulate set FitsSystemWindow true
+ */
+ private static void addMarginTopToContentChild(View mContentChild, int statusBarHeight) {
+ if (mContentChild == null) {
+ return;
+ }
+ if (!TAG_MARGIN_ADDED.equals(mContentChild.getTag())) {
+ FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mContentChild.getLayoutParams();
+ lp.topMargin += statusBarHeight;
+ mContentChild.setLayoutParams(lp);
+ mContentChild.setTag(TAG_MARGIN_ADDED);
+ }
+ }
+
+ /**
+ * remove marginTop to simulate set FitsSystemWindow false
+ */
+ private static void removeMarginTopOfContentChild(View mContentChild, int statusBarHeight) {
+ if (mContentChild == null) {
+ return;
+ }
+ if (TAG_MARGIN_ADDED.equals(mContentChild.getTag())) {
+ FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) mContentChild.getLayoutParams();
+ lp.topMargin -= statusBarHeight;
+ mContentChild.setLayoutParams(lp);
+ mContentChild.setTag(null);
+ }
+ }
+
+ /**
+ * set StatusBarColor
+ *
+ * 1. set Window Flag : WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
+ * 2. removeFakeStatusBarViewIfExist
+ * 3. addFakeStatusBarView
+ * 4. addMarginTopToContentChild
+ * 5. cancel ContentChild's fitsSystemWindow
+ */
+ static void setStatusBarColor(Activity activity, int statusColor) {
+ Window window = activity.getWindow();
+ window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+
+ ViewGroup mContentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT);
+ View mContentChild = mContentView.getChildAt(0);
+ int statusBarHeight = getStatusBarHeight(activity);
+
+ removeFakeStatusBarViewIfExist(activity);
+ addFakeStatusBarView(activity, statusColor, statusBarHeight);
+ addMarginTopToContentChild(mContentChild, statusBarHeight);
+
+ if (mContentChild != null) {
+ ViewCompat.setFitsSystemWindows(mContentChild, false);
+ }
+ }
+
+ /**
+ * translucentStatusBar
+ *
+ * 1. set Window Flag : WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
+ * 2. removeFakeStatusBarViewIfExist
+ * 3. removeMarginTopOfContentChild
+ * 4. cancel ContentChild's fitsSystemWindow
+ */
+ static void translucentStatusBar(Activity activity) {
+ Window window = activity.getWindow();
+ window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+
+ ViewGroup mContentView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);
+ View mContentChild = mContentView.getChildAt(0);
+
+ removeFakeStatusBarViewIfExist(activity);
+ removeMarginTopOfContentChild(mContentChild, getStatusBarHeight(activity));
+ if (mContentChild != null) {
+ ViewCompat.setFitsSystemWindows(mContentChild, false);
+ }
+ }
+
+ /**
+ * compat for CollapsingToolbarLayout
+ *
+ * 1. set Window Flag : WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
+ * 2. set FitsSystemWindows for views.
+ * 3. add Toolbar's height, let it layout from top, then add paddingTop to layout normal.
+ * 4. removeFakeStatusBarViewIfExist
+ * 5. removeMarginTopOfContentChild
+ * 6. add OnOffsetChangedListener to change statusBarView's alpha
+ */
+ static void setStatusBarColorForCollapsingToolbar(Activity activity, final AppBarLayout appBarLayout, final CollapsingToolbarLayout collapsingToolbarLayout,
+ Toolbar toolbar, int statusColor) {
+ Window window = activity.getWindow();
+ window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ ViewGroup mContentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT);
+
+ View mContentChild = mContentView.getChildAt(0);
+ mContentChild.setFitsSystemWindows(false);
+ ((View) appBarLayout.getParent()).setFitsSystemWindows(false);
+ appBarLayout.setFitsSystemWindows(false);
+ collapsingToolbarLayout.setFitsSystemWindows(false);
+ collapsingToolbarLayout.getChildAt(0).setFitsSystemWindows(false);
+
+ toolbar.setFitsSystemWindows(false);
+ if (toolbar.getTag() == null) {
+ CollapsingToolbarLayout.LayoutParams lp = (CollapsingToolbarLayout.LayoutParams) toolbar.getLayoutParams();
+ int statusBarHeight = getStatusBarHeight(activity);
+ lp.height += statusBarHeight;
+ toolbar.setLayoutParams(lp);
+ toolbar.setPadding(toolbar.getPaddingLeft(), toolbar.getPaddingTop() + statusBarHeight, toolbar.getPaddingRight(), toolbar.getPaddingBottom());
+ toolbar.setTag(true);
+ }
+
+ int statusBarHeight = getStatusBarHeight(activity);
+ removeFakeStatusBarViewIfExist(activity);
+ removeMarginTopOfContentChild(mContentChild, statusBarHeight);
+ final View statusView = addFakeStatusBarView(activity, statusColor, statusBarHeight);
+
+ CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams()).getBehavior();
+ if (behavior != null && behavior instanceof AppBarLayout.Behavior) {
+ int verticalOffset = ((AppBarLayout.Behavior) behavior).getTopAndBottomOffset();
+ if (Math.abs(verticalOffset) > appBarLayout.getHeight() - collapsingToolbarLayout.getScrimVisibleHeightTrigger()) {
+ statusView.setAlpha(1f);
+ } else {
+ statusView.setAlpha(0f);
+ }
+ } else {
+ statusView.setAlpha(0f);
+ }
+
+ appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
+ @Override
+ public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
+ if (Math.abs(verticalOffset) > appBarLayout.getHeight() - collapsingToolbarLayout.getScrimVisibleHeightTrigger()) {
+ if (statusView.getAlpha() == 0) {
+ statusView.animate().cancel();
+ statusView.animate().alpha(1f).setDuration(collapsingToolbarLayout.getScrimAnimationDuration()).start();
+ }
+ } else {
+ if (statusView.getAlpha() == 1) {
+ statusView.animate().cancel();
+ statusView.animate().alpha(0f).setDuration(collapsingToolbarLayout.getScrimAnimationDuration()).start();
+ }
+ }
+ }
+ });
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBarCompatLollipop.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBarCompatLollipop.java
new file mode 100644
index 0000000..c6e64ae
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/StatusBarCompatLollipop.java
@@ -0,0 +1,193 @@
+package com.dahe.mylibrary.utils;
+
+import android.animation.ValueAnimator;
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Color;
+import android.os.Build;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+
+import androidx.appcompat.widget.Toolbar;
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
+import androidx.core.view.OnApplyWindowInsetsListener;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.WindowInsetsCompat;
+
+import com.google.android.material.appbar.AppBarLayout;
+import com.google.android.material.appbar.CollapsingToolbarLayout;
+
+
+/**
+ * After Lollipop use system method.
+ * Created by qiu on 8/27/16.
+ */
+@TargetApi(Build.VERSION_CODES.LOLLIPOP)
+class StatusBarCompatLollipop {
+
+ /**
+ * node_return statusBar's Height in pixels
+ */
+ private static int getStatusBarHeight(Context context) {
+ int result = 0;
+ int resId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
+ if (resId > 0) {
+ result = context.getResources().getDimensionPixelOffset(resId);
+ }
+ return result;
+ }
+
+ /**
+ * set StatusBarColor
+ *
+ * 1. set Flags to call setStatusBarColor
+ * 2. call setSystemUiVisibility to clear translucentStatusBar's Flag.
+ * 3. set FitsSystemWindows to false
+ */
+ static void setStatusBarColor(Activity activity, int statusColor) {
+ Window window = activity.getWindow();
+
+ window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+ window.setStatusBarColor(statusColor);
+ window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
+
+ ViewGroup mContentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT);
+ View mChildView = mContentView.getChildAt(0);
+ if (mChildView != null) {
+ ViewCompat.setFitsSystemWindows(mChildView, false);
+ ViewCompat.requestApplyInsets(mChildView);
+ }
+ }
+
+ /**
+ * translucentStatusBar(full-screen)
+ *
+ * 1. set Flags to full-screen
+ * 2. set FitsSystemWindows to false
+ *
+ * @param hideStatusBarBackground hide statusBar's shadow
+ */
+ static void translucentStatusBar(Activity activity, boolean hideStatusBarBackground) {
+ Window window = activity.getWindow();
+
+ window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+ if (hideStatusBarBackground) {
+ window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ window.setStatusBarColor(Color.TRANSPARENT);
+ window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
+ } else {
+ window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
+ }
+
+ ViewGroup mContentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT);
+ View mChildView = mContentView.getChildAt(0);
+ if (mChildView != null) {
+ ViewCompat.setFitsSystemWindows(mChildView, false);
+ ViewCompat.requestApplyInsets(mChildView);
+ }
+ }
+
+ /**
+ * compat for CollapsingToolbarLayout
+ *
+ * 1. change to full-screen mode(like translucentStatusBar).
+ * 2. cancel CollapsingToolbarLayout's WindowInsets, let it layout as normal(now setStatusBarScrimColor is useless).
+ * 3. set View's FitsSystemWindow to false.
+ * 4. add Toolbar's height, let it layout from top, then add paddingTop to layout normal.
+ * 5. change statusBarColor by AppBarLayout's offset.
+ * 6. add Listener to change statusBarColor
+ */
+ static void setStatusBarColorForCollapsingToolbar(Activity activity, final AppBarLayout appBarLayout, final CollapsingToolbarLayout collapsingToolbarLayout,
+ Toolbar toolbar, final int statusColor) {
+ final Window window = activity.getWindow();
+
+ window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+ window.setStatusBarColor(Color.TRANSPARENT);
+ window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE);
+
+ ViewCompat.setOnApplyWindowInsetsListener(collapsingToolbarLayout, new OnApplyWindowInsetsListener() {
+ @Override
+ public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) {
+ return insets;
+ }
+ });
+
+ ViewGroup mContentView = (ViewGroup) window.findViewById(Window.ID_ANDROID_CONTENT);
+ View mChildView = mContentView.getChildAt(0);
+ if (mChildView != null) {
+ ViewCompat.setFitsSystemWindows(mChildView, false);
+ ViewCompat.requestApplyInsets(mChildView);
+ }
+
+ ((View) appBarLayout.getParent()).setFitsSystemWindows(false);
+ appBarLayout.setFitsSystemWindows(false);
+
+ toolbar.setFitsSystemWindows(false);
+ if (toolbar.getTag() == null) {
+ CollapsingToolbarLayout.LayoutParams lp = (CollapsingToolbarLayout.LayoutParams) toolbar.getLayoutParams();
+ int statusBarHeight = getStatusBarHeight(activity);
+ lp.height += statusBarHeight;
+ toolbar.setLayoutParams(lp);
+ toolbar.setPadding(toolbar.getPaddingLeft(), toolbar.getPaddingTop() + statusBarHeight, toolbar.getPaddingRight(), toolbar.getPaddingBottom());
+ toolbar.setTag(true);
+ }
+
+ CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams()).getBehavior();
+ if (behavior != null && behavior instanceof AppBarLayout.Behavior) {
+ int verticalOffset = ((AppBarLayout.Behavior) behavior).getTopAndBottomOffset();
+ if (Math.abs(verticalOffset) > appBarLayout.getHeight() - collapsingToolbarLayout.getScrimVisibleHeightTrigger()) {
+ window.setStatusBarColor(statusColor);
+ } else {
+ window.setStatusBarColor(Color.TRANSPARENT);
+ }
+ } else {
+ window.setStatusBarColor(Color.TRANSPARENT);
+ }
+
+ collapsingToolbarLayout.setFitsSystemWindows(false);
+ appBarLayout.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() {
+ @Override
+ public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) {
+ if (Math.abs(verticalOffset) > appBarLayout.getHeight() - collapsingToolbarLayout.getScrimVisibleHeightTrigger()) {
+ if (window.getStatusBarColor() != statusColor) {
+ startColorAnimation(window.getStatusBarColor(), statusColor, collapsingToolbarLayout.getScrimAnimationDuration(), window);
+ }
+ } else {
+ if (window.getStatusBarColor() != Color.TRANSPARENT) {
+ startColorAnimation(window.getStatusBarColor(), Color.TRANSPARENT, collapsingToolbarLayout.getScrimAnimationDuration(), window);
+ }
+ }
+ }
+ });
+ collapsingToolbarLayout.getChildAt(0).setFitsSystemWindows(false);
+ collapsingToolbarLayout.setStatusBarScrimColor(statusColor);
+ }
+
+ /**
+ * use ValueAnimator to change statusBarColor when using collapsingToolbarLayout
+ */
+ static void startColorAnimation(int startColor, int endColor, long duration, final Window window) {
+ if (sAnimator != null) {
+ sAnimator.cancel();
+ }
+ sAnimator = ValueAnimator.ofArgb(startColor, endColor)
+ .setDuration(duration);
+ sAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator valueAnimator) {
+ if (window != null) {
+ window.setStatusBarColor((Integer) valueAnimator.getAnimatedValue());
+ }
+ }
+ });
+ sAnimator.start();
+ }
+
+ private static ValueAnimator sAnimator;
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/StringUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/StringUtils.java
new file mode 100644
index 0000000..b71df3a
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/StringUtils.java
@@ -0,0 +1,99 @@
+package com.dahe.mylibrary.utils;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+
+public class StringUtils {
+
+ public static String byte2hex(byte[] b) {
+
+ String str = "";
+ String stmp = "";
+
+ int length = b.length;
+
+ for (int n = 0; n < length; n++) {
+ stmp = (Integer.toHexString(b[n] & 0XFF));
+ if (stmp.length() == 1) {
+ str += "0";
+ }
+ str += stmp;
+ }
+
+ return str.toLowerCase();
+ }
+
+ public static String nullToStrTrim(String str) {
+
+ if (str == null) {
+ str = "";
+ }
+
+ return str.trim();
+ }
+
+ public static boolean isNotEmpty(String str) {
+
+ return ((str != null) && (str.trim().length() > 0 && !"null".equals(str)));
+ }
+
+ public static boolean isEmpty(String str) {
+
+ return !isNotEmpty(str);
+ }
+
+ public static int getRealLength(String str) {
+
+ return getRealLength(str, "utf-8");
+ }
+
+ public static int getRealLength(String str, String charsetName) {
+
+ str = nullToStrTrim(str);
+
+ try {
+ return str.getBytes(charsetName).length;
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ return 0;
+ }
+ }
+ public static String encode(String str, String enc) {
+
+ String strEncode = "";
+
+ try {
+ if (str != null)
+ strEncode = URLEncoder.encode(str, enc);
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+
+ return strEncode;
+ }
+
+ public static String decode(String str, String enc) {
+
+ String strDecode = "";
+
+ try {
+ if (str != null)
+ strDecode = URLDecoder.decode(str, enc);
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+
+ return strDecode;
+ }
+
+ public static String encode(String str) {
+
+ return encode(str, "utf-8");
+ }
+
+ public static String decode(String str) {
+
+ return decode(str, "utf-8");
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimeConstants.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimeConstants.java
new file mode 100644
index 0000000..d1951da
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimeConstants.java
@@ -0,0 +1,44 @@
+package com.dahe.mylibrary.utils;
+
+
+import androidx.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ *
+ * author: Blankj
+ * blog : http://blankj.com
+ * time : 2017/03/13
+ * desc : 时间相关常量
+ *
+ */
+public final class TimeConstants {
+
+ /**
+ * 毫秒与毫秒的倍数
+ */
+ public static final int MSEC = 1;
+ /**
+ * 秒与毫秒的倍数
+ */
+ public static final int SEC = 1000;
+ /**
+ * 分与毫秒的倍数
+ */
+ public static final int MIN = 60000;
+ /**
+ * 时与毫秒的倍数
+ */
+ public static final int HOUR = 3600000;
+ /**
+ * 天与毫秒的倍数
+ */
+ public static final int DAY = 86400000;
+
+ @IntDef({MSEC, SEC, MIN, HOUR, DAY})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Unit {
+ }
+}
\ No newline at end of file
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimeUtil.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimeUtil.java
new file mode 100644
index 0000000..0cc51bc
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimeUtil.java
@@ -0,0 +1,1703 @@
+package com.dahe.mylibrary.utils;
+
+import android.text.TextUtils;
+
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ *
+ * author: LiJia
+ * time : 2021/08/02
+ * desc : 时间相关工具类
+ *
+ */
+public final class TimeUtil {
+
+ /**
+ * 在工具类中经常使用到工具类的格式化描述,这个主要是一个日期的操作类,所以日志格式主要使用 SimpleDateFormat的定义格式.
+ * 格式的意义如下: 日期和时间模式
+ * 日期和时间格式由日期和时间模式字符串指定。在日期和时间模式字符串中,未加引号的字母 'A' 到 'Z' 和 'a' 到 'z'
+ * 被解释为模式字母,用来表示日期或时间字符串元素。文本可以使用单引号 (') 引起来,以免进行解释。"''"
+ * 表示单引号。所有其他字符均不解释;只是在格式化时将它们简单复制到输出字符串,或者在分析时与输入字符串进行匹配。
+ *
+ * 定义了以下模式字母(所有其他字符 'A' 到 'Z' 和 'a' 到 'z' 都被保留):
+ *
+ *
+ * 字母
+ * 日期或时间元素
+ * 表示
+ * 示例
+ *
+ *
+ * G
+ * Era 标志符
+ * Text
+ * AD
+ *
+ *
+ * y
+ * 年
+ * Year
+ * 1996; 96
+ *
+ *
+ * M
+ * 年中的月份
+ * Month
+ * July; Jul; 07
+ *
+ *
+ * w
+ * 年中的周数
+ * Number
+ * 27
+ *
+ *
+ * W
+ * 月份中的周数
+ * Number
+ * 2
+ *
+ *
+ * D
+ * 年中的天数
+ * Number
+ * 189
+ *
+ *
+ * d
+ * 月份中的天数
+ * Number
+ * 10
+ *
+ *
+ * F
+ * 月份中的星期
+ * Number
+ * 2
+ *
+ *
+ * E
+ * 星期中的天数
+ * Text
+ * Tuesday; Tue
+ *
+ *
+ * a
+ * Am/pm 标记
+ * Text
+ * PM
+ *
+ *
+ * H
+ * 一天中的小时数(0-23)
+ * Number
+ * 0
+ *
+ *
+ * k
+ * 一天中的小时数(1-24)
+ * Number
+ * 24
+ *
+ *
+ * K
+ * am/pm 中的小时数(0-11)
+ * Number
+ * 0
+ *
+ *
+ * h
+ * am/pm 中的小时数(1-12)
+ * Number
+ * 12
+ *
+ *
+ * m
+ * 小时中的分钟数
+ * Number
+ * 30
+ *
+ *
+ * s
+ * 分钟中的秒数
+ * Number
+ * 55
+ *
+ *
+ * S
+ * 毫秒数
+ * Number
+ * 978
+ *
+ *
+ * z
+ * 时区
+ * General time zone
+ * Pacific Standard Time; PST; GMT-08:00
+ *
+ *
+ * Z
+ * 时区
+ * RFC 822 time zone
+ * -0800
+ *
+ *
+ *
+ * HH:mm 15:44
+ * h:mm a 3:44 下午
+ * HH:mm z 15:44 CST
+ * HH:mm Z 15:44 +0800
+ * HH:mm zzzz 15:44 中国标准时间
+ * HH:mm:ss 15:44:40
+ * yyyy-MM-dd 2016-08-12
+ * yyyy-MM-dd HH:mm 2016-08-12 15:44
+ * yyyy-MM-dd HH:mm:ss 2016-08-12 15:44:40
+ * yyyy-MM-dd HH:mm:ss zzzz 2016-08-12 15:44:40 中国标准时间
+ * EEEE yyyy-MM-dd HH:mm:ss zzzz 星期五 2016-08-12 15:44:40 中国标准时间
+ * yyyy-MM-dd HH:mm:ss.SSSZ 2016-08-12 15:44:40.461+0800
+ * yyyy-MM-dd'T'HH:mm:ss.SSSZ 2016-08-12T15:44:40.461+0800
+ * yyyy.MM.dd G 'at' HH:mm:ss z 2016.08.12 公元 at 15:44:40 CST
+ * K:mm a 3:44 下午
+ * EEE, MMM d, ''yy 星期五, 八月 12, '16
+ * hh 'o''clock' a, zzzz 03 o'clock 下午, 中国标准时间
+ * yyyyy.MMMMM.dd GGG hh:mm aaa 02016.八月.12 公元 03:44 下午
+ * EEE, d MMM yyyy HH:mm:ss Z 星期五, 12 八月 2016 15:44:40 +0800
+ * yyMMddHHmmssZ 160812154440+0800
+ * yyyy-MM-dd'T'HH:mm:ss.SSSZ 2016-08-12T15:44:40.461+0800
+ * EEEE 'DATE('yyyy-MM-dd')' 'TIME('HH:mm:ss')' zzzz 星期五 DATE(2016-08-12) TIME(15:44:40) 中国标准时间
+ *
+ * 注意:SimpleDateFormat不是线程安全的,线程安全需用{@code ThreadLocal}
+ */
+
+ private static final DateFormat DEFAULT_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
+ private static final DateFormat DEFAULT_FORMAT2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZSS:SS", Locale.getDefault());
+ private static final DateFormat DEFAULT_FORMAT3 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.getDefault());
+
+ private TimeUtil() {
+ throw new UnsupportedOperationException("u can't instantiate me...");
+ }
+
+ /**
+ * 将时间戳转为时间字符串
+ * 格式为yyyy-MM-dd HH:mm:ss
+ *
+ * @param millis 毫秒时间戳
+ * @return 时间字符串
+ */
+ public static String millis2String(final long millis) {
+ return millis2String(millis, DEFAULT_FORMAT);
+ }
+
+ /**
+ * 将时间戳转为时间字符串
+ * 格式为format
+ *
+ * @param millis 毫秒时间戳
+ * @param format 时间格式
+ * @return 时间字符串
+ */
+ public static String millis2String(final long millis, final DateFormat format) {
+ return format.format(new Date(millis));
+ }
+
+ /**
+ * 将时间字符串转为时间戳
+ * time格式为yyyy-MM-dd HH:mm:ss
+ *
+ * @param time 时间字符串
+ * @return 毫秒时间戳
+ */
+ public static long string2Millis(final String time) {
+ if (TextUtils.isEmpty(time)){
+ return -1;
+ }
+ return string2Millis(time, DEFAULT_FORMAT);
+ }
+
+ /**
+ * 将时间字符串转为时间戳
+ * time格式为format
+ *
+ * @param time 时间字符串
+ * @param format 时间格式
+ * @return 毫秒时间戳
+ */
+ public static long string2Millis(final String time, final DateFormat format) {
+ try {
+ return format.parse(time).getTime();
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ return -1;
+ }
+
+ /**
+ * 将时间字符串转为时间戳
+ * time格式为format
+ *
+ * @param time 时间字符串
+ * @return 毫秒时间戳
+ */
+ public static String string2String(final String time,final SimpleDateFormat format) {
+ try {
+ return date2String(format.parse(time));
+// return DEFAULT_FORMAT.format(DEFAULT_FORMAT2.parse(time).getTime());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+
+ /**
+ * 将时间字符串转为Date类型
+ * time格式为yyyy-MM-dd HH:mm:ss
+ *
+ * @param time 时间字符串
+ * @return Date类型
+ */
+ public static Date string2Date(final String time) {
+ return string2Date(time, DEFAULT_FORMAT);
+ }
+
+ /**
+ * 将时间字符串转为Date类型
+ * time格式为format
+ *
+ * @param time 时间字符串
+ * @param format 时间格式
+ * @return Date类型
+ */
+ public static Date string2Date(final String time, final DateFormat format) {
+ try {
+ return format.parse(time);
+ } catch (ParseException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ /**
+ * 将Date类型转为时间字符串
+ * 格式为yyyy-MM-dd HH:mm:ss
+ *
+ * @param date Date类型时间
+ * @return 时间字符串
+ */
+ public static String date2String(final Date date) {
+ return date2String(date, DEFAULT_FORMAT);
+ }
+
+ /**
+ * 将Date类型转为时间字符串
+ * 格式为format
+ *
+ * @param date Date类型时间
+ * @param format 时间格式
+ * @return 时间字符串
+ */
+ public static String date2String(final Date date, final DateFormat format) {
+ return format.format(date);
+ }
+
+ /**
+ * 将Date类型转为时间戳
+ *
+ * @param date Date类型时间
+ * @return 毫秒时间戳
+ */
+ public static long date2Millis(final Date date) {
+ return date.getTime();
+ }
+
+ /**
+ * 将时间戳转为Date类型
+ *
+ * @param millis 毫秒时间戳
+ * @return Date类型时间
+ */
+ public static Date millis2Date(final long millis) {
+ return new Date(millis);
+ }
+
+ /**
+ * 获取两个时间差(单位:unit)
+ * time0和time1格式都为yyyy-MM-dd HH:mm:ss
+ *
+ * @param time0 时间字符串0
+ * @param time1 时间字符串1
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return unit时间戳
+ */
+ public static long getTimeSpan(final String time0, final String time1, @TimeConstants.Unit final int unit) {
+ return getTimeSpan(time0, time1, DEFAULT_FORMAT, unit);
+ }
+
+ /**
+ * 获取两个时间差(单位:unit)
+ * time0和time1格式都为format
+ *
+ * @param time0 时间字符串0
+ * @param time1 时间字符串1
+ * @param format 时间格式
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return unit时间戳
+ */
+ public static long getTimeSpan(final String time0, final String time1, final DateFormat format, @TimeConstants.Unit final int unit) {
+ return millis2TimeSpan(Math.abs(string2Millis(time0, format) - string2Millis(time1, format)), unit);
+ }
+
+ /**
+ * 获取两个时间差(单位:unit)
+ *
+ * @param date0 Date类型时间0
+ * @param date1 Date类型时间1
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return unit时间戳
+ */
+ public static long getTimeSpan(final Date date0, final Date date1, @TimeConstants.Unit final int unit) {
+ return millis2TimeSpan(Math.abs(date2Millis(date0) - date2Millis(date1)), unit);
+ }
+
+ /**
+ * 获取两个时间差(单位:unit)
+ *
+ * @param millis0 毫秒时间戳0
+ * @param millis1 毫秒时间戳1
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return unit时间戳
+ */
+ public static long getTimeSpan(final long millis0, final long millis1, @TimeConstants.Unit final int unit) {
+ return millis2TimeSpan(Math.abs(millis0 - millis1), unit);
+ }
+
+ /**
+ * 获取合适型两个时间差
+ * time0和time1格式都为yyyy-MM-dd HH:mm:ss
+ *
+ * @param time0 时间字符串0
+ * @param time1 时间字符串1
+ * @param precision 精度
+ * precision = 0,返回null
+ * precision = 1,返回天
+ * precision = 2,返回天和小时
+ * precision = 3,返回天、小时和分钟
+ * precision = 4,返回天、小时、分钟和秒
+ * precision >= 5,返回天、小时、分钟、秒和毫秒
+ * @return 合适型两个时间差
+ */
+ public static String getFitTimeSpan(final String time0, final String time1, final int precision) {
+ if (TextUtils.isEmpty(time0)||TextUtils.isEmpty(time1)){
+ return "";
+ }
+ return millis2FitTimeSpan(Math.abs(string2Millis(time0, DEFAULT_FORMAT) - string2Millis(time1, DEFAULT_FORMAT)), precision);
+ }
+
+ /**
+ * 获取合适型两个时间差
+ * time0和time1格式都为format
+ *
+ * @param time0 时间字符串0
+ * @param time1 时间字符串1
+ * @param format 时间格式
+ * @param precision 精度
+ * precision = 0,返回null
+ * precision = 1,返回天
+ * precision = 2,返回天和小时
+ * precision = 3,返回天、小时和分钟
+ * precision = 4,返回天、小时、分钟和秒
+ * precision >= 5,返回天、小时、分钟、秒和毫秒
+ * @return 合适型两个时间差
+ */
+ public static String getFitTimeSpan(final String time0, final String time1, final DateFormat format, final int precision) {
+ return millis2FitTimeSpan(Math.abs(string2Millis(time0, format) - string2Millis(time1, format)), precision);
+ }
+
+ /**
+ * 获取合适型两个时间差
+ *
+ * @param date0 Date类型时间0
+ * @param date1 Date类型时间1
+ * @param precision 精度
+ * precision = 0,返回null
+ * precision = 1,返回天
+ * precision = 2,返回天和小时
+ * precision = 3,返回天、小时和分钟
+ * precision = 4,返回天、小时、分钟和秒
+ * precision >= 5,返回天、小时、分钟、秒和毫秒
+ * @return 合适型两个时间差
+ */
+ public static String getFitTimeSpan(final Date date0, final Date date1, final int precision) {
+ return millis2FitTimeSpan(Math.abs(date2Millis(date0) - date2Millis(date1)), precision);
+ }
+
+ /**
+ * 获取合适型两个时间差
+ *
+ * @param millis0 毫秒时间戳1
+ * @param millis1 毫秒时间戳2
+ * @param precision 精度
+ * precision = 0,返回null
+ * precision = 1,返回天
+ * precision = 2,返回天和小时
+ * precision = 3,返回天、小时和分钟
+ * precision = 4,返回天、小时、分钟和秒
+ * precision >= 5,返回天、小时、分钟、秒和毫秒
+ * @return 合适型两个时间差
+ */
+ public static String getFitTimeSpan(final long millis0, final long millis1, final int precision) {
+ return millis2FitTimeSpan(Math.abs(millis0 - millis1), precision);
+ }
+
+ /**
+ * 获取当前毫秒时间戳
+ *
+ * @return 毫秒时间戳
+ */
+ public static long getNowMills() {
+ return System.currentTimeMillis();
+ }
+
+ /**
+ * 获取当前时间字符串
+ *
+ * @param pattern 格式化时间的格式
+ * @return
+ */
+ public static String getNowString(String pattern) {
+ return millis2String(System.currentTimeMillis(), TextUtils.isEmpty(pattern) ? DEFAULT_FORMAT : new SimpleDateFormat(pattern, Locale.getDefault()));
+ }
+
+ /**
+ * 获取当前时间字符串
+ * 格式为format
+ *
+ * @param format 时间格式
+ * @return 时间字符串
+ */
+ public static String getNowString(final DateFormat format) {
+ return millis2String(System.currentTimeMillis(), format);
+ }
+
+ /**
+ * 获取当前Date
+ *
+ * @return Date类型时间
+ */
+ public static Date getNowDate() {
+ return new Date();
+ }
+
+ /**
+ * 获取与当前时间的差(单位:unit)
+ * time格式为yyyy-MM-dd HH:mm:ss
+ *
+ * @param time 时间字符串
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return unit时间戳
+ */
+ public static long getTimeSpanByNow(final String time, @TimeConstants.Unit final int unit) {
+ return getTimeSpan(getNowString(""), time, DEFAULT_FORMAT, unit);
+ }
+
+ /**
+ * 获取与当前时间的差(单位:unit)
+ * time格式为format
+ *
+ * @param time 时间字符串
+ * @param format 时间格式
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return unit时间戳
+ */
+ public static long getTimeSpanByNow(final String time, final DateFormat format, @TimeConstants.Unit final int unit) {
+ return getTimeSpan(getNowString(format), time, format, unit);
+ }
+
+ /**
+ * 获取与当前时间的差(单位:unit)
+ *
+ * @param date Date类型时间
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return unit时间戳
+ */
+ public static long getTimeSpanByNow(final Date date, @TimeConstants.Unit final int unit) {
+ return getTimeSpan(new Date(), date, unit);
+ }
+
+ /**
+ * 获取与当前时间的差(单位:unit)
+ *
+ * @param millis 毫秒时间戳
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return unit时间戳
+ */
+ public static long getTimeSpanByNow(final long millis, @TimeConstants.Unit final int unit) {
+ return getTimeSpan(System.currentTimeMillis(), millis, unit);
+ }
+
+ /**
+ * 获取合适型与当前时间的差
+ * time格式为yyyy-MM-dd HH:mm:ss
+ *
+ * @param time 时间字符串
+ * @param precision 精度
+ *
+ * precision = 0,返回null
+ * precision = 1,返回天
+ * precision = 2,返回天和小时
+ * precision = 3,返回天、小时和分钟
+ * precision = 4,返回天、小时、分钟和秒
+ * precision >= 5,返回天、小时、分钟、秒和毫秒
+ *
+ * @return 合适型与当前时间的差
+ */
+ public static String getFitTimeSpanByNow(final String time, final int precision) {
+ return getFitTimeSpan(getNowString(""), time, DEFAULT_FORMAT, precision);
+ }
+
+ /**
+ * 获取合适型与当前时间的差
+ * time格式为format
+ *
+ * @param time 时间字符串
+ * @param format 时间格式
+ * @param precision 精度
+ *
+ * precision = 0,返回null
+ * precision = 1,返回天
+ * precision = 2,返回天和小时
+ * precision = 3,返回天、小时和分钟
+ * precision = 4,返回天、小时、分钟和秒
+ * precision >= 5,返回天、小时、分钟、秒和毫秒
+ *
+ * @return 合适型与当前时间的差
+ */
+ public static String getFitTimeSpanByNow(final String time, final DateFormat format, final int precision) {
+ return getFitTimeSpan(getNowString(format), time, format, precision);
+ }
+
+ /**
+ * 获取合适型与当前时间的差
+ *
+ * @param date Date类型时间
+ * @param precision 精度
+ *
+ * precision = 0,返回null
+ * precision = 1,返回天
+ * precision = 2,返回天和小时
+ * precision = 3,返回天、小时和分钟
+ * precision = 4,返回天、小时、分钟和秒
+ * precision >= 5,返回天、小时、分钟、秒和毫秒
+ *
+ * @return 合适型与当前时间的差
+ */
+ public static String getFitTimeSpanByNow(final Date date, final int precision) {
+ return getFitTimeSpan(getNowDate(), date, precision);
+ }
+
+ /**
+ * 获取合适型与当前时间的差
+ *
+ * @param millis 毫秒时间戳
+ * @param precision 精度
+ *
+ * precision = 0,返回null
+ * precision = 1,返回天
+ * precision = 2,返回天和小时
+ * precision = 3,返回天、小时和分钟
+ * precision = 4,返回天、小时、分钟和秒
+ * precision >= 5,返回天、小时、分钟、秒和毫秒
+ *
+ * @return 合适型与当前时间的差
+ */
+ public static String getFitTimeSpanByNow(final long millis, final int precision) {
+ return getFitTimeSpan(System.currentTimeMillis(), millis, precision);
+ }
+
+ /**
+ * 获取友好型与当前时间的差
+ * time格式为yyyy-MM-dd HH:mm:ss
+ *
+ * @param time 时间字符串
+ * @return 友好型与当前时间的差
+ *
+ * 如果小于1秒钟内,显示刚刚
+ * 如果在1分钟内,显示XXX秒前
+ * 如果在1小时内,显示XXX分钟前
+ * 如果在1小时外的今天内,显示今天15:32
+ * 如果是昨天的,显示昨天15:32
+ * 其余显示,2016-10-15
+ * 时间不合法的情况全部日期和时间信息,如星期六 十月 27 14:21:20 CST 2007
+ *
+ */
+ public static String getFriendlyTimeSpanByNow(final String time) {
+ return getFriendlyTimeSpanByNow(time, DEFAULT_FORMAT);
+ }
+
+ /**
+ * 获取友好型与当前时间的差
+ * time格式为format
+ *
+ * @param time 时间字符串
+ * @param format 时间格式
+ * @return 友好型与当前时间的差
+ *
+ * 如果小于1秒钟内,显示刚刚
+ * 如果在1分钟内,显示XXX秒前
+ * 如果在1小时内,显示XXX分钟前
+ * 如果在1小时外的今天内,显示今天15:32
+ * 如果是昨天的,显示昨天15:32
+ * 其余显示,2016-10-15
+ * 时间不合法的情况全部日期和时间信息,如星期六 十月 27 14:21:20 CST 2007
+ *
+ */
+ public static String getFriendlyTimeSpanByNow(final String time, final DateFormat format) {
+ return getFriendlyTimeSpanByNow(string2Millis(time, format));
+ }
+
+ /**
+ * 获取友好型与当前时间的差
+ *
+ * @param date Date类型时间
+ * @return 友好型与当前时间的差
+ *
+ * 如果小于1秒钟内,显示刚刚
+ * 如果在1分钟内,显示XXX秒前
+ * 如果在1小时内,显示XXX分钟前
+ * 如果在1小时外的今天内,显示今天15:32
+ * 如果是昨天的,显示昨天15:32
+ * 其余显示,2016-10-15
+ * 时间不合法的情况全部日期和时间信息,如星期六 十月 27 14:21:20 CST 2007
+ *
+ */
+ public static String getFriendlyTimeSpanByNow(final Date date) {
+ return getFriendlyTimeSpanByNow(date.getTime());
+ }
+
+ /**
+ * 获取友好型与当前时间的差
+ *
+ * @param millis 毫秒时间戳
+ * @return 友好型与当前时间的差
+ *
+ * 如果小于1秒钟内,显示刚刚
+ * 如果在1分钟内,显示XXX秒前
+ * 如果在1小时内,显示XXX分钟前
+ * 如果在1小时外的今天内,显示今天15:32
+ * 如果是昨天的,显示昨天15:32
+ * 其余显示,2016-10-15
+ * 时间不合法的情况全部日期和时间信息,如星期六 十月 27 14:21:20 CST 2007
+ *
+ */
+ public static String getFriendlyTimeSpanByNow(final long millis) {
+ long now = System.currentTimeMillis();
+ long span = now - millis;
+ if (span < 0)
+ return String.format("%tc", millis);// U can read http://www.apihome.cn/api/java/Formatter.html to understand it.
+ if (span < 1000) {
+ return "刚刚";
+ } else if (span < TimeConstants.MIN) {
+ return String.format(Locale.getDefault(), "%d秒前", span / TimeConstants.SEC);
+ } else if (span < TimeConstants.HOUR) {
+ return String.format(Locale.getDefault(), "%d分钟前", span / TimeConstants.MIN);
+ }
+ // 获取当天00:00
+ long wee = getWeeOfToday();
+ if (millis >= wee) {
+ return String.format("今天%tR", millis);
+ } else if (millis >= wee - TimeConstants.DAY) {
+ return String.format("昨天%tR", millis);
+ } else {
+ return String.format("%tF", millis);
+ }
+ }
+
+ private static long getWeeOfToday() {
+ Calendar cal = Calendar.getInstance();
+ cal.set(Calendar.HOUR_OF_DAY, 0);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MINUTE, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+ return cal.getTimeInMillis();
+ }
+
+ /**
+ * 获取与给定时间等于时间差的时间戳
+ *
+ * @param millis 给定时间
+ * @param timeSpan 时间差的毫秒时间戳
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return 与给定时间等于时间差的时间戳
+ */
+ public static long getMillis(final long millis, final long timeSpan, @TimeConstants.Unit final int unit) {
+ return millis + timeSpan2Millis(timeSpan, unit);
+ }
+
+ /**
+ * 获取与给定时间等于时间差的时间戳
+ * time格式为yyyy-MM-dd HH:mm:ss
+ *
+ * @param time 给定时间
+ * @param timeSpan 时间差的毫秒时间戳
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return 与给定时间等于时间差的时间戳
+ */
+ public static long getMillis(final String time, final long timeSpan, @TimeConstants.Unit final int unit) {
+ return getMillis(time, DEFAULT_FORMAT, timeSpan, unit);
+ }
+
+ /**
+ * 获取与给定时间等于时间差的时间戳
+ * time格式为format
+ *
+ * @param time 给定时间
+ * @param format 时间格式
+ * @param timeSpan 时间差的毫秒时间戳
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return 与给定时间等于时间差的时间戳
+ */
+ public static long getMillis(final String time, final DateFormat format, final long timeSpan, @TimeConstants.Unit final int unit) {
+ return string2Millis(time, format) + timeSpan2Millis(timeSpan, unit);
+ }
+
+ /**
+ * 获取与给定时间等于时间差的时间戳
+ *
+ * @param date 给定时间
+ * @param timeSpan 时间差的毫秒时间戳
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return 与给定时间等于时间差的时间戳
+ */
+ public static long getMillis(final Date date, final long timeSpan, @TimeConstants.Unit final int unit) {
+ return date2Millis(date) + timeSpan2Millis(timeSpan, unit);
+ }
+
+ /**
+ * 获取与给定时间等于时间差的时间字符串
+ * 格式为yyyy-MM-dd HH:mm:ss
+ *
+ * @param millis 给定时间
+ * @param timeSpan 时间差的毫秒时间戳
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return 与给定时间等于时间差的时间字符串
+ */
+ public static String getString(final long millis, final long timeSpan, @TimeConstants.Unit final int unit) {
+ return getString(millis, DEFAULT_FORMAT, timeSpan, unit);
+ }
+
+ /**
+ * 获取与给定时间等于时间差的时间字符串
+ * 格式为format
+ *
+ * @param millis 给定时间
+ * @param format 时间格式
+ * @param timeSpan 时间差的毫秒时间戳
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return 与给定时间等于时间差的时间字符串
+ */
+ public static String getString(final long millis, final DateFormat format, final long timeSpan, @TimeConstants.Unit final int unit) {
+ return millis2String(millis + timeSpan2Millis(timeSpan, unit), format);
+ }
+
+ /**
+ * 获取与给定时间等于时间差的时间字符串
+ * time格式为yyyy-MM-dd HH:mm:ss
+ *
+ * @param time 给定时间
+ * @param timeSpan 时间差的毫秒时间戳
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return 与给定时间等于时间差的时间字符串
+ */
+ public static String getString(final String time, final long timeSpan, @TimeConstants.Unit final int unit) {
+ return getString(time, DEFAULT_FORMAT, timeSpan, unit);
+ }
+
+ /**
+ * 获取与给定时间等于时间差的时间字符串
+ * 格式为format
+ *
+ * @param time 给定时间
+ * @param format 时间格式
+ * @param timeSpan 时间差的毫秒时间戳
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return 与给定时间等于时间差的时间字符串
+ */
+ public static String getString(final String time, final DateFormat format, final long timeSpan, @TimeConstants.Unit final int unit) {
+ return millis2String(string2Millis(time, format) + timeSpan2Millis(timeSpan, unit), format);
+ }
+
+ /**
+ * 获取与给定时间等于时间差的时间字符串
+ * 格式为yyyy-MM-dd HH:mm:ss
+ *
+ * @param date 给定时间
+ * @param timeSpan 时间差的毫秒时间戳
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return 与给定时间等于时间差的时间字符串
+ */
+ public static String getString(final Date date, final long timeSpan, @TimeConstants.Unit final int unit) {
+ return getString(date, DEFAULT_FORMAT, timeSpan, unit);
+ }
+
+ /**
+ * 获取与给定时间等于时间差的时间字符串
+ * 格式为format
+ *
+ * @param date 给定时间
+ * @param format 时间格式
+ * @param timeSpan 时间差的毫秒时间戳
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return 与给定时间等于时间差的时间字符串
+ */
+ public static String getString(final Date date, final DateFormat format, final long timeSpan, @TimeConstants.Unit final int unit) {
+ return millis2String(date2Millis(date) + timeSpan2Millis(timeSpan, unit), format);
+ }
+
+ /**
+ * 获取与给定时间等于时间差的Date
+ *
+ * @param millis 给定时间
+ * @param timeSpan 时间差的毫秒时间戳
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return 与给定时间等于时间差的Date
+ */
+ public static Date getDate(final long millis, final long timeSpan, @TimeConstants.Unit final int unit) {
+ return millis2Date(millis + timeSpan2Millis(timeSpan, unit));
+ }
+
+ /**
+ * 获取与给定时间等于时间差的Date
+ * time格式为yyyy-MM-dd HH:mm:ss
+ *
+ * @param time 给定时间
+ * @param timeSpan 时间差的毫秒时间戳
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return 与给定时间等于时间差的Date
+ */
+ public static Date getDate(final String time, final long timeSpan, @TimeConstants.Unit final int unit) {
+ return getDate(time, DEFAULT_FORMAT, timeSpan, unit);
+ }
+
+ /**
+ * 获取与给定时间等于时间差的Date
+ * 格式为format
+ *
+ * @param time 给定时间
+ * @param format 时间格式
+ * @param timeSpan 时间差的毫秒时间戳
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return 与给定时间等于时间差的Date
+ */
+ public static Date getDate(final String time, final DateFormat format, final long timeSpan, @TimeConstants.Unit final int unit) {
+ return millis2Date(string2Millis(time, format) + timeSpan2Millis(timeSpan, unit));
+ }
+
+ /**
+ * 获取与给定时间等于时间差的Date
+ *
+ * @param date 给定时间
+ * @param timeSpan 时间差的毫秒时间戳
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return 与给定时间等于时间差的Date
+ */
+ public static Date getDate(final Date date, final long timeSpan, @TimeConstants.Unit final int unit) {
+ return millis2Date(date2Millis(date) + timeSpan2Millis(timeSpan, unit));
+ }
+
+ /**
+ * 获取与当前时间等于时间差的时间戳
+ *
+ * @param timeSpan 时间差的毫秒时间戳
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return 与当前时间等于时间差的时间戳
+ */
+ public static long getMillisByNow(final long timeSpan, @TimeConstants.Unit final int unit) {
+ return getMillis(getNowMills(), timeSpan, unit);
+ }
+
+ /**
+ * 获取与当前时间等于时间差的时间字符串
+ * 格式为yyyy-MM-dd HH:mm:ss
+ *
+ * @param timeSpan 时间差的毫秒时间戳
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return 与当前时间等于时间差的时间字符串
+ */
+ public static String getStringByNow(final long timeSpan, @TimeConstants.Unit final int unit) {
+ return getStringByNow(timeSpan, DEFAULT_FORMAT, unit);
+ }
+
+ /**
+ * 获取与当前时间等于时间差的时间字符串
+ * 格式为format
+ *
+ * @param timeSpan 时间差的毫秒时间戳
+ * @param format 时间格式
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return 与当前时间等于时间差的时间字符串
+ */
+ public static String getStringByNow(final long timeSpan, final DateFormat format, @TimeConstants.Unit final int unit) {
+ return getString(getNowMills(), format, timeSpan, unit);
+ }
+
+ /**
+ * 获取与当前时间等于时间差的Date
+ *
+ * @param timeSpan 时间差的毫秒时间戳
+ * @param unit 单位类型
+ *
+ * {@link TimeConstants#MSEC}: 毫秒
+ * {@link TimeConstants#SEC }: 秒
+ * {@link TimeConstants#MIN }: 分
+ * {@link TimeConstants#HOUR}: 小时
+ * {@link TimeConstants#DAY }: 天
+ *
+ * @return 与当前时间等于时间差的Date
+ */
+ public static Date getDateByNow(final long timeSpan, @TimeConstants.Unit final int unit) {
+ return getDate(getNowMills(), timeSpan, unit);
+ }
+
+ /**
+ * 判断是否今天
+ * time格式为yyyy-MM-dd HH:mm:ss
+ *
+ * @param time 时间字符串
+ * @return {@code true}: 是 {@code false}: 否
+ */
+ public static boolean isToday(final String time) {
+ return isToday(string2Millis(time, DEFAULT_FORMAT));
+ }
+
+ /**
+ * 判断是否今天
+ * time格式为format
+ *
+ * @param time 时间字符串
+ * @param format 时间格式
+ * @return {@code true}: 是 {@code false}: 否
+ */
+ public static boolean isToday(final String time, final DateFormat format) {
+ return isToday(string2Millis(time, format));
+ }
+
+ /**
+ * 判断是否今天
+ *
+ * @param date Date类型时间
+ * @return {@code true}: 是 {@code false}: 否
+ */
+ public static boolean isToday(final Date date) {
+ return isToday(date.getTime());
+ }
+
+ /**
+ * 判断是否今天
+ *
+ * @param millis 毫秒时间戳
+ * @return {@code true}: 是 {@code false}: 否
+ */
+ public static boolean isToday(final long millis) {
+ long wee = getWeeOfToday();
+ return millis >= wee && millis < wee + TimeConstants.DAY;
+ }
+
+ /**
+ * 判断是否闰年
+ * time格式为yyyy-MM-dd HH:mm:ss
+ *
+ * @param time 时间字符串
+ * @return {@code true}: 闰年 {@code false}: 平年
+ */
+ public static boolean isLeapYear(final String time) {
+ return isLeapYear(string2Date(time, DEFAULT_FORMAT));
+ }
+
+ /**
+ * 判断是否闰年
+ * time格式为format
+ *
+ * @param time 时间字符串
+ * @param format 时间格式
+ * @return {@code true}: 闰年 {@code false}: 平年
+ */
+ public static boolean isLeapYear(final String time, final DateFormat format) {
+ return isLeapYear(string2Date(time, format));
+ }
+
+ /**
+ * 判断是否闰年
+ *
+ * @param date Date类型时间
+ * @return {@code true}: 闰年 {@code false}: 平年
+ */
+ public static boolean isLeapYear(final Date date) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+ int year = cal.get(Calendar.YEAR);
+ return isLeapYear(year);
+ }
+
+ /**
+ * 判断是否闰年
+ *
+ * @param millis 毫秒时间戳
+ * @return {@code true}: 闰年 {@code false}: 平年
+ */
+ public static boolean isLeapYear(final long millis) {
+ return isLeapYear(millis2Date(millis));
+ }
+
+ /**
+ * 判断是否闰年
+ *
+ * @param year 年份
+ * @return {@code true}: 闰年 {@code false}: 平年
+ */
+ public static boolean isLeapYear(final int year) {
+ return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
+ }
+
+ /**
+ * 获取中式星期
+ * time格式为yyyy-MM-dd HH:mm:ss
+ *
+ * @param time 时间字符串
+ * @return 中式星期
+ */
+ public static String getChineseWeek(final String time) {
+ return getChineseWeek(string2Date(time, DEFAULT_FORMAT));
+ }
+
+ /**
+ * 获取当前中式时间
+ *
+ * @return
+ */
+ public static String getChineseNowWeek() {
+ return getChineseWeek(string2Date(getNowString(""), DEFAULT_FORMAT));
+ }
+
+ /**
+ * 获取中式星期
+ * time格式为format
+ *
+ * @param time 时间字符串
+ * @param format 时间格式
+ * @return 中式星期
+ */
+ public static String getChineseWeek(final String time, final DateFormat format) {
+ return getChineseWeek(string2Date(time, format));
+ }
+
+ /**
+ * 获取中式星期
+ *
+ * @param date Date类型时间
+ * @return 中式星期
+ */
+ public static String getChineseWeek(final Date date) {
+ return new SimpleDateFormat("E", Locale.CHINA).format(date);
+ }
+
+ /**
+ * 获取中式星期
+ *
+ * @param millis 毫秒时间戳
+ * @return 中式星期
+ */
+ public static String getChineseWeek(final long millis) {
+ return getChineseWeek(new Date(millis));
+ }
+
+ /**
+ * 获取美式星期
+ * time格式为yyyy-MM-dd HH:mm:ss
+ *
+ * @param time 时间字符串
+ * @return 美式星期
+ */
+ public static String getUSWeek(final String time) {
+ return getUSWeek(string2Date(time, DEFAULT_FORMAT));
+ }
+
+ /**
+ * 获取美式星期
+ * time格式为format
+ *
+ * @param time 时间字符串
+ * @param format 时间格式
+ * @return 美式星期
+ */
+ public static String getUSWeek(final String time, final DateFormat format) {
+ return getUSWeek(string2Date(time, format));
+ }
+
+ /**
+ * 获取美式星期
+ *
+ * @param date Date类型时间
+ * @return 美式星期
+ */
+ public static String getUSWeek(final Date date) {
+ return new SimpleDateFormat("EEEE", Locale.US).format(date);
+ }
+
+ /**
+ * 获取美式星期
+ *
+ * @param millis 毫秒时间戳
+ * @return 美式星期
+ */
+ public static String getUSWeek(final long millis) {
+ return getUSWeek(new Date(millis));
+ }
+
+ /**
+ * 获取星期索引
+ * 注意:周日的Index才是1,周六为7
+ * time格式为yyyy-MM-dd HH:mm:ss
+ *
+ * @param time 时间字符串
+ * @return 1...7
+ * @see Calendar#SUNDAY
+ * @see Calendar#MONDAY
+ * @see Calendar#TUESDAY
+ * @see Calendar#WEDNESDAY
+ * @see Calendar#THURSDAY
+ * @see Calendar#FRIDAY
+ * @see Calendar#SATURDAY
+ */
+ public static int getWeekIndex(final String time) {
+ return getWeekIndex(string2Date(time, DEFAULT_FORMAT));
+ }
+
+ /**
+ * 获取星期索引
+ * 注意:周日的Index才是1,周六为7
+ * time格式为format
+ *
+ * @param time 时间字符串
+ * @param format 时间格式
+ * @return 1...7
+ * @see Calendar#SUNDAY
+ * @see Calendar#MONDAY
+ * @see Calendar#TUESDAY
+ * @see Calendar#WEDNESDAY
+ * @see Calendar#THURSDAY
+ * @see Calendar#FRIDAY
+ * @see Calendar#SATURDAY
+ */
+ public static int getWeekIndex(final String time, final DateFormat format) {
+ return getWeekIndex(string2Date(time, format));
+ }
+
+ /**
+ * 获取星期索引
+ * 注意:周日的Index才是1,周六为7
+ *
+ * @param date Date类型时间
+ * @return 1...7
+ * @see Calendar#SUNDAY
+ * @see Calendar#MONDAY
+ * @see Calendar#TUESDAY
+ * @see Calendar#WEDNESDAY
+ * @see Calendar#THURSDAY
+ * @see Calendar#FRIDAY
+ * @see Calendar#SATURDAY
+ */
+ public static int getWeekIndex(final Date date) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+ return cal.get(Calendar.DAY_OF_WEEK);
+ }
+
+ /**
+ * 获取星期索引
+ * 注意:周日的Index才是1,周六为7
+ *
+ * @param millis 毫秒时间戳
+ * @return 1...7
+ * @see Calendar#SUNDAY
+ * @see Calendar#MONDAY
+ * @see Calendar#TUESDAY
+ * @see Calendar#WEDNESDAY
+ * @see Calendar#THURSDAY
+ * @see Calendar#FRIDAY
+ * @see Calendar#SATURDAY
+ */
+ public static int getWeekIndex(final long millis) {
+ return getWeekIndex(millis2Date(millis));
+ }
+
+ /**
+ * 获取月份中的第几周
+ * 注意:国外周日才是新的一周的开始
+ * time格式为yyyy-MM-dd HH:mm:ss
+ *
+ * @param time 时间字符串
+ * @return 1...5
+ */
+ public static int getWeekOfMonth(final String time) {
+ return getWeekOfMonth(string2Date(time, DEFAULT_FORMAT));
+ }
+
+ /**
+ * 获取月份中的第几周
+ * 注意:国外周日才是新的一周的开始
+ * time格式为format
+ *
+ * @param time 时间字符串
+ * @param format 时间格式
+ * @return 1...5
+ */
+ public static int getWeekOfMonth(final String time, final DateFormat format) {
+ return getWeekOfMonth(string2Date(time, format));
+ }
+
+ /**
+ * 获取月份中的第几周
+ * 注意:国外周日才是新的一周的开始
+ *
+ * @param date Date类型时间
+ * @return 1...5
+ */
+ public static int getWeekOfMonth(final Date date) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+ return cal.get(Calendar.WEEK_OF_MONTH);
+ }
+
+ /**
+ * 获取月份中的第几周
+ * 注意:国外周日才是新的一周的开始
+ *
+ * @param millis 毫秒时间戳
+ * @return 1...5
+ */
+ public static int getWeekOfMonth(final long millis) {
+ return getWeekOfMonth(millis2Date(millis));
+ }
+
+ /**
+ * 获取年份中的第几周
+ * 注意:国外周日才是新的一周的开始
+ * time格式为yyyy-MM-dd HH:mm:ss
+ *
+ * @param time 时间字符串
+ * @return 1...54
+ */
+ public static int getWeekOfYear(final String time) {
+ return getWeekOfYear(string2Date(time, DEFAULT_FORMAT));
+ }
+
+ /**
+ * 获取年份中的第几周
+ * 注意:国外周日才是新的一周的开始
+ * time格式为format
+ *
+ * @param time 时间字符串
+ * @param format 时间格式
+ * @return 1...54
+ */
+ public static int getWeekOfYear(final String time, final DateFormat format) {
+ return getWeekOfYear(string2Date(time, format));
+ }
+
+ /**
+ * 获取年份中的第几周
+ * 注意:国外周日才是新的一周的开始
+ *
+ * @param date Date类型时间
+ * @return 1...54
+ */
+ public static int getWeekOfYear(final Date date) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+ return cal.get(Calendar.WEEK_OF_YEAR);
+ }
+
+ /**
+ * 获取年份中的第几周
+ * 注意:国外周日才是新的一周的开始
+ *
+ * @param millis 毫秒时间戳
+ * @return 1...54
+ */
+ public static int getWeekOfYear(final long millis) {
+ return getWeekOfYear(millis2Date(millis));
+ }
+
+ private static final String[] CHINESE_ZODIAC = {"猴", "鸡", "狗", "猪", "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊"};
+
+ /**
+ * 获取生肖
+ * time格式为yyyy-MM-dd HH:mm:ss
+ *
+ * @param time 时间字符串
+ * @return 生肖
+ */
+ public static String getChineseZodiac(final String time) {
+ return getChineseZodiac(string2Date(time, DEFAULT_FORMAT));
+ }
+
+ /**
+ * 获取生肖
+ * time格式为format
+ *
+ * @param time 时间字符串
+ * @param format 时间格式
+ * @return 生肖
+ */
+ public static String getChineseZodiac(final String time, final DateFormat format) {
+ return getChineseZodiac(string2Date(time, format));
+ }
+
+ /**
+ * 获取生肖
+ *
+ * @param date Date类型时间
+ * @return 生肖
+ */
+ public static String getChineseZodiac(final Date date) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+ return CHINESE_ZODIAC[cal.get(Calendar.YEAR) % 12];
+ }
+
+ /**
+ * 获取生肖
+ *
+ * @param millis 毫秒时间戳
+ * @return 生肖
+ */
+ public static String getChineseZodiac(final long millis) {
+ return getChineseZodiac(millis2Date(millis));
+ }
+
+ /**
+ * 获取生肖
+ *
+ * @param year 年
+ * @return 生肖
+ */
+ public static String getChineseZodiac(final int year) {
+ return CHINESE_ZODIAC[year % 12];
+ }
+
+ private static final String[] ZODIAC = {"水瓶座", "双鱼座", "白羊座", "金牛座", "双子座", "巨蟹座", "狮子座", "处女座", "天秤座", "天蝎座", "射手座", "魔羯座"};
+ private static final int[] ZODIAC_FLAGS = {20, 19, 21, 21, 21, 22, 23, 23, 23, 24, 23, 22};
+
+ /**
+ * 获取星座
+ * time格式为yyyy-MM-dd HH:mm:ss
+ *
+ * @param time 时间字符串
+ * @return 生肖
+ */
+ public static String getZodiac(final String time) {
+ return getZodiac(string2Date(time, DEFAULT_FORMAT));
+ }
+
+ /**
+ * 获取星座
+ * time格式为format
+ *
+ * @param time 时间字符串
+ * @param format 时间格式
+ * @return 生肖
+ */
+ public static String getZodiac(final String time, final DateFormat format) {
+ return getZodiac(string2Date(time, format));
+ }
+
+ /**
+ * 获取星座
+ *
+ * @param date Date类型时间
+ * @return 星座
+ */
+ public static String getZodiac(final Date date) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime(date);
+ int month = cal.get(Calendar.MONTH) + 1;
+ int day = cal.get(Calendar.DAY_OF_MONTH);
+ return getZodiac(month, day);
+ }
+
+ /**
+ * 获取星座
+ *
+ * @param millis 毫秒时间戳
+ * @return 星座
+ */
+ public static String getZodiac(final long millis) {
+ return getZodiac(millis2Date(millis));
+ }
+
+ /**
+ * 获取星座
+ *
+ * @param month 月
+ * @param day 日
+ * @return 星座
+ */
+ public static String getZodiac(final int month, final int day) {
+ return ZODIAC[day >= ZODIAC_FLAGS[month - 1]
+ ? month - 1
+ : (month + 10) % 12];
+ }
+
+ private static long timeSpan2Millis(final long timeSpan, @TimeConstants.Unit final int unit) {
+ return timeSpan * unit;
+ }
+
+ private static long millis2TimeSpan(final long millis, @TimeConstants.Unit final int unit) {
+ return millis / unit;
+ }
+
+ public static String millis2FitTimeSpan(long millis, int precision) {
+ if (millis < 0 || precision <= 0) return null;
+ precision = Math.min(precision, 5);
+ String[] units = {"天", "时", "分", "秒", "毫秒"};
+ if (millis == 0) return 0 + units[precision - 1];
+ StringBuilder sb = new StringBuilder();
+ int[] unitLen = {86400000, 3600000, 60000, 1000, 1};
+ for (int i = 0; i < precision; i++) {
+ if (millis >= unitLen[i]) {
+ long mode = millis / unitLen[i];
+ millis -= mode * unitLen[i];
+ sb.append(mode).append(units[i]);
+ }
+ }
+ return sb.toString();
+ }
+
+
+ /**
+ * 比较时间大小
+ *
+ * @param nowDate
+ * @param compareDate
+ * @return
+ */
+ public static boolean compareDate(String nowDate, String compareDate) {
+ DateFormat df = DEFAULT_FORMAT;
+ try {
+ Date now = df.parse(nowDate);
+ Date compare = df.parse(compareDate);
+ if (now.after(compare)) {
+ return true;
+ } else {
+ return false;
+ }
+ } catch (ParseException e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * 比较时间大小
+ *
+ * @param nowDate
+ * @param compareDate
+ * @return
+ */
+ public static boolean compareDate(String nowDate, String compareDate,DateFormat format) {
+ DateFormat df = format;
+ try {
+ Date now = df.parse(nowDate);
+ Date compare = df.parse(compareDate);
+ if (now.after(compare)) {
+ return true;
+ } else {
+ return false;
+ }
+ } catch (ParseException e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimingX.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimingX.java
new file mode 100644
index 0000000..df631dc
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/TimingX.java
@@ -0,0 +1,145 @@
+package com.dahe.mylibrary.utils;
+
+import android.os.Handler;
+import android.os.Message;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+
+import io.reactivex.rxjava3.annotations.NonNull;
+
+public class TimingX {
+
+ private volatile static TimingX sTimingX;
+
+ private static int sSecond = 0, sStatus = TimingEnum.STOP.val;
+
+ private static final Handler sHandler = new TimingXHandler();
+
+ private static final ArrayList timingViews = new ArrayList<>(8);
+
+ private static String time = "";
+
+ private TimingX() {
+ }
+
+ public static TimingX builder(){
+ if(sTimingX == null){
+ synchronized (TimingX.class){
+ if(sTimingX == null){
+ sTimingX = new TimingX();
+ }
+ }
+ }
+ return sTimingX;
+ }
+
+ private static class TimingXHandler extends Handler {
+ @Override
+ public void handleMessage(@NonNull Message msg) {
+ int status = msg.what;
+ if (status == TimingEnum.START.val) {
+ sSecond += 1;
+ time = format(sSecond);
+ sHandler.sendEmptyMessageDelayed(status, 1000);
+ } else if (status == TimingEnum.STOP.val) {
+ time = format(sSecond);
+ }
+ showTime();
+ }
+ }
+
+ private static void showTime(){
+ for (TextView timingView : timingViews) {
+ timingView.setText(time);
+ }
+ }
+
+ public int getStatus(){
+ return sStatus;
+ }
+
+ enum TimingEnum {
+ STOP(0), // 停止计时
+ START(1), // 开始计时
+ CLEAR(-1); // 清除计时
+ int val;
+ TimingEnum(int val){
+ this.val = val;
+ }
+ }
+
+ /**
+ * 添加需要计时的 view
+ * @param view
+ * @return
+ */
+ public TimingX add(TextView view){
+ if(!timingViews.contains(view)){
+ timingViews.add(view);
+ }
+ return sTimingX;
+ }
+
+ /**
+ * 移除不需要计时的 view
+ * @param view
+ * @return
+ */
+ public TimingX remove(TextView view){
+ timingViews.remove(view);
+ return sTimingX;
+ }
+
+ /**
+ * 开始计时
+ */
+ public void start(){
+ if(sStatus == TimingEnum.STOP.val){
+ sStatus = TimingEnum.START.val;
+ sHandler.sendEmptyMessageDelayed(sStatus, 1000);
+ }
+ }
+
+ /**
+ * 停止计时
+ */
+ public void stop(){
+ if(sStatus == TimingEnum.START.val){
+ sStatus = TimingEnum.STOP.val;
+ sHandler.removeMessages(TimingEnum.START.val);
+ sHandler.sendEmptyMessage(sStatus);
+ }
+ }
+
+ /**
+ * 销毁 handler
+ */
+ public void destroy(){
+ sStatus = TimingEnum.STOP.val;
+ sSecond = 0;
+ sHandler.removeMessages(TimingEnum.START.val);
+ timingViews.clear();
+ }
+
+ /**
+ * 将秒转化为分秒的形式(00:00)
+ * @param second
+ * @return
+ */
+ public static String format(int second) {
+ StringBuilder sb = new StringBuilder();
+ int minutes = second / 60;
+ int sec = second % 60;
+ if(minutes < 10){
+ sb.append(0);
+ }
+ sb.append(minutes);
+ sb.append(":");
+ if(sec < 10){
+ sb.append(0);
+ }
+ sb.append(sec);
+ return sb.toString();
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/utils/ToastUtils.java b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ToastUtils.java
new file mode 100644
index 0000000..5b03d72
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/utils/ToastUtils.java
@@ -0,0 +1,37 @@
+package com.dahe.mylibrary.utils;
+
+import android.content.Context;
+import android.text.TextUtils;
+import android.widget.Toast;
+
+/**
+ * Created by Administrator on 2017/11/28 0028.
+ */
+
+public class ToastUtils {
+ public static Toast mToast = null;
+
+ public static void showToast(Context mContext, String message) {
+ if (!TextUtils.isEmpty(message)) {
+
+// if ( mToast != null) {
+// mToast.cancel();
+// }
+// mToast = Toast.makeText(mContext, message, Toast.LENGTH_SHORT);
+// mToast.show();
+
+ if (mToast == null) {
+ mToast = Toast.makeText(mContext, message, Toast.LENGTH_SHORT);
+ } else {
+ mToast.setText(message);
+ }
+ mToast.show();
+ }
+ }
+
+ public static void cancelToast(){
+ if (mToast!=null)
+ mToast.cancel();
+ }
+
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/wapper/SelectSimAdapter.java b/mylibrary/src/main/java/com/dahe/mylibrary/wapper/SelectSimAdapter.java
new file mode 100644
index 0000000..6302e3e
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/wapper/SelectSimAdapter.java
@@ -0,0 +1,37 @@
+package com.dahe.mylibrary.wapper;
+
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+
+import com.chad.library.adapter.base.BaseQuickAdapter;
+import com.chad.library.adapter.base.viewholder.BaseViewHolder;
+import com.dahe.mylibrary.R;
+
+import java.util.List;
+
+public class SelectSimAdapter extends BaseQuickAdapter {
+ private String selectString = "";
+
+
+ public SelectSimAdapter(int layoutResId, @Nullable List data, String selectString) {
+ super(R.layout.item_select, data);
+ this.selectString = selectString;
+ }
+
+ @Override
+ protected void convert(BaseViewHolder helper, String item) {
+ helper.setText(R.id.tv_content,item);
+ TextView tv = helper.getView(R.id.tv_content);
+ if (item.equals(selectString)){
+ tv.setSelected(true);
+ }else{
+ tv.setSelected(false);
+ }
+
+ }
+
+ public void setSelect(String selectString){
+ this.selectString = selectString;
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/AttachButton.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/AttachButton.java
new file mode 100644
index 0000000..6051134
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/AttachButton.java
@@ -0,0 +1,157 @@
+package com.dahe.mylibrary.weight;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.BounceInterpolator;
+
+import androidx.annotation.Nullable;
+
+import com.dahe.mylibrary.R;
+/**
+ * 自定义View实现拖动并自动吸边效果
+ *
+ * 处理滑动和贴边 {@link #onTouchEvent(MotionEvent)}
+ * 处理事件分发 {@link #dispatchTouchEvent(MotionEvent)}
+ *
+ *
+ * @attr customIsAttach //是否需要自动吸边
+ * @attr customIsDrag //是否可拖曳
+ */
+public class AttachButton extends View {
+ private float mLastRawX;
+ private float mLastRawY;
+ private final String TAG = "AttachButton";
+ private boolean isDrug = false;
+ private int mRootMeasuredWidth = 0;
+ private int mRootMeasuredHeight = 0;
+ private int mRootTopY = 0;
+ private boolean customIsAttach;
+ private boolean customIsDrag;
+
+ public AttachButton(Context context) {
+ this(context, null);
+ }
+
+ public AttachButton(Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public AttachButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ initAttrs(context, attrs);
+ }
+
+ /**
+ * 初始化自定义属性
+ */
+ private void initAttrs(Context context, AttributeSet attrs) {
+ TypedArray mTypedAttay = context.obtainStyledAttributes(attrs, R.styleable.AttachButton);
+ customIsAttach = mTypedAttay.getBoolean(R.styleable.AttachButton_customIsAttach, true);
+ customIsDrag = mTypedAttay.getBoolean(R.styleable.AttachButton_customIsDrag, true);
+ mTypedAttay.recycle();
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent event) {
+ super.dispatchTouchEvent(event);
+ return true;
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ //判断是否需要滑动
+ if (customIsDrag) {
+ //当前手指的坐标
+ float mRawX = ev.getRawX();
+ float mRawY = ev.getRawY();
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_DOWN://手指按下
+ isDrug = false;
+ //记录按下的位置
+ mLastRawX = mRawX;
+ mLastRawY = mRawY;
+ ViewGroup mViewGroup = (ViewGroup) getParent();
+ if (mViewGroup != null) {
+ int[] location = new int[2];
+ mViewGroup.getLocationInWindow(location);
+ //获取父布局的高度
+ mRootMeasuredHeight = mViewGroup.getMeasuredHeight();
+ mRootMeasuredWidth = mViewGroup.getMeasuredWidth();
+ //获取父布局顶点的坐标
+ mRootTopY = location[1];
+ }
+ break;
+ case MotionEvent.ACTION_MOVE://手指滑动
+ if (mRawX >= 0 && mRawX <= mRootMeasuredWidth && mRawY >= mRootTopY && mRawY <= (mRootMeasuredHeight + mRootTopY)) {
+ //手指X轴滑动距离
+ float differenceValueX = mRawX - mLastRawX;
+ //手指Y轴滑动距离
+ float differenceValueY = mRawY - mLastRawY;
+ //判断是否为拖动操作
+ if (!isDrug) {
+ if (Math.sqrt(differenceValueX * differenceValueX + differenceValueY * differenceValueY) < 2) {
+ isDrug = false;
+ } else {
+ isDrug = true;
+ }
+ }
+ //获取手指按下的距离与控件本身X轴的距离
+ float ownX = getX();
+ //获取手指按下的距离与控件本身Y轴的距离
+ float ownY = getY();
+ //理论中X轴拖动的距离
+ float endX = ownX + differenceValueX;
+ //理论中Y轴拖动的距离
+ float endY = ownY + differenceValueY;
+ //X轴可以拖动的最大距离
+ float maxX = mRootMeasuredWidth - getWidth();
+ //Y轴可以拖动的最大距离
+ float maxY = mRootMeasuredHeight - getHeight();
+ //X轴边界限制
+ endX = endX < 0 ? 0 : endX > maxX ? maxX : endX;
+ //Y轴边界限制
+ endY = endY < 0 ? 0 : endY > maxY ? maxY : endY;
+ //开始移动
+ setX(endX);
+ setY(endY);
+ //记录位置
+ mLastRawX = mRawX;
+ mLastRawY = mRawY;
+ }
+
+ break;
+ case MotionEvent.ACTION_UP://手指离开
+ //根据自定义属性判断是否需要贴边
+ if (customIsAttach) {
+ //判断是否为点击事件
+ if (isDrug) {
+ float center = mRootMeasuredWidth / 2;
+ //自动贴边
+ if (mLastRawX <= center) {
+ //向左贴边
+ AttachButton.this.animate()
+ .setInterpolator(new BounceInterpolator())
+ .setDuration(500)
+ .x(0)
+ .start();
+ } else {
+ //向右贴边
+ AttachButton.this.animate()
+ .setInterpolator(new BounceInterpolator())
+ .setDuration(500)
+ .x(mRootMeasuredWidth - getWidth())
+ .start();
+ }
+ }
+ }
+ break;
+ }
+ }
+ //是否拦截事件
+ return isDrug ? isDrug : super.onTouchEvent(ev);
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/FullyGridLayoutManager.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/FullyGridLayoutManager.java
new file mode 100644
index 0000000..ed6da0e
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/FullyGridLayoutManager.java
@@ -0,0 +1,104 @@
+package com.dahe.mylibrary.weight;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+/**
+ * author:luck
+ * project:PictureSelector
+ * package:com.luck.picture.ui
+ * email:893855882@qq.com
+ * data:16/12/31
+ */
+
+public class FullyGridLayoutManager extends GridLayoutManager {
+ public FullyGridLayoutManager(Context context, int spanCount) {
+ super(context, spanCount);
+ }
+
+ public FullyGridLayoutManager(Context context, int spanCount, int orientation, boolean reverseLayout) {
+ super(context, spanCount, orientation, reverseLayout);
+ }
+
+ private int[] mMeasuredDimension = new int[2];
+
+ @Override
+ public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
+ final int widthMode = View.MeasureSpec.getMode(widthSpec);
+ final int heightMode = View.MeasureSpec.getMode(heightSpec);
+ final int widthSize = View.MeasureSpec.getSize(widthSpec);
+ final int heightSize = View.MeasureSpec.getSize(heightSpec);
+
+ int width = 0;
+ int height = 0;
+ int count = getItemCount();
+ int span = getSpanCount();
+ for (int i = 0; i < count; i++) {
+ measureScrapChild(recycler, i,
+ View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
+ View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
+ mMeasuredDimension);
+
+ if (getOrientation() == HORIZONTAL) {
+ if (i % span == 0) {
+ width = width + mMeasuredDimension[0];
+ }
+ if (i == 0) {
+ height = mMeasuredDimension[1];
+ }
+ } else {
+ if (i % span == 0) {
+ height = height + mMeasuredDimension[1];
+ }
+ if (i == 0) {
+ width = mMeasuredDimension[0];
+ }
+ }
+ }
+
+ switch (widthMode) {
+ case View.MeasureSpec.EXACTLY:
+ width = widthSize;
+ case View.MeasureSpec.AT_MOST:
+ case View.MeasureSpec.UNSPECIFIED:
+ }
+
+ switch (heightMode) {
+ case View.MeasureSpec.EXACTLY:
+ height = heightSize;
+ case View.MeasureSpec.AT_MOST:
+ case View.MeasureSpec.UNSPECIFIED:
+ }
+
+ setMeasuredDimension(width, height);
+ }
+
+ final RecyclerView.State mState = new RecyclerView.State();
+
+ private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
+ int heightSpec, int[] measuredDimension) {
+ int itemCount = mState.getItemCount();
+ if (position < itemCount) {
+ try {
+ View view = recycler.getViewForPosition(0);
+ if (view != null) {
+ RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
+ int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
+ getPaddingLeft() + getPaddingRight(), p.width);
+ int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
+ getPaddingTop() + getPaddingBottom(), p.height);
+ view.measure(childWidthSpec, childHeightSpec);
+ measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;
+ measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;
+ recycler.recycleView(view);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/GlideCircleWithBorder.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/GlideCircleWithBorder.java
new file mode 100644
index 0000000..24f7cf3
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/GlideCircleWithBorder.java
@@ -0,0 +1,67 @@
+package com.dahe.mylibrary.weight;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+
+import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
+import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
+
+import java.security.MessageDigest;
+
+/**
+ * 加载圆形头像带白色边框
+ */
+public class GlideCircleWithBorder extends BitmapTransformation {
+ private Paint mBorderPaint;
+ private float mBorderWidth;
+
+ public GlideCircleWithBorder(Context context, int borderWidth, int borderColor) {
+ mBorderWidth = Resources.getSystem().getDisplayMetrics().density * borderWidth;
+ mBorderPaint = new Paint();
+ mBorderPaint.setDither(true);
+ mBorderPaint.setAntiAlias(true);
+ mBorderPaint.setColor(borderColor);
+ mBorderPaint.setStyle(Paint.Style.STROKE);
+ mBorderPaint.setStrokeWidth(mBorderWidth);
+ }
+
+ protected Bitmap transform(BitmapPool pool, Bitmap toTransform, int outWidth, int outHeight) {
+ return circleCrop(pool, toTransform);
+ }
+
+ private Bitmap circleCrop(BitmapPool pool, Bitmap source) {
+ if (source == null) {
+ return null;
+ }
+ int size = (int) (Math.min(source.getWidth(), source.getHeight()) - (mBorderWidth / 2));
+ int x = (source.getWidth() - size) / 2;
+ int y = (source.getHeight() - size) / 2;
+ Bitmap squared = Bitmap.createBitmap(source, x, y, size, size);
+ Bitmap result = pool.get(size, size, Bitmap.Config.ARGB_8888);
+ if (result == null) {
+ result = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
+ }
+ //创建画笔 画布 手动描绘边框
+ Canvas canvas = new Canvas(result);
+ Paint paint = new Paint();
+ paint.setShader(new BitmapShader(squared, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP));
+ paint.setAntiAlias(true);
+ float r = size / 2f;
+ canvas.drawCircle(r, r, r, paint);
+ if (mBorderPaint != null) {
+ float borderRadius = r - mBorderWidth / 2;
+ canvas.drawCircle(r, r, borderRadius, mBorderPaint);
+ }
+ return result;
+ }
+
+ @Override
+ public void updateDiskCacheKey(MessageDigest messageDigest) {
+
+ }
+
+}
\ No newline at end of file
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/GlideEngine.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/GlideEngine.java
new file mode 100644
index 0000000..e531d35
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/GlideEngine.java
@@ -0,0 +1,233 @@
+package com.dahe.mylibrary.weight;
+
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.PointF;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.widget.ImageView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.graphics.drawable.RoundedBitmapDrawable;
+import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.RequestOptions;
+import com.bumptech.glide.request.target.BitmapImageViewTarget;
+import com.bumptech.glide.request.target.ImageViewTarget;
+import com.dahe.mylibrary.R;
+import com.luck.picture.lib.engine.ImageEngine;
+import com.luck.picture.lib.listener.OnImageCompleteCallback;
+import com.luck.picture.lib.tools.MediaUtils;
+import com.luck.picture.lib.widget.longimage.ImageSource;
+import com.luck.picture.lib.widget.longimage.ImageViewState;
+import com.luck.picture.lib.widget.longimage.SubsamplingScaleImageView;
+
+/**
+ * @author:luck
+ * @date:2019-11-13 17:02
+ * @describe:Glide加载引擎
+ */
+public class GlideEngine implements ImageEngine {
+
+ /**
+ * 加载图片
+ *
+ * @param context
+ * @param url
+ * @param imageView
+ */
+ @Override
+ public void loadImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView) {
+ Glide.with(context)
+ .load(url)
+ .into(imageView);
+ }
+
+
+ /**
+ * 加载网络图片适配长图方案
+ * # 注意:此方法只有加载网络图片才会回调
+ *
+ * @param context
+ * @param url
+ * @param imageView
+ * @param longImageView
+ * @param callback 网络图片加载回调监听 {link after version 2.5.1 Please use the #OnImageCompleteCallback#}
+ */
+ @Override
+ public void loadImage(@NonNull Context context, @NonNull String url,
+ @NonNull final ImageView imageView,
+ final SubsamplingScaleImageView longImageView, final OnImageCompleteCallback callback) {
+ Glide.with(context)
+ .asBitmap()
+ .load(url)
+ .into(new ImageViewTarget(imageView) {
+ @Override
+ public void onLoadStarted(@Nullable Drawable placeholder) {
+ super.onLoadStarted(placeholder);
+ if (callback != null) {
+ callback.onShowLoading();
+ }
+ }
+
+ @Override
+ public void onLoadFailed(@Nullable Drawable errorDrawable) {
+ super.onLoadFailed(errorDrawable);
+ if (callback != null) {
+ callback.onHideLoading();
+ }
+ }
+
+ @Override
+ protected void setResource(@Nullable Bitmap resource) {
+ if (callback != null) {
+ callback.onHideLoading();
+ }
+ if (resource != null) {
+ boolean eqLongImage = MediaUtils.isLongImg(resource.getWidth(),
+ resource.getHeight());
+ longImageView.setVisibility(eqLongImage ? View.VISIBLE : View.GONE);
+ imageView.setVisibility(eqLongImage ? View.GONE : View.VISIBLE);
+ if (eqLongImage) {
+ // 加载长图
+ longImageView.setQuickScaleEnabled(true);
+ longImageView.setZoomEnabled(true);
+ longImageView.setDoubleTapZoomDuration(100);
+ longImageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_CROP);
+ longImageView.setDoubleTapZoomDpi(SubsamplingScaleImageView.ZOOM_FOCUS_CENTER);
+ longImageView.setImage(ImageSource.bitmap(resource),
+ new ImageViewState(0, new PointF(0, 0), 0));
+ } else {
+ // 普通图片
+ imageView.setImageBitmap(resource);
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * 加载网络图片适配长图方案
+ * # 注意:此方法只有加载网络图片才会回调
+ *
+ * @param context
+ * @param url
+ * @param imageView
+ * @param longImageView
+ * @ 已废弃
+ */
+ @Override
+ public void loadImage(@NonNull Context context, @NonNull String url,
+ @NonNull final ImageView imageView,
+ final SubsamplingScaleImageView longImageView) {
+ Glide.with(context)
+ .asBitmap()
+ .load(url)
+ .into(new ImageViewTarget(imageView) {
+ @Override
+ protected void setResource(@Nullable Bitmap resource) {
+ if (resource != null) {
+ boolean eqLongImage = MediaUtils.isLongImg(resource.getWidth(),
+ resource.getHeight());
+ longImageView.setVisibility(eqLongImage ? View.VISIBLE : View.GONE);
+ imageView.setVisibility(eqLongImage ? View.GONE : View.VISIBLE);
+ if (eqLongImage) {
+ // 加载长图
+ longImageView.setQuickScaleEnabled(true);
+ longImageView.setZoomEnabled(true);
+ longImageView.setDoubleTapZoomDuration(100);
+ longImageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_CROP);
+ longImageView.setDoubleTapZoomDpi(SubsamplingScaleImageView.ZOOM_FOCUS_CENTER);
+ longImageView.setImage(ImageSource.bitmap(resource),
+ new ImageViewState(0, new PointF(0, 0), 0));
+ } else {
+ // 普通图片
+ imageView.setImageBitmap(resource);
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * 加载相册目录
+ *
+ * @param context 上下文
+ * @param url 图片路径
+ * @param imageView 承载图片ImageView
+ */
+ @Override
+ public void loadFolderImage(@NonNull final Context context, @NonNull String url, @NonNull final ImageView imageView) {
+ Glide.with(context)
+ .asBitmap()
+ .load(url)
+ .override(180, 180)
+ .centerCrop()
+ .sizeMultiplier(0.5f)
+ .apply(new RequestOptions().placeholder(R.drawable.picture_image_placeholder))
+ .into(new BitmapImageViewTarget(imageView) {
+ @Override
+ protected void setResource(Bitmap resource) {
+ RoundedBitmapDrawable circularBitmapDrawable =
+ RoundedBitmapDrawableFactory.
+ create(context.getResources(), resource);
+ circularBitmapDrawable.setCornerRadius(8);
+ imageView.setImageDrawable(circularBitmapDrawable);
+ }
+ });
+ }
+
+
+ /**
+ * 加载gif
+ *
+ * @param context 上下文
+ * @param url 图片路径
+ * @param imageView 承载图片ImageView
+ */
+ @Override
+ public void loadAsGifImage(@NonNull Context context, @NonNull String url,
+ @NonNull ImageView imageView) {
+ Glide.with(context)
+ .asGif()
+ .load(url)
+ .into(imageView);
+ }
+
+ /**
+ * 加载图片列表图片
+ *
+ * @param context 上下文
+ * @param url 图片路径
+ * @param imageView 承载图片ImageView
+ */
+ @Override
+ public void loadGridImage(@NonNull Context context, @NonNull String url, @NonNull ImageView imageView) {
+ Glide.with(context)
+ .load(url)
+ .override(200, 200)
+ .centerCrop()
+ .apply(new RequestOptions().placeholder(R.drawable.picture_image_placeholder))
+ .into(imageView);
+ }
+
+
+ private GlideEngine() {
+ }
+
+ private static GlideEngine instance;
+
+ public static GlideEngine createGlideEngine() {
+ if (null == instance) {
+ synchronized (GlideEngine.class) {
+ if (null == instance) {
+ instance = new GlideEngine();
+ }
+ }
+ }
+ return instance;
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/GridSectionAverageGapItemDecoration.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/GridSectionAverageGapItemDecoration.java
new file mode 100644
index 0000000..6fa5c4b
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/GridSectionAverageGapItemDecoration.java
@@ -0,0 +1,231 @@
+package com.dahe.mylibrary.weight;
+
+import android.graphics.Rect;
+import android.os.Build;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+import androidx.recyclerview.widget.GridLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.chad.library.adapter.base.BaseSectionQuickAdapter;
+import com.chad.library.adapter.base.entity.SectionEntity;
+import com.chad.library.adapter.base.viewholder.BaseViewHolder;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 应用于RecyclerView的GridLayoutManager,水平方向上固定间距大小,从而使条目宽度自适应。
+ * 配合Brvah的Section使用,不对Head生效,仅对每个Head的子Grid列表生效
+ * Section Grid中Item的宽度应设为MATCH_PARAENT
+ *
+ * @author : renpeng
+ * @since : 2018/9/29
+ */
+public class GridSectionAverageGapItemDecoration extends RecyclerView.ItemDecoration {
+
+ private class Section {
+ public int startPos = 0;
+ public int endPos = 0;
+
+ public int getCount() {
+ return endPos - startPos + 1;
+ }
+
+ public boolean contains(int pos) {
+ return pos >= startPos && pos <= endPos;
+ }
+
+ @Override
+ public String toString() {
+ return "Section{" +
+ "startPos=" + startPos +
+ ", endPos=" + endPos +
+ '}';
+ }
+ }
+
+ private float gapHorizontalDp;
+ private float gapVerticalDp;
+ private float sectionEdgeHPaddingDp;
+ private float sectionEdgeVPaddingDp;
+ private int gapHSizePx = -1;
+ private int gapVSizePx = -1;
+ private int sectionEdgeHPaddingPx;
+ private int eachItemHPaddingPx; //每个条目应该在水平方向上加的padding 总大小,即=paddingLeft+paddingRight
+ private int sectionEdgeVPaddingPx;
+ private List mSectionList = new ArrayList<>();
+ private BaseSectionQuickAdapter mAdapter;
+ private RecyclerView.AdapterDataObserver mDataObserver = new RecyclerView.AdapterDataObserver() {
+ @Override
+ public void onChanged() {
+ markSections();
+ }
+
+ @Override
+ public void onItemRangeChanged(int positionStart, int itemCount) {
+ markSections();
+ }
+
+ @Override
+ public void onItemRangeChanged(int positionStart, int itemCount, @Nullable Object payload) {
+ markSections();
+ }
+
+ @Override
+ public void onItemRangeInserted(int positionStart, int itemCount) {
+ markSections();
+ }
+
+ @Override
+ public void onItemRangeRemoved(int positionStart, int itemCount) {
+ markSections();
+ }
+
+ @Override
+ public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
+ markSections();
+ }
+ };
+
+
+ /**
+ * @param gapHorizontalDp item之间的水平间距
+ * @param gapVerticalDp item之间的垂直间距
+ * @param sectionEdgeHPaddingDp section左右两端的padding大小
+ * @param sectionEdgeVPaddingDp section上下两端的padding大小
+ */
+ public GridSectionAverageGapItemDecoration(float gapHorizontalDp, float gapVerticalDp, float sectionEdgeHPaddingDp, float sectionEdgeVPaddingDp) {
+ this.gapHorizontalDp = gapHorizontalDp;
+ this.gapVerticalDp = gapVerticalDp;
+ this.sectionEdgeHPaddingDp = sectionEdgeHPaddingDp;
+ this.sectionEdgeVPaddingDp = sectionEdgeVPaddingDp;
+ }
+
+ @Override
+ public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
+ if (parent.getLayoutManager() instanceof GridLayoutManager && parent.getAdapter() instanceof BaseSectionQuickAdapter) {
+ GridLayoutManager layoutManager = (GridLayoutManager) parent.getLayoutManager();
+ BaseSectionQuickAdapter adapter = (BaseSectionQuickAdapter) parent.getAdapter();
+ if (mAdapter != adapter) {
+ setUpWithAdapter(adapter);
+ }
+ int spanCount = layoutManager.getSpanCount();
+ int position = parent.getChildAdapterPosition(view) - mAdapter.getHeaderLayoutCount();
+ SectionEntity entity = adapter.getItem(position);
+
+ if (entity == null || entity.isHeader()) {
+ //不处理header
+ outRect.set(0, 0, 0, 0);
+// Log.w("GridAverageGapItem", "pos=" + position + "," + outRect.toShortString());
+ return;
+ }
+
+ Section section = findSectionLastItemPos(position);
+
+ if (gapHSizePx < 0 || gapVSizePx < 0) {
+ transformGapDefinition(parent, spanCount);
+ }
+ outRect.top = gapVSizePx;
+ outRect.bottom = 0;
+
+ //下面的visualPos为单个Section内的视觉Pos
+ int visualPos = position + 1 - section.startPos;
+ if (visualPos % spanCount == 1) {
+ //第一列
+ outRect.left = sectionEdgeHPaddingPx;
+ outRect.right = eachItemHPaddingPx - sectionEdgeHPaddingPx;
+ } else if (visualPos % spanCount == 0) {
+ //最后一列
+ outRect.left = eachItemHPaddingPx - sectionEdgeHPaddingPx;
+ outRect.right = sectionEdgeHPaddingPx;
+ } else {
+ outRect.left = gapHSizePx - (eachItemHPaddingPx - sectionEdgeHPaddingPx);
+ outRect.right = eachItemHPaddingPx - outRect.left;
+ }
+
+ if (visualPos - spanCount <= 0) {
+ //第一行
+ outRect.top = sectionEdgeVPaddingPx;
+ }
+
+ if (isLastRow(visualPos, spanCount, section.getCount())) {
+ //最后一行
+ outRect.bottom = sectionEdgeVPaddingPx;
+// Log.w("GridAverageGapItem", "last row pos=" + position);
+ }
+// Log.w("GridAverageGapItem", "pos=" + position + ",vPos=" + visualPos + "," + outRect.toShortString());
+ } else {
+ super.getItemOffsets(outRect, view, parent, state);
+ }
+ }
+
+ private void setUpWithAdapter(BaseSectionQuickAdapter adapter) {
+ if (mAdapter != null) {
+ mAdapter.unregisterAdapterDataObserver(mDataObserver);
+ }
+ mAdapter = adapter;
+ mAdapter.registerAdapterDataObserver(mDataObserver);
+ markSections();
+ }
+
+ private void markSections() {
+ if (mAdapter != null) {
+ BaseSectionQuickAdapter adapter = mAdapter;
+ mSectionList.clear();
+ SectionEntity sectionEntity = null;
+ Section section = new Section();
+ for (int i = 0, size = adapter.getItemCount(); i < size; i++) {
+ sectionEntity = adapter.getItem(i);
+ if (sectionEntity != null && sectionEntity.isHeader()) {
+ //找到新Section起点
+ if (section != null && i != 0) {
+ //已经有待添加的section
+ section.endPos = i - 1;
+ mSectionList.add(section);
+ }
+ section = new Section();
+ section.startPos = i + 1;
+ } else {
+ section.endPos = i;
+ }
+ }
+ //处理末尾情况
+ if (!mSectionList.contains(section)) {
+ mSectionList.add(section);
+ }
+
+// Log.w("GridAverageGapItem", "section list=" + mSectionList);
+ }
+ }
+
+ private void transformGapDefinition(RecyclerView parent, int spanCount) {
+ DisplayMetrics displayMetrics = new DisplayMetrics();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ parent.getDisplay().getMetrics(displayMetrics);
+ }
+ gapHSizePx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, gapHorizontalDp, displayMetrics);
+ gapVSizePx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, gapVerticalDp, displayMetrics);
+ sectionEdgeHPaddingPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, sectionEdgeHPaddingDp, displayMetrics);
+ sectionEdgeVPaddingPx = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, sectionEdgeVPaddingDp, displayMetrics);
+ eachItemHPaddingPx = (sectionEdgeHPaddingPx * 2 + gapHSizePx * (spanCount - 1)) / spanCount;
+ }
+
+ private Section findSectionLastItemPos(int curPos) {
+ for (Section section : mSectionList) {
+ if (section.contains(curPos)) {
+ return section;
+ }
+ }
+ return null;
+ }
+
+ private boolean isLastRow(int visualPos, int spanCount, int sectionItemCount) {
+ int lastRowCount = sectionItemCount % spanCount;
+ lastRowCount = lastRowCount == 0 ? spanCount : lastRowCount;
+ return visualPos > sectionItemCount - lastRowCount;
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/MovedImageButton.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/MovedImageButton.java
new file mode 100644
index 0000000..841f073
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/MovedImageButton.java
@@ -0,0 +1,93 @@
+package com.dahe.mylibrary.weight;
+
+import android.animation.ObjectAnimator;
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.view.MotionEvent;
+import android.view.animation.OvershootInterpolator;
+import android.widget.ImageButton;
+
+import com.dahe.mylibrary.utils.BaseUtils;
+
+public class MovedImageButton extends androidx.appcompat.widget.AppCompatImageButton {
+ private int lastX;
+ private int lastY;
+ private float screenWidth;
+
+ public MovedImageButton(Context context) {
+ super(context);
+ }
+
+ public MovedImageButton(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public MovedImageButton(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ DisplayMetrics dm = getResources().getDisplayMetrics();
+ screenWidth = dm.widthPixels;
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ }
+
+ @SuppressLint("ClickableViewAccessibility")
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ int x = (int) event.getX();
+ int y = (int) event.getY();
+ switch (event.getAction()){
+ case MotionEvent.ACTION_DOWN:
+ lastX = x;
+ lastY = y;
+ break;
+ case MotionEvent.ACTION_MOVE:
+ int offsetX = x-lastX;
+ int offsetY = y-lastY;
+ //第一种方法
+// layout(getLeft()+offsetX,
+// getTop()+offsetY,
+// getRight()+offsetX,
+// getBottom()+offsetY);
+ //第二种方法
+ offsetLeftAndRight(offsetX);
+ offsetTopAndBottom(offsetY);
+ break;
+ case MotionEvent.ACTION_UP:
+ adsorbAnim(event.getRawX(), event.getRawY());
+ break;
+ }
+ return super.onTouchEvent(event);
+ }
+
+ private void adsorbAnim(float rawX, float rawY){
+ //靠顶吸附
+// if (rawY <= BaseUtils.dip2px(getContext(),200)){//注意rawY包含了标题栏的高
+// animate().setDuration(400)
+// .setInterpolator(new OvershootInterpolator())
+// .yBy(-getY()-getHeight()/2.0f)
+// .start();
+// }else
+
+ if (rawX >= screenWidth/2){//靠右吸附
+ animate().setDuration(400)
+ .setInterpolator(new OvershootInterpolator())
+ .xBy(screenWidth - getX() - getWidth())
+ .start();
+ }else {//靠左吸附
+ ObjectAnimator animator = ObjectAnimator.ofFloat(this, "x", getX(), 0);
+ animator.setInterpolator(new OvershootInterpolator());
+ animator.setDuration(400);
+ animator.start();
+ }
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/MySlideBar.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/MySlideBar.java
new file mode 100644
index 0000000..7bd8b59
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/MySlideBar.java
@@ -0,0 +1,191 @@
+package com.dahe.mylibrary.weight;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+
+import com.dahe.mylibrary.R;
+import com.dahe.mylibrary.utils.ToastUtils;
+
+public class MySlideBar extends RelativeLayout implements View.OnClickListener {
+
+ private boolean canSelect;
+ private TextView tvT1;
+ private TextView tvT2;
+ private TextView tvT3;
+ private TextView tvT4;
+ private TextView tvC1;
+ private TextView tvC2;
+ private TextView tvC3;
+ private TextView tvC4;
+ private View view1;
+ private View view2;
+
+ public MySlideBar(Context context) {
+ this(context, null);
+ }
+
+ public MySlideBar(Context context, @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public MySlideBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, 0, 0);
+ }
+
+ public MySlideBar(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ init(context, attrs);
+
+
+ }
+
+ private void init(Context context, AttributeSet attrs) {
+ View inflate = View.inflate(context, R.layout.view_slide_bar, this);
+ tvT1 = (TextView) findViewById(R.id.tv_title1);
+ tvT2 = (TextView) findViewById(R.id.tv_title2);
+ tvT3 = (TextView) findViewById(R.id.tv_title3);
+ tvT4 = (TextView) findViewById(R.id.tv_title4);
+ tvC1 = (TextView) findViewById(R.id.tv_conten1);
+ tvC2 = (TextView) findViewById(R.id.tv_content2);
+ tvC3 = (TextView) findViewById(R.id.tv_content3);
+ tvC4 = (TextView) findViewById(R.id.tv_content4);
+ view1 = (View) findViewById(R.id.view1);
+ view2 = (View) findViewById(R.id.view2);
+ LinearLayout ll1 = (LinearLayout) findViewById(R.id.ll1);
+ LinearLayout ll2 = (LinearLayout) findViewById(R.id.ll2);
+ LinearLayout ll3 = (LinearLayout) findViewById(R.id.ll3);
+ LinearLayout ll4 = (LinearLayout) findViewById(R.id.ll4);
+ ll1.setOnClickListener(this);
+ ll2.setOnClickListener(this);
+ ll3.setOnClickListener(this);
+ ll4.setOnClickListener(this);
+
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MySlideBar);
+ int integer = a.getInteger(R.styleable.MySlideBar_proress, -1);
+ canSelect = a.getBoolean(R.styleable.MySlideBar_canSelect, false);
+ changeProress(integer,true);
+
+ a.recycle();
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (canSelect) {
+ int id = v.getId();
+ if (id == R.id.ll1) {
+ changeProress(0,canSelect);
+ } else if (id == R.id.ll2) {
+ changeProress(1,canSelect);
+ } else if (id == R.id.ll3) {
+ changeProress(2,canSelect);
+ } else if (id == R.id.ll4) {
+ changeProress(3,canSelect);
+ }
+ }
+
+ }
+
+ public void setProress(int proress){
+ changeProress(proress,canSelect);
+ }
+
+ private void changeProress(int integer,boolean canSelect){
+ if (listener!=null&&canSelect){
+ listener.onChange(integer);
+ }
+ if (0 == integer) {
+ tvT1.setBackgroundResource(R.drawable.select_slide_title);
+ tvT2.setBackgroundResource(R.drawable.select_slide_title);
+ tvT3.setBackgroundResource(R.drawable.select_slide_title);
+ tvT4.setBackgroundResource(R.drawable.select_slide_title);
+ tvT1.setText("1");
+ tvT2.setText("2");
+ tvT3.setText("3");
+ tvT4.setText("4");
+ tvT1.setSelected(true);
+ tvT2.setSelected(false);
+ tvT3.setSelected(false);
+ tvT4.setSelected(false);
+
+ view1.setBackgroundResource(R.color.color_d5);
+ view2.setBackgroundResource(R.color.color_d5);
+
+ tvC1.setTextColor(getResources().getColor(R.color.mine_top_bg));
+ tvC2.setTextColor(getResources().getColor(R.color.color_9));
+ tvC3.setTextColor(getResources().getColor(R.color.color_9));
+ tvC4.setTextColor(getResources().getColor(R.color.color_9));
+ } else if (1 == integer) {
+ tvT1.setBackgroundResource(R.drawable.ok);
+ tvT2.setBackgroundResource(R.drawable.select_slide_title);
+ tvT3.setBackgroundResource(R.drawable.select_slide_title);
+ tvT4.setBackgroundResource(R.drawable.select_slide_title);
+ tvT1.setText("");
+ tvT2.setText("2");
+ tvT3.setText("3");
+ tvT4.setText("4");
+ tvT2.setSelected(true);
+ tvT3.setSelected(false);
+ tvT4.setSelected(false);
+
+ view1.setBackgroundResource(R.color.mine_top_bg);
+ view2.setBackgroundResource(R.color.color_d5);
+
+ tvC1.setTextColor(getResources().getColor(R.color.black));
+ tvC2.setTextColor(getResources().getColor(R.color.mine_top_bg));
+ tvC3.setTextColor(getResources().getColor(R.color.color_9));
+ tvC4.setTextColor(getResources().getColor(R.color.color_9));
+ } else if (2 == integer) {
+ tvT1.setBackgroundResource(R.drawable.ok);
+ tvT2.setBackgroundResource(R.drawable.ok);
+ tvT3.setBackgroundResource(R.drawable.select_slide_title);
+ tvT4.setBackgroundResource(R.drawable.select_slide_title);
+ tvT1.setText("");
+ tvT2.setText("");
+ tvT3.setText("3");
+ tvT4.setText("4");
+ tvT3.setSelected(true);
+ tvT4.setSelected(false);
+
+ view1.setBackgroundResource(R.color.mine_top_bg);
+ view2.setBackgroundResource(R.color.mine_top_bg);
+
+ tvC1.setTextColor(getResources().getColor(R.color.black));
+ tvC2.setTextColor(getResources().getColor(R.color.black));
+ tvC3.setTextColor(getResources().getColor(R.color.mine_top_bg));
+ tvC4.setTextColor(getResources().getColor(R.color.color_9));
+ } else if (3 == integer) {
+ tvT1.setBackgroundResource(R.drawable.ok);
+ tvT2.setBackgroundResource(R.drawable.ok);
+ tvT3.setBackgroundResource(R.drawable.ok);
+ tvT4.setBackgroundResource(R.drawable.select_slide_title);
+ tvT1.setText("");
+ tvT2.setText("");
+ tvT3.setText("");
+ tvT4.setText("4");
+ tvT4.setSelected(true);
+
+ tvC1.setTextColor(getResources().getColor(R.color.black));
+ tvC2.setTextColor(getResources().getColor(R.color.black));
+ tvC3.setTextColor(getResources().getColor(R.color.black));
+ tvC4.setTextColor(getResources().getColor(R.color.mine_top_bg));
+ }
+ }
+
+
+ public interface OnChangeListener{
+ void onChange(int progress);
+ }
+
+ private OnChangeListener listener;
+ public void setOnChangeListener(OnChangeListener listener){
+ this.listener = listener;
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/SideBar.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/SideBar.java
new file mode 100644
index 0000000..1b1e471
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/SideBar.java
@@ -0,0 +1,130 @@
+package com.dahe.mylibrary.weight;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Vibrator;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.TextView;
+
+import com.dahe.mylibrary.R;
+
+public class SideBar extends View {
+ // 触摸事件
+ private OnTouchingLetterChangedListener onTouchingLetterChangedListener;
+ public static String[] b = { "A", "B", "C", "D", "E", "F", "G", "H", "I",
+ "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
+ "W", "X", "Y", "Z", "#" };
+ private int choose = -1;
+ private Paint paint = new Paint();
+
+ private TextView mTextDialog;
+
+ /**
+ * 为SideBar设置显示字母的TextView
+ * @param textDialog
+ */
+ public void setTextView(TextView textDialog) {
+ this.mTextDialog = textDialog;
+ }
+
+
+ public SideBar(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ public SideBar(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public SideBar(Context context) {
+ super(context);
+ }
+
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ int height = getHeight();
+ int width = getWidth();
+ int singleHeight = height / b.length;// 获取每一个字母的高度
+
+ for (int i = 0; i < b.length; i++) {
+ paint.setColor(Color.rgb(33, 65, 98));
+ // paint.setColor(Color.WHITE);
+ paint.setTypeface(Typeface.DEFAULT_BOLD);
+ paint.setAntiAlias(true);
+ paint.setTextSize(20);
+ if (i == choose) {// 选中的状态
+ paint.setColor(Color.parseColor("#999999"));
+ paint.setFakeBoldText(true);
+ }
+ // x坐标等于中间-字符串宽度的一半
+ float xPos = width / 2 - paint.measureText(b[i]) / 2;
+ float yPos = singleHeight * i + singleHeight;
+ canvas.drawText(b[i], xPos, yPos, paint);
+ paint.reset();
+ }
+
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent event) {
+ final int action = event.getAction();
+ final float y = event.getY();
+ final int oldChoose = choose;
+ final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener;
+ final int c = (int) (y / getHeight() * b.length);// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数
+
+ switch (action) {
+ case MotionEvent.ACTION_UP:
+ setBackground(new ColorDrawable(0x00000000));
+ choose = -1;//
+ invalidate();
+ if (mTextDialog != null) {
+ mTextDialog.setVisibility(View.INVISIBLE);
+ }
+ break;
+
+ default:
+// setBackgroundResource(R.drawable.sidebar_background);
+ if (oldChoose != c) {
+ if (c >= 0 && c < b.length) {
+ if (listener != null) {
+ listener.onTouchingLetterChanged(b[c]);
+ }
+ if (mTextDialog != null) {
+ mTextDialog.setText(b[c]);
+ mTextDialog.setVisibility(View.VISIBLE);
+ }
+
+ choose = c;
+ invalidate();
+ }
+ }
+
+ break;
+ }
+ return true;
+ }
+
+ /**
+ * 触摸事件
+ * @param onTouchingLetterChangedListener
+ */
+ public void setOnTouchingLetterChangedListener(
+ OnTouchingLetterChangedListener onTouchingLetterChangedListener) {
+ this.onTouchingLetterChangedListener = onTouchingLetterChangedListener;
+ }
+
+ /**
+ * 回调接口
+ */
+ public interface OnTouchingLetterChangedListener {
+ void onTouchingLetterChanged(String s);
+ }
+
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/SwitchView.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/SwitchView.java
new file mode 100644
index 0000000..93fbb50
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/SwitchView.java
@@ -0,0 +1,508 @@
+package com.dahe.mylibrary.weight;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.RadialGradient;
+import android.graphics.RectF;
+import android.graphics.Shader;
+import android.os.Build;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.animation.AccelerateInterpolator;
+
+import com.dahe.mylibrary.R;
+
+
+/**
+ * hei hei hei
+ */
+public class SwitchView extends View {
+
+ private static final int STATE_SWITCH_ON = 4;
+ private static final int STATE_SWITCH_ON2 = 3;
+ private static final int STATE_SWITCH_OFF2 = 2;
+ private static final int STATE_SWITCH_OFF = 1;
+
+ private final AccelerateInterpolator interpolator = new AccelerateInterpolator(2);
+ private final Paint paint = new Paint();
+ private final Path sPath = new Path();
+ private final Path bPath = new Path();
+ private final RectF bRectF = new RectF();
+ private float sAnim, bAnim;
+ private RadialGradient shadowGradient;
+
+ protected float ratioAspect = 0.68f; // (0,1]
+ protected float animationSpeed = 0.1f; // (0,1]
+
+ private int state;
+ private int lastState;
+ private boolean isCanVisibleDrawing = false;
+ private OnClickListener mOnClickListener;
+ protected int colorPrimary;
+ protected int colorPrimaryDark;
+ protected int colorOff;
+ protected int colorOffDark;
+ protected int colorShadow;
+ protected boolean hasShadow;
+ protected boolean isOpened;
+ protected boolean canEnable;
+
+ private float sRight;
+ private float sCenterX, sCenterY;
+ private float sScale;
+
+ private float bOffset;
+ private float bRadius, bStrokeWidth;
+ private float bWidth;
+ private float bLeft;
+ private float bRight;
+ private float bOnLeftX, bOn2LeftX, bOff2LeftX, bOffLeftX;
+
+ private float shadowReservedHeight;
+
+ public SwitchView(Context context) {
+ this(context, null);
+ }
+
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB)
+ public SwitchView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setLayerType(LAYER_TYPE_SOFTWARE, null);
+
+ final int DEFAULT_COLOR_PRIMARY = 0xFF4BD763;
+ final int DEFAULT_COLOR_PRIMARY_DARK = 0xFF3AC652;
+
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SwitchView);
+ colorPrimary = a.getColor(R.styleable.SwitchView_primaryColor, DEFAULT_COLOR_PRIMARY);
+ colorPrimaryDark = a.getColor(R.styleable.SwitchView_primaryColorDark, DEFAULT_COLOR_PRIMARY_DARK);
+ colorOff = a.getColor(R.styleable.SwitchView_offColor, 0xFFE3E3E3);
+ colorOffDark = a.getColor(R.styleable.SwitchView_offColorDark, 0xFFBFBFBF);
+ colorShadow = a.getColor(R.styleable.SwitchView_shadowColor, 0xFF333333);
+ ratioAspect = a.getFloat(R.styleable.SwitchView_ratioAspect, 0.68f);
+ hasShadow = a.getBoolean(R.styleable.SwitchView_hasShadow, true);
+ isOpened = a.getBoolean(R.styleable.SwitchView_isOpened, false);
+ canEnable = a.getBoolean(R.styleable.SwitchView_canEnable, true);
+ state = isOpened ? STATE_SWITCH_ON : STATE_SWITCH_OFF;
+ lastState = state;
+ a.recycle();
+
+ if (colorPrimary == DEFAULT_COLOR_PRIMARY && colorPrimaryDark == DEFAULT_COLOR_PRIMARY_DARK) {
+ try {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ TypedValue primaryColorTypedValue = new TypedValue();
+ context.getTheme().resolveAttribute(android.R.attr.colorPrimary, primaryColorTypedValue, true);
+ if (primaryColorTypedValue.data > 0) colorPrimary = primaryColorTypedValue.data;
+ TypedValue primaryColorDarkTypedValue = new TypedValue();
+ context.getTheme().resolveAttribute(android.R.attr.colorPrimaryDark, primaryColorDarkTypedValue, true);
+ if (primaryColorDarkTypedValue.data > 0)
+ colorPrimaryDark = primaryColorDarkTypedValue.data;
+ }
+ } catch (Exception ignore) {
+ }
+ }
+ }
+
+ public void setColor(int newColorPrimary, int newColorPrimaryDark) {
+ setColor(newColorPrimary, newColorPrimaryDark, colorOff, colorOffDark);
+ }
+
+ public void setColor(int newColorPrimary, int newColorPrimaryDark, int newColorOff, int newColorOffDark) {
+ setColor(newColorPrimary, newColorPrimaryDark, newColorOff, newColorOffDark, colorShadow);
+ }
+
+ public void setColor(int newColorPrimary, int newColorPrimaryDark, int newColorOff, int newColorOffDark, int newColorShadow) {
+ colorPrimary = newColorPrimary;
+ colorPrimaryDark = newColorPrimaryDark;
+ colorOff = newColorOff;
+ colorOffDark = newColorOffDark;
+ colorShadow = newColorShadow;
+ invalidate();
+ }
+
+ public void setCanEnable(boolean canEnable){
+ this.canEnable = canEnable;
+ invalidate();
+ }
+
+ public void setShadow(boolean shadow) {
+ hasShadow = shadow;
+ invalidate();
+ }
+
+ public boolean isOpened() {
+ return isOpened;
+ }
+
+ public void setOpened(boolean isOpened) {
+ int wishState = isOpened ? STATE_SWITCH_ON : STATE_SWITCH_OFF;
+ if (wishState == state) {
+ return;
+ }
+ refreshState(wishState);
+ }
+
+ public void toggleSwitch(boolean isOpened) {
+ int wishState = isOpened ? STATE_SWITCH_ON : STATE_SWITCH_OFF;
+ if (wishState == state) {
+ return;
+ }
+ if ((wishState == STATE_SWITCH_ON && (state == STATE_SWITCH_OFF || state == STATE_SWITCH_OFF2))
+ || (wishState == STATE_SWITCH_OFF && (state == STATE_SWITCH_ON || state == STATE_SWITCH_ON2))) {
+ sAnim = 1;
+ }
+ bAnim = 1;
+ refreshState(wishState);
+ }
+
+ private void refreshState(int newState) {
+ if (!isOpened && newState == STATE_SWITCH_ON) {
+ isOpened = true;
+ } else if (isOpened && newState == STATE_SWITCH_OFF) {
+ isOpened = false;
+ }
+ lastState = state;
+ state = newState;
+ postInvalidate();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+ int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ int resultWidth;
+ if (widthMode == MeasureSpec.EXACTLY) {
+ resultWidth = widthSize;
+ } else {
+ resultWidth = (int) (56 * getResources().getDisplayMetrics().density + 0.5f)
+ + getPaddingLeft() + getPaddingRight();
+ if (widthMode == MeasureSpec.AT_MOST) {
+ resultWidth = Math.min(resultWidth, widthSize);
+ }
+ }
+
+ int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+ int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+ int resultHeight;
+ if (heightMode == MeasureSpec.EXACTLY) {
+ resultHeight = heightSize;
+ } else {
+ resultHeight = (int) (resultWidth * ratioAspect) + getPaddingTop() + getPaddingBottom();
+ if (heightMode == MeasureSpec.AT_MOST) {
+ resultHeight = Math.min(resultHeight, heightSize);
+ }
+ }
+ setMeasuredDimension(resultWidth, resultHeight);
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+ super.onSizeChanged(w, h, oldw, oldh);
+
+ isCanVisibleDrawing = w > getPaddingLeft() + getPaddingRight() && h > getPaddingTop() + getPaddingBottom();
+
+ if (isCanVisibleDrawing) {
+ int actuallyDrawingAreaWidth = w - getPaddingLeft() - getPaddingRight();
+ int actuallyDrawingAreaHeight = h - getPaddingTop() - getPaddingBottom();
+
+ int actuallyDrawingAreaLeft;
+ int actuallyDrawingAreaRight;
+ int actuallyDrawingAreaTop;
+ int actuallyDrawingAreaBottom;
+ if (actuallyDrawingAreaWidth * ratioAspect < actuallyDrawingAreaHeight) {
+ actuallyDrawingAreaLeft = getPaddingLeft();
+ actuallyDrawingAreaRight = w - getPaddingRight();
+ int heightExtraSize = (int) (actuallyDrawingAreaHeight - actuallyDrawingAreaWidth * ratioAspect);
+ actuallyDrawingAreaTop = getPaddingTop() + heightExtraSize / 2;
+ actuallyDrawingAreaBottom = getHeight() - getPaddingBottom() - heightExtraSize / 2;
+ } else {
+ int widthExtraSize = (int) (actuallyDrawingAreaWidth - actuallyDrawingAreaHeight / ratioAspect);
+ actuallyDrawingAreaLeft = getPaddingLeft() + widthExtraSize / 2;
+ actuallyDrawingAreaRight = getWidth() - getPaddingRight() - widthExtraSize / 2;
+ actuallyDrawingAreaTop = getPaddingTop();
+ actuallyDrawingAreaBottom = getHeight() - getPaddingBottom();
+ }
+
+ shadowReservedHeight = (int) ((actuallyDrawingAreaBottom - actuallyDrawingAreaTop) * 0.07f);
+ float sLeft = actuallyDrawingAreaLeft;
+ float sTop = actuallyDrawingAreaTop + shadowReservedHeight;
+ sRight = actuallyDrawingAreaRight;
+ float sBottom = actuallyDrawingAreaBottom - shadowReservedHeight;
+
+ float sHeight = sBottom - sTop;
+ sCenterX = (sRight + sLeft) / 2;
+ sCenterY = (sBottom + sTop) / 2;
+
+ bLeft = sLeft;
+ bWidth = sBottom - sTop;
+ bRight = sLeft + bWidth;
+ final float halfHeightOfS = bWidth / 2; // OfB
+ bRadius = halfHeightOfS * 0.95f;
+ bOffset = bRadius * 0.2f; // offset of switching
+ bStrokeWidth = (halfHeightOfS - bRadius) * 2;
+ bOnLeftX = sRight - bWidth;
+ bOn2LeftX = bOnLeftX - bOffset;
+ bOffLeftX = sLeft;
+ bOff2LeftX = bOffLeftX + bOffset;
+ sScale = 1 - bStrokeWidth / sHeight;
+
+ sPath.reset();
+ RectF sRectF = new RectF();
+ sRectF.top = sTop;
+ sRectF.bottom = sBottom;
+ sRectF.left = sLeft;
+ sRectF.right = sLeft + sHeight;
+ sPath.arcTo(sRectF, 90, 180);
+ sRectF.left = sRight - sHeight;
+ sRectF.right = sRight;
+ sPath.arcTo(sRectF, 270, 180);
+ sPath.close();
+
+ bRectF.left = bLeft;
+ bRectF.right = bRight;
+ bRectF.top = sTop + bStrokeWidth / 2; // bTop = sTop
+ bRectF.bottom = sBottom - bStrokeWidth / 2; // bBottom = sBottom
+ float bCenterX = (bRight + bLeft) / 2;
+ float bCenterY = (sBottom + sTop) / 2;
+
+ int red = colorShadow >> 16 & 0xFF;
+ int green = colorShadow >> 8 & 0xFF;
+ int blue = colorShadow & 0xFF;
+ shadowGradient = new RadialGradient(bCenterX, bCenterY, bRadius, Color.argb(200, red, green, blue),
+ Color.argb(25, red, green, blue), Shader.TileMode.CLAMP);
+ }
+ }
+
+ private void calcBPath(float percent) {
+ bPath.reset();
+ bRectF.left = bLeft + bStrokeWidth / 2;
+ bRectF.right = bRight - bStrokeWidth / 2;
+ bPath.arcTo(bRectF, 90, 180);
+ bRectF.left = bLeft + percent * bOffset + bStrokeWidth / 2;
+ bRectF.right = bRight + percent * bOffset - bStrokeWidth / 2;
+ bPath.arcTo(bRectF, 270, 180);
+ bPath.close();
+ }
+
+ private float calcBTranslate(float percent) {
+ float result = 0;
+ switch (state - lastState) {
+ case 1:
+ if (state == STATE_SWITCH_OFF2) {
+ result = bOffLeftX; // off -> off2
+ } else if (state == STATE_SWITCH_ON) {
+ result = bOnLeftX - (bOnLeftX - bOn2LeftX) * percent; // on2 -> on
+ }
+ break;
+ case 2:
+ if (state == STATE_SWITCH_ON) {
+ result = bOnLeftX - (bOnLeftX - bOffLeftX) * percent; // off2 -> on
+ } else if (state == STATE_SWITCH_ON2) {
+ result = bOn2LeftX - (bOn2LeftX - bOffLeftX) * percent; // off -> on2
+ }
+ break;
+ case 3:
+ result = bOnLeftX - (bOnLeftX - bOffLeftX) * percent; // off -> on
+ break;
+ case -1:
+ if (state == STATE_SWITCH_ON2) {
+ result = bOn2LeftX + (bOnLeftX - bOn2LeftX) * percent; // on -> on2
+ } else if (state == STATE_SWITCH_OFF) {
+ result = bOffLeftX; // off2 -> off
+ }
+ break;
+ case -2:
+ if (state == STATE_SWITCH_OFF) {
+ result = bOffLeftX + (bOn2LeftX - bOffLeftX) * percent; // on2 -> off
+ } else if (state == STATE_SWITCH_OFF2) {
+ result = bOff2LeftX + (bOnLeftX - bOff2LeftX) * percent; // on -> off2
+ }
+ break;
+ case -3:
+ result = bOffLeftX + (bOnLeftX - bOffLeftX) * percent; // on -> off
+ break;
+ default: // init
+ case 0:
+ if (state == STATE_SWITCH_OFF) {
+ result = bOffLeftX; // off -> off
+ } else if (state == STATE_SWITCH_ON) {
+ result = bOnLeftX; // on -> on
+ }
+ break;
+ }
+ return result - bOffLeftX;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ if (!isCanVisibleDrawing) return;
+
+ paint.setAntiAlias(true);
+ final boolean isOn = (state == STATE_SWITCH_ON || state == STATE_SWITCH_ON2);
+ // Draw background
+ paint.setStyle(Paint.Style.FILL);
+ paint.setColor(isOn ? colorPrimary : colorOff);
+ canvas.drawPath(sPath, paint);
+
+ sAnim = sAnim - animationSpeed > 0 ? sAnim - animationSpeed : 0;
+ bAnim = bAnim - animationSpeed > 0 ? bAnim - animationSpeed : 0;
+
+ final float dsAnim = interpolator.getInterpolation(sAnim);
+ final float dbAnim = interpolator.getInterpolation(bAnim);
+ // Draw background animation
+ final float scale = sScale * (isOn ? dsAnim : 1 - dsAnim);
+ final float scaleOffset = (sRight - sCenterX - bRadius) * (isOn ? 1 - dsAnim : dsAnim);
+ canvas.save();
+ canvas.scale(scale, scale, sCenterX + scaleOffset, sCenterY);
+ paint.setColor(0xFFFFFFFF);
+ canvas.drawPath(sPath, paint);
+ canvas.restore();
+ // To prepare center bar path
+ canvas.save();
+ canvas.translate(calcBTranslate(dbAnim), shadowReservedHeight);
+ final boolean isState2 = (state == STATE_SWITCH_ON2 || state == STATE_SWITCH_OFF2);
+ calcBPath(isState2 ? 1 - dbAnim : dbAnim);
+ // Use center bar path to draw shadow
+ if (hasShadow) {
+ paint.setStyle(Paint.Style.FILL);
+ paint.setShader(shadowGradient);
+ canvas.drawPath(bPath, paint);
+ paint.setShader(null);
+ }
+ canvas.translate(0, -shadowReservedHeight);
+ // draw bar
+ canvas.scale(0.98f, 0.98f, bWidth / 2, bWidth / 2);
+ paint.setStyle(Paint.Style.FILL);
+ paint.setColor(0xffffffff);
+ canvas.drawPath(bPath, paint);
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setStrokeWidth(bStrokeWidth * 0.5f);
+ paint.setColor(isOn ? colorPrimaryDark : colorOffDark);
+ canvas.drawPath(bPath, paint);
+ canvas.restore();
+
+ paint.reset();
+ if (sAnim > 0 || bAnim > 0) invalidate();
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (!canEnable)
+ return super.onTouchEvent(event);
+ if ((state == STATE_SWITCH_ON || state == STATE_SWITCH_OFF) && (sAnim * bAnim == 0)) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ return true;
+ case MotionEvent.ACTION_UP:
+ lastState = state;
+
+ bAnim = 1;
+ if (state == STATE_SWITCH_OFF) {
+ refreshState(STATE_SWITCH_OFF2);
+ listener.toggleToOn(this);
+ } else if (state == STATE_SWITCH_ON) {
+ refreshState(STATE_SWITCH_ON2);
+ listener.toggleToOff(this);
+ }
+
+ if (mOnClickListener != null) {
+ mOnClickListener.onClick(this);
+ }
+ break;
+ }
+ }
+ return super.onTouchEvent(event);
+ }
+
+ @Override
+ public void setOnClickListener(OnClickListener l) {
+ super.setOnClickListener(l);
+ mOnClickListener = l;
+ }
+
+ public interface OnStateChangedListener {
+ void toggleToOn(SwitchView view);
+
+ void toggleToOff(SwitchView view);
+ }
+
+ private OnStateChangedListener listener = new OnStateChangedListener() {
+ @Override
+ public void toggleToOn(SwitchView view) {
+ toggleSwitch(true);
+ }
+
+ @Override
+ public void toggleToOff(SwitchView view) {
+ toggleSwitch(false);
+ }
+ };
+
+ public void setOnStateChangedListener(OnStateChangedListener listener) {
+ if (listener == null) throw new IllegalArgumentException("empty listener");
+ this.listener = listener;
+ }
+
+ @Override
+ public Parcelable onSaveInstanceState() {
+ Parcelable superState = super.onSaveInstanceState();
+ SavedState ss = new SavedState(superState);
+ ss.isOpened = isOpened;
+ return ss;
+ }
+
+ @Override
+ public void onRestoreInstanceState(Parcelable state) {
+ SavedState ss = (SavedState) state;
+ super.onRestoreInstanceState(ss.getSuperState());
+ this.isOpened = ss.isOpened;
+ this.state = this.isOpened ? STATE_SWITCH_ON : STATE_SWITCH_OFF;
+ invalidate();
+ }
+
+ private static final class SavedState extends BaseSavedState {
+ private boolean isOpened;
+
+ SavedState(Parcelable superState) {
+ super(superState);
+ }
+
+ private SavedState(Parcel in) {
+ super(in);
+ isOpened = 1 == in.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ super.writeToParcel(out, flags);
+ out.writeInt(isOpened ? 1 : 0);
+ }
+
+ // fixed by Night99 https://github.com/g19980115
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+
+ @Override
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/segmentcontrol/RadiusDrawable.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/segmentcontrol/RadiusDrawable.java
new file mode 100644
index 0000000..2569625
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/segmentcontrol/RadiusDrawable.java
@@ -0,0 +1,139 @@
+package com.dahe.mylibrary.weight.segmentcontrol;
+
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PixelFormat;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+
+// 圆角 Drawable 每个角的圆半径可以不同 (使用不同半径圆角图形的时候 使用这个类 以防止 系统提供的用 xml 实现的圆角 Drawable 在2.3 上 出现各个角位置错乱)
+
+/**
+ * Created by caifangmao on 15/4/22.
+ */
+public class RadiusDrawable extends Drawable {
+
+ private int topLeftRadius;
+ private int topRightRadius;
+ private int bottomLeftRadius;
+ private int bottomRightRadius;
+
+ private int left;
+ private int top;
+ private int right;
+ private int bottom;
+
+ private final Paint paint;
+ private final boolean isStroke;
+ private int strokeWidth = 0;
+ private int strokeColor = Color.CYAN;
+ private int fillColor;
+
+ private Path path;
+
+ public RadiusDrawable(boolean isStroke) {
+ this(0, isStroke);
+ }
+
+ public RadiusDrawable(int radius, boolean isStroke) {
+ setRadius(radius);
+
+ paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ this.isStroke = isStroke;
+ }
+
+ public void setStrokeWidth(int width) {
+ strokeWidth = width;
+ setBounds(left, top, right, bottom);
+ }
+
+ public void setStrokeColor(int strokeColor) {
+ this.strokeColor = strokeColor;
+ }
+
+ public void setFillColor(int fillColor) {
+ this.fillColor = fillColor;
+ }
+
+ public void setRadius(int radius) {
+ this.topLeftRadius = this.topRightRadius = this.bottomLeftRadius = this.bottomRightRadius = radius;
+ }
+
+ public void setRadius(int topLeftRadius, int topRightRadius, int bottomLeftRadius, int bottomRightRadius) {
+ this.topLeftRadius = topLeftRadius;
+ this.topRightRadius = topRightRadius;
+ this.bottomLeftRadius = bottomLeftRadius;
+ this.bottomRightRadius = bottomRightRadius;
+ }
+
+ @Override
+ public void setBounds(int left, int top, int right, int bottom) {
+ super.setBounds(left, top, right, bottom);
+
+ this.left = left;
+ this.top = top;
+ this.right = right;
+ this.bottom = bottom;
+
+ if (isStroke) {
+ int halfStrokeWidth = strokeWidth / 2;
+ left += halfStrokeWidth;
+ top += halfStrokeWidth;
+ right -= halfStrokeWidth;
+ bottom -= halfStrokeWidth;
+ }
+
+ path = new Path();
+ path.moveTo(left + topLeftRadius, top);
+ path.lineTo(right - topRightRadius, top);
+ path.arcTo(new RectF(right - topRightRadius * 2, top, right, top + topRightRadius * 2),
+ -90, 90);
+ // path.quadTo(right, top, right, top + topRightRadius);
+ path.lineTo(right, bottom - bottomRightRadius);
+ path.arcTo(new RectF(right - bottomRightRadius * 2, bottom - bottomRightRadius * 2, right,
+ bottom), 0, 90);
+ // path.quadTo(right, bottom, right - bottomRightRadius, bottom);
+ path.lineTo(left + bottomLeftRadius, bottom);
+ path.arcTo(new RectF(left, bottom - bottomLeftRadius * 2, left + bottomLeftRadius * 2,
+ bottom), 90, 90);
+ // path.quadTo(left, bottom, left, bottom - bottomLeftRadius);
+ path.lineTo(left, top + topLeftRadius);
+ path.arcTo(new RectF(left, top, left + topLeftRadius * 2, top + topLeftRadius * 2), 180, 90);
+ // path.quadTo(left, top, left + topLeftRadius, top);
+ path.close();
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ if (fillColor != 0) {
+ paint.setColor(fillColor);
+ paint.setStyle(Paint.Style.FILL);
+ canvas.drawPath(path, paint);
+ }
+
+ if (strokeWidth > 0) {
+ paint.setColor(strokeColor);
+ paint.setStyle(Paint.Style.STROKE);
+ paint.setStrokeJoin(Paint.Join.MITER);
+ paint.setStrokeWidth(strokeWidth);
+ canvas.drawPath(path, paint);
+ }
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter cf) {
+ }
+
+ @Override
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
+ }
+}
diff --git a/mylibrary/src/main/java/com/dahe/mylibrary/weight/segmentcontrol/SegmentControl.java b/mylibrary/src/main/java/com/dahe/mylibrary/weight/segmentcontrol/SegmentControl.java
new file mode 100644
index 0000000..a5bf65d
--- /dev/null
+++ b/mylibrary/src/main/java/com/dahe/mylibrary/weight/segmentcontrol/SegmentControl.java
@@ -0,0 +1,526 @@
+package com.dahe.mylibrary.weight.segmentcontrol;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+
+import com.dahe.mylibrary.R;
+
+
+/**
+ * Created by 7heaven on 15/4/22.
+ */
+public class SegmentControl extends View {
+
+ private String[] mTexts;
+ private Rect[] mCacheBounds;
+ private Rect[] mTextBounds;
+
+ private RadiusDrawable mBackgroundDrawable;
+ private RadiusDrawable mSelectedDrawable;
+
+ private int mCurrentIndex;
+
+ private int mTouchSlop;
+ private boolean inTapRegion;
+ private float mStartX;
+ private float mStartY;
+ private float mCurrentX;
+ private float mCurrentY;
+
+ private int mHorizonGap;
+ private int mVerticalGap;
+
+ /** 外边框的width */
+ private int mBoundWidth = 4;
+ /** 内边框的width */
+ private int mSeparatorWidth = mBoundWidth / 2;
+
+ private int mSingleChildWidth;
+ private int mSingleChildHeight;
+
+ private Paint mPaint;
+
+ private int mTextSize;
+ private ColorStateList mBackgroundColors;
+ private ColorStateList mTextColors;
+ private int mCornerRadius;
+
+ private int DEFAULT_SELECTED_COLOR = 0xFF32ADFF;
+ private int DEFAULT_NORMAL_COLOR = 0xFFFFFFFF;
+
+ private Paint.FontMetrics mCachedFM;
+
+ public enum Direction {
+ HORIZONTAL(0), VERTICAL(1);
+
+ int value;
+
+ Direction(int v) {
+ value = v;
+ }
+ }
+
+ private Direction mDirection;
+
+ public SegmentControl(Context context) {
+ this(context, null);
+ }
+
+ public SegmentControl(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public SegmentControl(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SegmentControl);
+
+ String textArray = ta.getString(R.styleable.SegmentControl_texts);
+ if (textArray != null) {
+ mTexts = textArray.split("\\|");
+ }
+
+ mTextSize = ta.getDimensionPixelSize(R.styleable.SegmentControl_android_textSize, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 14, context.getResources().getDisplayMetrics()));
+ mCornerRadius = ta.getDimensionPixelSize(R.styleable.SegmentControl_cornerRadius, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 5, context.getResources().getDisplayMetrics()));
+ mDirection = Direction.values()[ta.getInt(R.styleable.SegmentControl_android_orientation, 0)];
+
+ mHorizonGap = ta.getDimensionPixelSize(R.styleable.SegmentControl_horizonGap, 0);
+ mVerticalGap = ta.getDimensionPixelSize(R.styleable.SegmentControl_verticalGap, 0);
+
+ int gap = ta.getDimensionPixelSize(R.styleable.SegmentControl_gaps, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, context.getResources().getDisplayMetrics()));
+
+ if(mHorizonGap == 0) {
+ mHorizonGap = gap;
+ }
+ if(mVerticalGap == 0) {
+ mVerticalGap = gap;
+ }
+
+ mBackgroundDrawable = new RadiusDrawable(mCornerRadius, true);
+ mBackgroundDrawable.setStrokeWidth(2);
+
+ DEFAULT_NORMAL_COLOR = ta.getColor(R.styleable.SegmentControl_normalColor, DEFAULT_NORMAL_COLOR);
+ DEFAULT_SELECTED_COLOR = ta.getColor(R.styleable.SegmentControl_selectedColor, DEFAULT_SELECTED_COLOR);
+
+ mBackgroundColors = ta.getColorStateList(R.styleable.SegmentControl_backgroundColors);
+ mTextColors = ta.getColorStateList(R.styleable.SegmentControl_textColors);
+ if (mBackgroundColors == null) {
+ mBackgroundColors = new ColorStateList(new int[][]{{android.R.attr.state_selected}, {-android.R.attr.state_selected}}, new int[]{DEFAULT_SELECTED_COLOR, DEFAULT_NORMAL_COLOR});
+ }
+
+ if(mTextColors == null){
+ mTextColors = new ColorStateList(new int[][]{{android.R.attr.state_selected}, {-android.R.attr.state_selected}}, new int[]{DEFAULT_NORMAL_COLOR, DEFAULT_SELECTED_COLOR});
+ }
+
+ mBoundWidth = ta.getDimensionPixelSize(R.styleable.SegmentControl_boundWidth, mBoundWidth);
+ mSeparatorWidth = ta.getDimensionPixelSize(R.styleable.SegmentControl_separatorWidth, mSeparatorWidth);
+
+ ta.recycle();
+
+ mBackgroundDrawable = new RadiusDrawable(mCornerRadius, true);
+ mBackgroundDrawable.setStrokeWidth(mBoundWidth);
+ mBackgroundDrawable.setStrokeColor(getSelectedBGColor());
+ mBackgroundDrawable.setFillColor(getNormalBGColor());
+
+ if (Build.VERSION.SDK_INT < 16) {
+ setBackgroundDrawable(mBackgroundDrawable);
+ } else {
+ setBackground(mBackgroundDrawable);
+ }
+
+ mSelectedDrawable = new RadiusDrawable(false);
+ mSelectedDrawable.setFillColor(getSelectedBGColor());
+
+ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mPaint.setTextSize(mTextSize);
+ mCachedFM = mPaint.getFontMetrics();
+
+ int touchSlop = 0;
+ if (context == null) {
+ touchSlop = ViewConfiguration.getTouchSlop();
+ } else {
+ final ViewConfiguration config = ViewConfiguration.get(context);
+ touchSlop = config.getScaledTouchSlop();
+ }
+ mTouchSlop = touchSlop * touchSlop;
+ inTapRegion = false;
+ }
+
+ public void setText(String... texts) {
+ mTexts = texts;
+ if (mTexts != null) {
+ requestLayout();
+ }
+ }
+
+ /**
+ * 设置文字颜色
+ *
+ * @param color 需要设置的颜色
+ */
+ public void setSelectedTextColors(ColorStateList color) {
+ mTextColors = color;
+ invalidate();
+ }
+
+ /**
+ * 设置背景颜色
+ *
+ * @param colors 颜色
+ */
+ public void setColors(ColorStateList colors) {
+ mBackgroundColors = colors;
+
+ if (mBackgroundDrawable != null) {
+ mBackgroundDrawable.setStrokeColor(getSelectedBGColor());
+ mBackgroundDrawable.setFillColor(getNormalBGColor());
+ }
+
+ if (mSelectedDrawable != null) {
+ mSelectedDrawable.setFillColor(getSelectedBGColor());
+ }
+
+ invalidate();
+ }
+
+ public void setCornerRadius(int cornerRadius) {
+ mCornerRadius = cornerRadius;
+
+ if (mBackgroundDrawable != null) {
+ mBackgroundDrawable.setRadius(cornerRadius);
+ }
+
+ invalidate();
+ }
+
+ public void setDirection(Direction direction) {
+ Direction tDirection = mDirection;
+
+ mDirection = direction;
+
+ if (tDirection != direction) {
+ requestLayout();
+ invalidate();
+ }
+ }
+
+ public void setTextSize(int textSize_sp) {
+ setTextSize(TypedValue.COMPLEX_UNIT_SP, textSize_sp);
+ }
+
+ public void setTextSize(int unit, int textSize) {
+ mPaint.setTextSize((int) (TypedValue.applyDimension(unit, textSize, getContext().getResources().getDisplayMetrics())));
+
+ if (textSize != mTextSize) {
+ mTextSize = textSize;
+ mCachedFM = mPaint.getFontMetrics();
+
+ requestLayout();
+ }
+ }
+
+ public void setSelectedIndex(int index) {
+ mCurrentIndex = index;
+
+ if(mOnSegmentControlClickListener != null) {
+ mOnSegmentControlClickListener.onSegmentControlClick(index);
+ }
+
+ invalidate();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+
+ int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+ int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+
+ int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+ int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+
+ int width = 0;
+ int height = 0;
+
+ if (mTexts != null && mTexts.length > 0) {
+
+ mSingleChildHeight = 0;
+ mSingleChildWidth = 0;
+
+ if (mCacheBounds == null || mCacheBounds.length != mTexts.length) {
+ mCacheBounds = new Rect[mTexts.length];
+ }
+
+ if (mTextBounds == null || mTextBounds.length != mTexts.length) {
+ mTextBounds = new Rect[mTexts.length];
+ }
+
+ for (int i = 0; i < mTexts.length; i++) {
+ String text = mTexts[i];
+
+ if(text != null){
+
+ if(mTextBounds[i] == null) {
+ mTextBounds[i] = new Rect();
+ }
+
+ mPaint.getTextBounds(text, 0, text.length(), mTextBounds[i]);
+
+ if(mSingleChildWidth < mTextBounds[i].width() + mHorizonGap * 2) {
+ mSingleChildWidth = mTextBounds[i].width() + mHorizonGap * 2;
+ }
+ if(mSingleChildHeight < mTextBounds[i].height() + mVerticalGap * 2) {
+ mSingleChildHeight = mTextBounds[i].height() + mVerticalGap * 2;
+ }
+ }
+ }
+
+ switch (widthMode) {
+ case MeasureSpec.AT_MOST:
+ if (mDirection == Direction.HORIZONTAL) {
+ if (widthSize <= mSingleChildWidth * mTexts.length) {
+ mSingleChildWidth = widthSize / mTexts.length;
+ width = widthSize;
+ } else {
+ width = mSingleChildWidth * mTexts.length;
+ }
+ } else {
+ width = widthSize <= mSingleChildWidth ? widthSize : mSingleChildWidth;
+ }
+ break;
+ case MeasureSpec.EXACTLY:
+ width = widthSize;
+ break;
+ case MeasureSpec.UNSPECIFIED:
+ default:
+ if (mDirection == Direction.HORIZONTAL) {
+ width = mSingleChildWidth * mTexts.length;
+ } else {
+ width = mSingleChildWidth;
+ }
+ break;
+ }
+
+ switch (heightMode) {
+ case MeasureSpec.AT_MOST:
+ if (mDirection == Direction.VERTICAL) {
+ if (heightSize <= mSingleChildHeight * mTexts.length) {
+ mSingleChildHeight = heightSize / mTexts.length;
+ height = heightSize;
+ } else {
+ height = mSingleChildHeight * mTexts.length;
+ }
+ } else {
+ height = heightSize <= mSingleChildHeight ? heightSize : mSingleChildHeight;
+ }
+ break;
+ case MeasureSpec.EXACTLY:
+ height = heightSize;
+ break;
+ case MeasureSpec.UNSPECIFIED:
+ default:
+ if (mDirection == Direction.VERTICAL) {
+ height = mSingleChildHeight * mTexts.length;
+ } else {
+ height = mSingleChildHeight;
+ }
+
+ break;
+ }
+
+ switch (mDirection) {
+ case HORIZONTAL:
+ if (mSingleChildWidth != width / mTexts.length) {
+ mSingleChildWidth = width / mTexts.length;
+ }
+ mSingleChildHeight = height;
+ break;
+ case VERTICAL:
+ if(mSingleChildHeight != height / mTexts.length) {
+ mSingleChildHeight = height / mTexts.length;
+ }
+ mSingleChildWidth = width;
+ break;
+ default:
+ break;
+ }
+
+ for (int i = 0; i < mTexts.length; i++) {
+
+ if (mCacheBounds[i] == null) {
+ mCacheBounds[i] = new Rect();
+ }
+
+ if (mDirection == Direction.HORIZONTAL) {
+ mCacheBounds[i].left = i * mSingleChildWidth;
+ mCacheBounds[i].top = 0;
+ } else {
+ mCacheBounds[i].left = 0;
+ mCacheBounds[i].top = i * mSingleChildHeight;
+ }
+
+ mCacheBounds[i].right = mCacheBounds[i].left + mSingleChildWidth;
+ mCacheBounds[i].bottom = mCacheBounds[i].top + mSingleChildHeight;
+ }
+ } else {
+ width = widthMode == MeasureSpec.UNSPECIFIED ? 0 : widthSize;
+ height = heightMode == MeasureSpec.UNSPECIFIED ? 0 : heightSize;
+ }
+
+ setMeasuredDimension(width, height);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ switch (event.getAction() & MotionEvent.ACTION_MASK) {
+ case MotionEvent.ACTION_DOWN:
+ inTapRegion = true;
+
+ mStartX = event.getX();
+ mStartY = event.getY();
+ break;
+
+ case MotionEvent.ACTION_MOVE:
+ mCurrentX = event.getX();
+ mCurrentY = event.getY();
+
+ int dx = (int) (mCurrentX - mStartX);
+ int dy = (int) (mCurrentY - mStartY);
+
+ int distance = dx * dx + dy * dy;
+
+ if (distance > mTouchSlop) {
+ inTapRegion = false;
+ }
+ break;
+
+ case MotionEvent.ACTION_UP:
+ if (inTapRegion) {
+ int index = 0;
+ if (mDirection == Direction.HORIZONTAL) {
+ index = (int) (mStartX / mSingleChildWidth);
+ } else {
+ index = (int) (mStartY / mSingleChildHeight);
+ }
+
+ setSelectedIndex(index);
+ }
+ break;
+ default:
+ break;
+ }
+ return true;
+ }
+
+ private int getSelectedTextColor(){
+ return mTextColors.getColorForState(new int[]{android.R.attr.state_selected}, DEFAULT_NORMAL_COLOR);
+ }
+
+ private int getNormalTextColor(){
+ return mTextColors.getColorForState(new int[]{-android.R.attr.state_selected}, DEFAULT_SELECTED_COLOR);
+ }
+
+ private int getSelectedBGColor(){
+ return mBackgroundColors.getColorForState(new int[]{android.R.attr.state_selected}, DEFAULT_SELECTED_COLOR);
+ }
+
+ private int getNormalBGColor(){
+ return mBackgroundColors.getColorForState(new int[]{-android.R.attr.state_selected}, DEFAULT_NORMAL_COLOR);
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ if (mTexts != null && mTexts.length > 0) {
+
+ for (int i = 0; i < mTexts.length; i++) {
+
+ //draw separate lines
+ if (i < mTexts.length - 1) {
+ mPaint.setColor(getSelectedBGColor());
+ mPaint.setStrokeWidth(mSeparatorWidth);
+ if (mDirection == Direction.HORIZONTAL) {
+ canvas.drawLine(mCacheBounds[i].right, 0, mCacheBounds[i].right, getHeight(), mPaint);
+ } else {
+ canvas.drawLine(mCacheBounds[i].left, mSingleChildHeight * (i + 1), mCacheBounds[i].right, mSingleChildHeight * (i + 1), mPaint);
+ }
+ }
+
+ //draw selected drawable
+ if (i == mCurrentIndex && mSelectedDrawable != null) {
+ int topLeftRadius = 0;
+ int topRightRadius = 0;
+ int bottomLeftRadius = 0;
+ int bottomRightRadius = 0;
+
+ if(mTexts.length == 1){
+ topLeftRadius = mCornerRadius;
+ bottomLeftRadius = mCornerRadius;
+ topRightRadius = mCornerRadius;
+ bottomRightRadius = mCornerRadius;
+ }else{
+ if (mDirection == Direction.HORIZONTAL) {
+ if (i == 0) {
+ topLeftRadius = mCornerRadius;
+ bottomLeftRadius = mCornerRadius;
+ } else if (i == mTexts.length - 1) {
+ topRightRadius = mCornerRadius;
+ bottomRightRadius = mCornerRadius;
+ }
+ } else {
+ if (i == 0) {
+ topLeftRadius = mCornerRadius;
+ topRightRadius = mCornerRadius;
+ } else if (i == mTexts.length - 1) {
+ bottomLeftRadius = mCornerRadius;
+ bottomRightRadius = mCornerRadius;
+ }
+ }
+ }
+
+ mSelectedDrawable.setRadius(topLeftRadius, topRightRadius, bottomLeftRadius, bottomRightRadius);
+ mSelectedDrawable.setBounds(mCacheBounds[i]);
+ mSelectedDrawable.draw(canvas);
+
+ mPaint.setColor(getSelectedTextColor());
+ } else {
+ mPaint.setColor(getNormalTextColor());
+ }
+
+ //draw texts
+
+ float baseline = mCacheBounds[i].top + ((mSingleChildHeight - mCachedFM.ascent + mCachedFM.descent) / 2) - mCachedFM.descent;
+ canvas.drawText(mTexts[i], mCacheBounds[i].left + (mSingleChildWidth - mTextBounds[i].width()) / 2, baseline, mPaint);
+
+ }
+ }
+ }
+
+ // =========================================================
+ // OnSegmentControlClickListener
+ // =========================================================
+ private OnSegmentControlClickListener mOnSegmentControlClickListener;
+
+ public void setOnSegmentControlClickListener(OnSegmentControlClickListener listener) {
+ mOnSegmentControlClickListener = listener;
+ }
+
+ public OnSegmentControlClickListener getOnSegmentControlClicklistener() {
+ return mOnSegmentControlClickListener;
+ }
+
+ public interface OnSegmentControlClickListener {
+ void onSegmentControlClick(int index);
+ }
+}
diff --git a/mylibrary/src/main/res/anim/anim_bottom_in.xml b/mylibrary/src/main/res/anim/anim_bottom_in.xml
new file mode 100644
index 0000000..e1191a5
--- /dev/null
+++ b/mylibrary/src/main/res/anim/anim_bottom_in.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/anim/anim_bottom_out.xml b/mylibrary/src/main/res/anim/anim_bottom_out.xml
new file mode 100644
index 0000000..2c2299b
--- /dev/null
+++ b/mylibrary/src/main/res/anim/anim_bottom_out.xml
@@ -0,0 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/color/select_text_color.xml b/mylibrary/src/main/res/color/select_text_color.xml
new file mode 100644
index 0000000..e3e3992
--- /dev/null
+++ b/mylibrary/src/main/res/color/select_text_color.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/drawable-hdpi/left.png b/mylibrary/src/main/res/drawable-hdpi/left.png
new file mode 100644
index 0000000..6a9e644
Binary files /dev/null and b/mylibrary/src/main/res/drawable-hdpi/left.png differ
diff --git a/mylibrary/src/main/res/drawable-xhdpi/black_back.png b/mylibrary/src/main/res/drawable-xhdpi/black_back.png
new file mode 100644
index 0000000..c12c77f
Binary files /dev/null and b/mylibrary/src/main/res/drawable-xhdpi/black_back.png differ
diff --git a/mylibrary/src/main/res/drawable-xhdpi/fab_add.png b/mylibrary/src/main/res/drawable-xhdpi/fab_add.png
new file mode 100644
index 0000000..c118072
Binary files /dev/null and b/mylibrary/src/main/res/drawable-xhdpi/fab_add.png differ
diff --git a/mylibrary/src/main/res/drawable-xhdpi/ic_add_image.png b/mylibrary/src/main/res/drawable-xhdpi/ic_add_image.png
new file mode 100644
index 0000000..38e38da
Binary files /dev/null and b/mylibrary/src/main/res/drawable-xhdpi/ic_add_image.png differ
diff --git a/mylibrary/src/main/res/drawable-xhdpi/icon_upload.png b/mylibrary/src/main/res/drawable-xhdpi/icon_upload.png
new file mode 100644
index 0000000..d8ff158
Binary files /dev/null and b/mylibrary/src/main/res/drawable-xhdpi/icon_upload.png differ
diff --git a/mylibrary/src/main/res/drawable-xhdpi/left.png b/mylibrary/src/main/res/drawable-xhdpi/left.png
new file mode 100644
index 0000000..fa0ec3d
Binary files /dev/null and b/mylibrary/src/main/res/drawable-xhdpi/left.png differ
diff --git a/mylibrary/src/main/res/drawable-xxhdpi/cars.png b/mylibrary/src/main/res/drawable-xxhdpi/cars.png
new file mode 100644
index 0000000..c0959a8
Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/cars.png differ
diff --git a/mylibrary/src/main/res/drawable-xxhdpi/cha.png b/mylibrary/src/main/res/drawable-xxhdpi/cha.png
new file mode 100644
index 0000000..7b2ce05
Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/cha.png differ
diff --git a/mylibrary/src/main/res/drawable-xxhdpi/check_nor.png b/mylibrary/src/main/res/drawable-xxhdpi/check_nor.png
new file mode 100644
index 0000000..7b92670
Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/check_nor.png differ
diff --git a/mylibrary/src/main/res/drawable-xxhdpi/check_sel.png b/mylibrary/src/main/res/drawable-xxhdpi/check_sel.png
new file mode 100644
index 0000000..b88f5e3
Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/check_sel.png differ
diff --git a/mylibrary/src/main/res/drawable-xxhdpi/diss.png b/mylibrary/src/main/res/drawable-xxhdpi/diss.png
new file mode 100644
index 0000000..eae77a0
Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/diss.png differ
diff --git a/mylibrary/src/main/res/drawable-xxhdpi/empty.png b/mylibrary/src/main/res/drawable-xxhdpi/empty.png
new file mode 100644
index 0000000..2bc4195
Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/empty.png differ
diff --git a/mylibrary/src/main/res/drawable-xxhdpi/error.png b/mylibrary/src/main/res/drawable-xxhdpi/error.png
new file mode 100644
index 0000000..771f025
Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/error.png differ
diff --git a/mylibrary/src/main/res/drawable-xxhdpi/fab_add.png b/mylibrary/src/main/res/drawable-xxhdpi/fab_add.png
new file mode 100644
index 0000000..07af313
Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/fab_add.png differ
diff --git a/mylibrary/src/main/res/drawable-xxhdpi/icon_refuse.png b/mylibrary/src/main/res/drawable-xxhdpi/icon_refuse.png
new file mode 100644
index 0000000..78a9c52
Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/icon_refuse.png differ
diff --git a/mylibrary/src/main/res/drawable-xxhdpi/id_select.png b/mylibrary/src/main/res/drawable-xxhdpi/id_select.png
new file mode 100644
index 0000000..c2f3394
Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/id_select.png differ
diff --git a/mylibrary/src/main/res/drawable-xxhdpi/id_select_loading.png b/mylibrary/src/main/res/drawable-xxhdpi/id_select_loading.png
new file mode 100644
index 0000000..fa1a413
Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/id_select_loading.png differ
diff --git a/mylibrary/src/main/res/drawable-xxhdpi/id_select_z.png b/mylibrary/src/main/res/drawable-xxhdpi/id_select_z.png
new file mode 100644
index 0000000..629b84d
Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/id_select_z.png differ
diff --git a/mylibrary/src/main/res/drawable-xxhdpi/left.png b/mylibrary/src/main/res/drawable-xxhdpi/left.png
new file mode 100644
index 0000000..78dfb14
Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/left.png differ
diff --git a/mylibrary/src/main/res/drawable-xxhdpi/message.png b/mylibrary/src/main/res/drawable-xxhdpi/message.png
new file mode 100644
index 0000000..b976b4e
Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/message.png differ
diff --git a/mylibrary/src/main/res/drawable-xxhdpi/ok.png b/mylibrary/src/main/res/drawable-xxhdpi/ok.png
new file mode 100644
index 0000000..e64bc5b
Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/ok.png differ
diff --git a/mylibrary/src/main/res/drawable-xxhdpi/update_head.png b/mylibrary/src/main/res/drawable-xxhdpi/update_head.png
new file mode 100644
index 0000000..97ac15d
Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/update_head.png differ
diff --git a/mylibrary/src/main/res/drawable-xxhdpi/version_top_bg.png b/mylibrary/src/main/res/drawable-xxhdpi/version_top_bg.png
new file mode 100644
index 0000000..8312c7c
Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxhdpi/version_top_bg.png differ
diff --git a/mylibrary/src/main/res/drawable-xxxhdpi/left.png b/mylibrary/src/main/res/drawable-xxxhdpi/left.png
new file mode 100644
index 0000000..7e9f9c5
Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxxhdpi/left.png differ
diff --git a/mylibrary/src/main/res/drawable-xxxhdpi/version_top_bg.png b/mylibrary/src/main/res/drawable-xxxhdpi/version_top_bg.png
new file mode 100644
index 0000000..e462198
Binary files /dev/null and b/mylibrary/src/main/res/drawable-xxxhdpi/version_top_bg.png differ
diff --git a/mylibrary/src/main/res/drawable/bnav_shape_du.xml b/mylibrary/src/main/res/drawable/bnav_shape_du.xml
new file mode 100644
index 0000000..28f5f8d
--- /dev/null
+++ b/mylibrary/src/main/res/drawable/bnav_shape_du.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/drawable/bnav_tab_background.xml b/mylibrary/src/main/res/drawable/bnav_tab_background.xml
new file mode 100644
index 0000000..270a701
--- /dev/null
+++ b/mylibrary/src/main/res/drawable/bnav_tab_background.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/drawable/loading.xml b/mylibrary/src/main/res/drawable/loading.xml
new file mode 100644
index 0000000..0ab50a0
--- /dev/null
+++ b/mylibrary/src/main/res/drawable/loading.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/drawable/select_check_node.xml b/mylibrary/src/main/res/drawable/select_check_node.xml
new file mode 100644
index 0000000..1cec8b6
--- /dev/null
+++ b/mylibrary/src/main/res/drawable/select_check_node.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/drawable/select_sim_text.xml b/mylibrary/src/main/res/drawable/select_sim_text.xml
new file mode 100644
index 0000000..d16b429
--- /dev/null
+++ b/mylibrary/src/main/res/drawable/select_sim_text.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/drawable/select_slide_title.xml b/mylibrary/src/main/res/drawable/select_slide_title.xml
new file mode 100644
index 0000000..bf8e084
--- /dev/null
+++ b/mylibrary/src/main/res/drawable/select_slide_title.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/drawable/select_text_c.xml b/mylibrary/src/main/res/drawable/select_text_c.xml
new file mode 100644
index 0000000..5a4b510
--- /dev/null
+++ b/mylibrary/src/main/res/drawable/select_text_c.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/drawable/shadow_bg.9.png b/mylibrary/src/main/res/drawable/shadow_bg.9.png
new file mode 100644
index 0000000..6dd4442
Binary files /dev/null and b/mylibrary/src/main/res/drawable/shadow_bg.9.png differ
diff --git a/mylibrary/src/main/res/drawable/shape_bg8.xml b/mylibrary/src/main/res/drawable/shape_bg8.xml
new file mode 100644
index 0000000..ba34bfb
--- /dev/null
+++ b/mylibrary/src/main/res/drawable/shape_bg8.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/drawable/shape_bind_phone_background.xml b/mylibrary/src/main/res/drawable/shape_bind_phone_background.xml
new file mode 100644
index 0000000..270e9f0
--- /dev/null
+++ b/mylibrary/src/main/res/drawable/shape_bind_phone_background.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/drawable/shape_blue_bg10.xml b/mylibrary/src/main/res/drawable/shape_blue_bg10.xml
new file mode 100644
index 0000000..a9bae1b
--- /dev/null
+++ b/mylibrary/src/main/res/drawable/shape_blue_bg10.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/drawable/shape_blue_bg25.xml b/mylibrary/src/main/res/drawable/shape_blue_bg25.xml
new file mode 100644
index 0000000..cdccedf
--- /dev/null
+++ b/mylibrary/src/main/res/drawable/shape_blue_bg25.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/drawable/shape_blue_bg4.xml b/mylibrary/src/main/res/drawable/shape_blue_bg4.xml
new file mode 100644
index 0000000..dd388ad
--- /dev/null
+++ b/mylibrary/src/main/res/drawable/shape_blue_bg4.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/drawable/shape_blue_bg8.xml b/mylibrary/src/main/res/drawable/shape_blue_bg8.xml
new file mode 100644
index 0000000..6e7e086
--- /dev/null
+++ b/mylibrary/src/main/res/drawable/shape_blue_bg8.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/drawable/shape_bottom_bgw16.xml b/mylibrary/src/main/res/drawable/shape_bottom_bgw16.xml
new file mode 100644
index 0000000..ad939cf
--- /dev/null
+++ b/mylibrary/src/main/res/drawable/shape_bottom_bgw16.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/drawable/shape_gray_bg10.xml b/mylibrary/src/main/res/drawable/shape_gray_bg10.xml
new file mode 100644
index 0000000..4a9a9e5
--- /dev/null
+++ b/mylibrary/src/main/res/drawable/shape_gray_bg10.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/drawable/shape_gray_bg25.xml b/mylibrary/src/main/res/drawable/shape_gray_bg25.xml
new file mode 100644
index 0000000..bb01f39
--- /dev/null
+++ b/mylibrary/src/main/res/drawable/shape_gray_bg25.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/drawable/shape_gray_bg4.xml b/mylibrary/src/main/res/drawable/shape_gray_bg4.xml
new file mode 100644
index 0000000..7ed2a61
--- /dev/null
+++ b/mylibrary/src/main/res/drawable/shape_gray_bg4.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/drawable/shape_log_btn_bg22.xml b/mylibrary/src/main/res/drawable/shape_log_btn_bg22.xml
new file mode 100644
index 0000000..6a526c2
--- /dev/null
+++ b/mylibrary/src/main/res/drawable/shape_log_btn_bg22.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/drawable/shape_message.xml b/mylibrary/src/main/res/drawable/shape_message.xml
new file mode 100644
index 0000000..f70d586
--- /dev/null
+++ b/mylibrary/src/main/res/drawable/shape_message.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/drawable/shape_text_4_blue.xml b/mylibrary/src/main/res/drawable/shape_text_4_blue.xml
new file mode 100644
index 0000000..9d7ac38
--- /dev/null
+++ b/mylibrary/src/main/res/drawable/shape_text_4_blue.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/drawable/shape_text_4_nor.xml b/mylibrary/src/main/res/drawable/shape_text_4_nor.xml
new file mode 100644
index 0000000..9389c1b
--- /dev/null
+++ b/mylibrary/src/main/res/drawable/shape_text_4_nor.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/drawable/shape_view_v.xml b/mylibrary/src/main/res/drawable/shape_view_v.xml
new file mode 100644
index 0000000..d59ee95
--- /dev/null
+++ b/mylibrary/src/main/res/drawable/shape_view_v.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/drawable/white_round_corner_bg.xml b/mylibrary/src/main/res/drawable/white_round_corner_bg.xml
new file mode 100644
index 0000000..d330d5b
--- /dev/null
+++ b/mylibrary/src/main/res/drawable/white_round_corner_bg.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/layout/common_toolbar.xml b/mylibrary/src/main/res/layout/common_toolbar.xml
new file mode 100644
index 0000000..ce88b6e
--- /dev/null
+++ b/mylibrary/src/main/res/layout/common_toolbar.xml
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mylibrary/src/main/res/layout/custom_dic_popup.xml b/mylibrary/src/main/res/layout/custom_dic_popup.xml
new file mode 100644
index 0000000..9f161b1
--- /dev/null
+++ b/mylibrary/src/main/res/layout/custom_dic_popup.xml
@@ -0,0 +1,15 @@
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/layout/custom_part_shadow_popup.xml b/mylibrary/src/main/res/layout/custom_part_shadow_popup.xml
new file mode 100644
index 0000000..bfbd9d4
--- /dev/null
+++ b/mylibrary/src/main/res/layout/custom_part_shadow_popup.xml
@@ -0,0 +1,10 @@
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/layout/dialog_phone.xml b/mylibrary/src/main/res/layout/dialog_phone.xml
new file mode 100644
index 0000000..1624eb3
--- /dev/null
+++ b/mylibrary/src/main/res/layout/dialog_phone.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/layout/dialog_photo_select.xml b/mylibrary/src/main/res/layout/dialog_photo_select.xml
new file mode 100644
index 0000000..85a4382
--- /dev/null
+++ b/mylibrary/src/main/res/layout/dialog_photo_select.xml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/layout/empty.xml b/mylibrary/src/main/res/layout/empty.xml
new file mode 100644
index 0000000..b6c7977
--- /dev/null
+++ b/mylibrary/src/main/res/layout/empty.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mylibrary/src/main/res/layout/empty_pic.xml b/mylibrary/src/main/res/layout/empty_pic.xml
new file mode 100644
index 0000000..52b216b
--- /dev/null
+++ b/mylibrary/src/main/res/layout/empty_pic.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mylibrary/src/main/res/layout/gv_filter_image.xml b/mylibrary/src/main/res/layout/gv_filter_image.xml
new file mode 100644
index 0000000..3a5194e
--- /dev/null
+++ b/mylibrary/src/main/res/layout/gv_filter_image.xml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/layout/item_car_select.xml b/mylibrary/src/main/res/layout/item_car_select.xml
new file mode 100644
index 0000000..414e97c
--- /dev/null
+++ b/mylibrary/src/main/res/layout/item_car_select.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/layout/item_dic_select.xml b/mylibrary/src/main/res/layout/item_dic_select.xml
new file mode 100644
index 0000000..9e94d4c
--- /dev/null
+++ b/mylibrary/src/main/res/layout/item_dic_select.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/layout/item_node_select.xml b/mylibrary/src/main/res/layout/item_node_select.xml
new file mode 100644
index 0000000..396acb0
--- /dev/null
+++ b/mylibrary/src/main/res/layout/item_node_select.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/layout/item_select.xml b/mylibrary/src/main/res/layout/item_select.xml
new file mode 100644
index 0000000..56a9f34
--- /dev/null
+++ b/mylibrary/src/main/res/layout/item_select.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/layout/my_confim_popup_input.xml b/mylibrary/src/main/res/layout/my_confim_popup_input.xml
new file mode 100644
index 0000000..db788f2
--- /dev/null
+++ b/mylibrary/src/main/res/layout/my_confim_popup_input.xml
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/layout/my_confim_popup_tip.xml b/mylibrary/src/main/res/layout/my_confim_popup_tip.xml
new file mode 100644
index 0000000..366f7cf
--- /dev/null
+++ b/mylibrary/src/main/res/layout/my_confim_popup_tip.xml
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/layout/my_confim_popup_unus.xml b/mylibrary/src/main/res/layout/my_confim_popup_unus.xml
new file mode 100644
index 0000000..ec68db1
--- /dev/null
+++ b/mylibrary/src/main/res/layout/my_confim_popup_unus.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/layout/upush_bar_image_notification.xml b/mylibrary/src/main/res/layout/upush_bar_image_notification.xml
new file mode 100644
index 0000000..b6c466a
--- /dev/null
+++ b/mylibrary/src/main/res/layout/upush_bar_image_notification.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/layout/upush_notification.xml b/mylibrary/src/main/res/layout/upush_notification.xml
new file mode 100644
index 0000000..79a9ade
--- /dev/null
+++ b/mylibrary/src/main/res/layout/upush_notification.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/layout/view_node.xml b/mylibrary/src/main/res/layout/view_node.xml
new file mode 100644
index 0000000..44d183f
--- /dev/null
+++ b/mylibrary/src/main/res/layout/view_node.xml
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mylibrary/src/main/res/layout/view_slide_bar.xml b/mylibrary/src/main/res/layout/view_slide_bar.xml
new file mode 100644
index 0000000..80483e7
--- /dev/null
+++ b/mylibrary/src/main/res/layout/view_slide_bar.xml
@@ -0,0 +1,182 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mylibrary/src/main/res/values/attrs.xml b/mylibrary/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..6af9f09
--- /dev/null
+++ b/mylibrary/src/main/res/values/attrs.xml
@@ -0,0 +1,211 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/values/colors.xml b/mylibrary/src/main/res/values/colors.xml
new file mode 100644
index 0000000..2a87706
--- /dev/null
+++ b/mylibrary/src/main/res/values/colors.xml
@@ -0,0 +1,30 @@
+
+
+ #28B950
+ #28B950
+ #D81B60
+
+ #FFFFFFFF
+ #333333
+ #666666
+ #FE0606
+ #ff007aff
+ #3C6FC6
+ #88888888
+
+
+
+
+ #F5F5F5
+ #000000
+ #E6E6E6
+ #F7F7F7
+ #999999
+ #f6f6f6
+ #D5D9DB
+
+
+
+
+
+
diff --git a/mylibrary/src/main/res/values/dimens.xml b/mylibrary/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..003e401
--- /dev/null
+++ b/mylibrary/src/main/res/values/dimens.xml
@@ -0,0 +1,26 @@
+
+
+ 8sp
+ 9sp
+ 10sp
+ 11sp
+ 12sp
+ 13sp
+ 14sp
+ 15sp
+ 16sp
+ 17sp
+ 18sp
+ 19sp
+ 20sp
+ 21sp
+ 22sp
+ 23sp
+ 24sp
+ 26sp
+ 28sp
+ 30sp
+ 40sp
+ 56dp
+ 40dp
+
diff --git a/mylibrary/src/main/res/values/ids.xml b/mylibrary/src/main/res/values/ids.xml
new file mode 100644
index 0000000..efaf17b
--- /dev/null
+++ b/mylibrary/src/main/res/values/ids.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/main/res/values/strings.xml b/mylibrary/src/main/res/values/strings.xml
new file mode 100644
index 0000000..708d45e
--- /dev/null
+++ b/mylibrary/src/main/res/values/strings.xml
@@ -0,0 +1,7 @@
+
+ CommonBaseLibrary
+
+ 拍照
+ 从相册中选择
+ 取消
+
diff --git a/mylibrary/src/main/res/values/styles.xml b/mylibrary/src/main/res/values/styles.xml
new file mode 100644
index 0000000..6c47106
--- /dev/null
+++ b/mylibrary/src/main/res/values/styles.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mylibrary/src/test/java/com/dahe/mylibrary/ExampleUnitTest.kt b/mylibrary/src/test/java/com/dahe/mylibrary/ExampleUnitTest.kt
new file mode 100644
index 0000000..0e4dd1d
--- /dev/null
+++ b/mylibrary/src/test/java/com/dahe/mylibrary/ExampleUnitTest.kt
@@ -0,0 +1,17 @@
+package com.dahe.mylibrary
+
+import org.junit.Test
+
+import org.junit.Assert.*
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * See [testing documentation](http://d.android.com/tools/testing).
+ */
+class ExampleUnitTest {
+ @Test
+ fun addition_isCorrect() {
+ assertEquals(4, 2 + 2)
+ }
+}
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index 05b3c75..ad6d5be 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,2 +1,3 @@
rootProject.name = "app-dhhy-cargo"
include ':app'
+include ':mylibrary'