.idea/dbnavigator.xml
@@ -17,6 +17,12 @@ <component name="DBNavigator.Project.DatabaseFileManager"> <open-files /> </component> <component name="DBNavigator.Project.ExecutionManager"> <retain-sticky-names value="false" /> </component> <component name="DBNavigator.Project.ParserDiagnosticsManager"> <diagnostics-history /> </component> <component name="DBNavigator.Project.Settings"> <connections /> <browser-settings> .idea/deploymentTargetDropDown.xml
@@ -7,11 +7,11 @@ <deviceKey> <Key> <type value="VIRTUAL_DEVICE_PATH" /> <value value="C:\Users\86175\.android\avd\Pixel_5_API_30.avd" /> <value value="D:\software\Android\.android\avd\Pixel_API_30.avd" /> </Key> </deviceKey> </Target> </targetSelectedWithDropDown> <timeTargetWasSelectedWithDropDown value="2023-03-21T13:34:06.068432400Z" /> <timeTargetWasSelectedWithDropDown value="2023-03-27T13:20:06.320581100Z" /> </component> </project> app/src/main/AndroidManifest.xml
@@ -3,7 +3,10 @@ xmlns:tools="http://schemas.android.com/tools"> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <application android:name=".MyApplication" android:allowBackup="true" @@ -15,7 +18,7 @@ android:networkSecurityConfig="@xml/network_security_config" android:resizeableActivity="true" android:supportsRtl="true" android:theme="@style/Theme.Zhangshi_app_android" android:theme="@style/Theme.app" android:usesCleartextTraffic="true" tools:targetApi="31"> <!-- 沉浸式状态栏全面屏 --> @@ -28,6 +31,13 @@ <meta-data android:name="notch.config" android:value="portrait|landscape" /> <!-- 屏幕适配 (默认以宽度适配)--> <meta-data android:name="design_width_in_dp" android:value="360"/> <meta-data android:name="design_height_in_dp" android:value="640"/> <activity android:name=".ui.main.MainActivity" app/src/main/java/com/application/zhangshi_app_android/MyApplication.java
@@ -4,6 +4,8 @@ import com.hjq.bar.TitleBar; import com.hjq.bar.style.TransparentBarStyle; //import me.jessyan.autosize.AutoSizeConfig; /** * @author Ljj * @date 2023.03.02. 17:51 app/src/main/java/com/application/zhangshi_app_android/adapter/FamilyMemorabiliaRvAdapter.java
@@ -4,12 +4,23 @@ import android.view.View; import android.view.animation.Animation; import android.view.animation.Transformation; import android.widget.CompoundButton; import android.widget.FrameLayout; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import com.android.app_base.base.adapter.BaseRVAdapter; import com.application.zhangshi_app_android.R; import com.application.zhangshi_app_android.bean.FamilyMemorabiliaBean; import com.application.zhangshi_app_android.databinding.ItemFamilyMemorabiliaBinding; import com.application.zhangshi_app_android.ui.function.FamilyMemorabiliaActivity; import com.application.zhangshi_app_android.ui.function.FamilyMemorabiliaActivityViewModel; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; /** * @author Ljj @@ -17,8 +28,18 @@ * @desc 家大事记 recyclerView 的 adapter */ public class FamilyMemorabiliaRvAdapter extends BaseRVAdapter<FamilyMemorabiliaBean, ItemFamilyMemorabiliaBinding, FamilyMemorabiliaRvAdapter.MyViewHolder> { private FamilyMemorabiliaActivityViewModel viewModel; private boolean isCheckable; public FamilyMemorabiliaRvAdapter(Context context) { super(context); } public FamilyMemorabiliaRvAdapter(Context context, FamilyMemorabiliaActivityViewModel viewModel) { super(context); this.viewModel = viewModel; } @Override @@ -33,10 +54,29 @@ @Override protected void onBind(MyViewHolder holder, int position) { holder.getBinding().setBean(mDataList.get(position)); if (position % 2 != 0){ holder.getBinding().cardView.setCardBackgroundColor(mContext.getColor(R.color.color_card_blue)); }else { holder.getBinding().cardView.setCardBackgroundColor(mContext.getColor(R.color.color_card_pink)); } if (isCheckable){ holder.getBinding().checkbox.setVisibility(View.VISIBLE); holder.getBinding().checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { List<FamilyMemorabiliaBean> list = new ArrayList<>(Objects.requireNonNull(viewModel.getCheckListLiveData().getValue())); if (isChecked){ list.add(mDataList.get(position)); }else{ list.remove(mDataList.get(position)); } viewModel.getCheckListLiveData().postValue(list); } }); holder.getBinding().checkbox.setChecked(viewModel.getCheckListLiveData().getValue().contains(mDataList.get(position))); }else{ holder.getBinding().checkbox.setVisibility(View.GONE); } holder.getBinding().layoutTitle.setOnClickListener(new View.OnClickListener() { @Override @@ -90,6 +130,11 @@ }); } public void setCheckable(boolean b) { isCheckable = b; notifyItemRangeChanged(0,getItemCount()); } public static class MyViewHolder extends BaseViewHolder<ItemFamilyMemorabiliaBinding>{ private boolean isExpended; @@ -98,5 +143,6 @@ super(binding); } } } app/src/main/java/com/application/zhangshi_app_android/bean/CaptchaImageBean.java
New file @@ -0,0 +1,60 @@ package com.application.zhangshi_app_android.bean; /** * @author Ljj * @date 2023.03.24. 15:29 * @desc 登录/注册的验证码图片类 */ public class CaptchaImageBean { /** * 图片的base64编码 */ private String img; /** * 验证码的 uuid */ private String uuid; /** * 验证码图片的值(方便开发阶段使用) */ private String value; public CaptchaImageBean(String img, String uuid, String value) { this.img = img; this.uuid = uuid; this.value = value; } public String getImg() { return img; } public void setImg(String img) { this.img = img; } public String getUuid() { return uuid; } public void setUuid(String uuid) { this.uuid = uuid; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } @Override public String toString() { return "CaptchaImageBean{" + "img='" + img + '\'' + ", uuid='" + uuid + '\'' + ", value='" + value + '\'' + '}'; } } app/src/main/java/com/application/zhangshi_app_android/bean/FamilyMemorabiliaBean.java
@@ -6,4 +6,32 @@ * @desc 家大事记 bean 类 */ public class FamilyMemorabiliaBean { private long id; private String address; private String createTime; private String people; private String remark; private String title; private String url; public String getAddress() { return address; } public void setAddress(String value) { this.address = value; } public String getCreateTime() { return createTime; } public void setCreateTime(String value) { this.createTime = value; } public long getId() { return id; } public void setId(long value) { this.id = value; } public String getPeople() { return people; } public void setPeople(String value) { this.people = value; } public String getRemark() { return remark; } public void setRemark(String value) { this.remark = value; } public String getTitle() { return title; } public void setTitle(String value) { this.title = value; } public String getUrl() { return url; } public void setUrl(String value) { this.url = value; } } app/src/main/java/com/application/zhangshi_app_android/bean/FamilyMemorabiliaRequestBean.java
New file @@ -0,0 +1,73 @@ package com.application.zhangshi_app_android.bean; /** * @author Ljj * @date 2023.03.28. 15:57 * @desc */ public class FamilyMemorabiliaRequestBean { private String people; private String address; private String remark; private String title; private String createTime; private int pageNum; private int pageSize; public String getPeople() { return people; } public void setPeople(String people) { this.people = people; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public int getPageNum() { return pageNum; } public void setPageNum(int pageNum) { this.pageNum = pageNum; } public int getPageSize() { return pageSize; } public void setPageSize(int pageSize) { this.pageSize = pageSize; } public String getCreateTime() { return createTime; } public void setCreateTime(String createTime) { this.createTime = createTime; } } app/src/main/java/com/application/zhangshi_app_android/bean/FamilyMemorabiliaResponseBean.java
New file @@ -0,0 +1,27 @@ package com.application.zhangshi_app_android.bean; import java.util.List; /** * @author Ljj * @date 2023.03.28. 13:52 * @desc 获取家大事记的返回类 */ public class FamilyMemorabiliaResponseBean { private List<FamilyMemorabiliaBean> data; private long pageNum; private long pageSize; private long total; public List<FamilyMemorabiliaBean> getData() { return data; } public void setData(List<FamilyMemorabiliaBean> value) { this.data = value; } public long getPageNum() { return pageNum; } public void setPageNum(long value) { this.pageNum = value; } public long getPageSize() { return pageSize; } public void setPageSize(long value) { this.pageSize = value; } public long getTotal() { return total; } public void setTotal(long value) { this.total = value; } } app/src/main/java/com/application/zhangshi_app_android/bean/LoginRequestBean.java
New file @@ -0,0 +1,45 @@ package com.application.zhangshi_app_android.bean; /** * @author Ljj * @date 2023.03.25. 19:07 * @desc 登录参数类 */ public class LoginRequestBean { private String code; private String password; private String username; private String uuid; public LoginRequestBean(String username,String password,String code, String uuid) { this.code = code; this.password = password; this.username = username; this.uuid = uuid; } /** * 验证码的值 */ public String getCode() { return code; } public void setCode(String value) { this.code = value; } /** * 注册提交的密码 */ public String getPassword() { return password; } public void setPassword(String value) { this.password = value; } /** * 注册提交的用户名 */ public String getUsername() { return username; } public void setUsername(String value) { this.username = value; } /** * 验证码的UUID,请求后端获取验证码接口后返回 */ public String getUuid() { return uuid; } public void setUuid(String value) { this.uuid = value; } } app/src/main/java/com/application/zhangshi_app_android/bean/LoginResponseBean.java
New file @@ -0,0 +1,18 @@ package com.application.zhangshi_app_android.bean; /** * @author Ljj * @date 2023.03.25. 19:20 * @desc 获取家大事记的参数类 */ public class LoginResponseBean { private String token; public String getToken() { return token; } public void setToken(String token) { this.token = token; } } app/src/main/java/com/application/zhangshi_app_android/config/BaseConfig.java
File was deleted app/src/main/java/com/application/zhangshi_app_android/data/DataRepository.java
@@ -3,10 +3,20 @@ import androidx.annotation.NonNull; import com.android.app_base.base.model.BaseModel; import com.android.app_base.http.ResultData; import com.application.zhangshi_app_android.bean.CaptchaImageBean; import com.application.zhangshi_app_android.bean.FamilyMemorabiliaBean; import com.application.zhangshi_app_android.bean.FamilyMemorabiliaRequestBean; import com.application.zhangshi_app_android.bean.FamilyMemorabiliaResponseBean; import com.application.zhangshi_app_android.bean.LoginRequestBean; import com.application.zhangshi_app_android.bean.LoginResponseBean; import com.application.zhangshi_app_android.data.source.HttpDataSource; import com.application.zhangshi_app_android.data.source.LocalDataSource; import com.application.zhangshi_app_android.data.source.http.HttpDataSourceImpl; import com.application.zhangshi_app_android.data.source.local.LocalDataSourceImpl; import java.util.List; import java.util.Map; import io.reactivex.Observable; import io.reactivex.Observer; @@ -50,7 +60,46 @@ /** * @see HttpDataSourceImpl */ /** * 获取验证码图片 */ public Observable<ResultData<CaptchaImageBean>> getCaptchaImage(){ return mHttpDataSource.getCaptchaImage(); } /** * 登录 */ public Observable<ResultData<LoginResponseBean>> login(LoginRequestBean loginRequestBean){ return mHttpDataSource.login(loginRequestBean); } /** * 注册 */ public Observable<ResultData<String>> register(LoginRequestBean loginRequestBean){ return mHttpDataSource.register(loginRequestBean); } /** * 获取家大事记 */ @Override public Observable<ResultData<FamilyMemorabiliaResponseBean>> getFamilyMemorabilia(Map<String, Object> queryMap) { return mHttpDataSource.getFamilyMemorabilia(queryMap); } /** * 增加家大事记 */ @Override public Observable<ResultData<String>> addFamilyMemorabilia(FamilyMemorabiliaBean familyMemorabiliaBean) { return mHttpDataSource.addFamilyMemorabilia(familyMemorabiliaBean); } /** * 删除家大事记 */ @Override public Observable<ResultData<String>> deleteFamilyMemorabilia(String ids) { return mHttpDataSource.deleteFamilyMemorabilia(ids); } /** * @see LocalDataSourceImpl app/src/main/java/com/application/zhangshi_app_android/data/source/HttpDataSource.java
@@ -1,5 +1,16 @@ package com.application.zhangshi_app_android.data.source; import com.android.app_base.http.ResultData; import com.application.zhangshi_app_android.bean.CaptchaImageBean; import com.application.zhangshi_app_android.bean.FamilyMemorabiliaBean; import com.application.zhangshi_app_android.bean.FamilyMemorabiliaRequestBean; import com.application.zhangshi_app_android.bean.FamilyMemorabiliaResponseBean; import com.application.zhangshi_app_android.bean.LoginRequestBean; import com.application.zhangshi_app_android.bean.LoginResponseBean; import java.util.List; import java.util.Map; import io.reactivex.Observable; import io.reactivex.Observer; @@ -9,5 +20,31 @@ * @desc 网络请求数据源 接口 */ public interface HttpDataSource { /** * 获取验证码图片 */ Observable<ResultData<CaptchaImageBean>> getCaptchaImage(); /** * 登录 */ Observable<ResultData<LoginResponseBean>> login(LoginRequestBean loginRequestBean); /** * 注册 */ Observable<ResultData<String>> register(LoginRequestBean loginRequestBean); /** * 获取家大事记 */ Observable<ResultData<FamilyMemorabiliaResponseBean>> getFamilyMemorabilia(Map<String, Object> queryMap); /** * 增加家大事记 */ Observable<ResultData<String>> addFamilyMemorabilia(FamilyMemorabiliaBean familyMemorabiliaBean); /** * 删除家大事记 */ Observable<ResultData<String>> deleteFamilyMemorabilia(String ids); } app/src/main/java/com/application/zhangshi_app_android/data/source/http/ApiService.java
@@ -1,13 +1,24 @@ package com.application.zhangshi_app_android.data.source.http; import com.android.app_base.http.ResultData; import com.application.zhangshi_app_android.bean.CaptchaImageBean; import com.application.zhangshi_app_android.bean.FamilyMemorabiliaBean; import com.application.zhangshi_app_android.bean.FamilyMemorabiliaRequestBean; import com.application.zhangshi_app_android.bean.FamilyMemorabiliaResponseBean; import com.application.zhangshi_app_android.bean.LoginRequestBean; import com.application.zhangshi_app_android.bean.LoginResponseBean; import java.util.List; import java.util.Map; import io.reactivex.Observable; import retrofit2.http.FieldMap; import retrofit2.http.FormUrlEncoded; import retrofit2.http.Body; import retrofit2.http.DELETE; import retrofit2.http.GET; import retrofit2.http.POST; import retrofit2.http.Url; import retrofit2.http.Path; import retrofit2.http.Query; import retrofit2.http.QueryMap; /** * @author Ljj @@ -15,6 +26,38 @@ * @desc 网络请求 service */ public interface ApiService { @GET() Observable<String> getData(@Url String url); /** * 获取验证码图片 */ @GET("/captchaImage") Observable<ResultData<CaptchaImageBean>> getCaptchaImage(); /** * 登录 */ @POST("/login") Observable<ResultData<LoginResponseBean>> login(@Body LoginRequestBean loginRequestBean); /** * 注册 */ @POST("/register") Observable<ResultData<String>> register(@Body LoginRequestBean loginRequestBean); /** * 获取家大事件 */ @GET("family/zfEvent/all") Observable<ResultData<FamilyMemorabiliaResponseBean>> getFamilyMemorabilia(@QueryMap Map<String,Object> queryMap); /** * 增加家大事记 */ @POST("/family/zfEvent") Observable<ResultData<String>> addFamilyMemorabilia(@Body FamilyMemorabiliaBean familyMemorabiliaBean); /** * 删除家大事记 */ @DELETE("/family/zfEvent/{ids}") Observable<ResultData<String>> deleteFamilyMemorabilia(@Path("ids") String ids); } app/src/main/java/com/application/zhangshi_app_android/data/source/http/HttpDataSourceImpl.java
@@ -1,17 +1,18 @@ package com.application.zhangshi_app_android.data.source.http; import androidx.annotation.NonNull; import com.android.app_base.http.OkHttpHelper; import com.android.app_base.http.ResultData; import com.android.app_base.http.RetrofitManager; import com.application.zhangshi_app_android.config.BaseConfig; import com.application.zhangshi_app_android.bean.CaptchaImageBean; import com.application.zhangshi_app_android.bean.FamilyMemorabiliaBean; import com.application.zhangshi_app_android.bean.FamilyMemorabiliaResponseBean; import com.application.zhangshi_app_android.bean.LoginRequestBean; import com.application.zhangshi_app_android.bean.LoginResponseBean; import com.android.app_base.base.BaseConfig; import com.application.zhangshi_app_android.data.source.HttpDataSource; import java.io.IOException; import java.util.Map; import io.reactivex.Observable; import okhttp3.Interceptor; import okhttp3.Response; /** * @author Ljj @@ -42,4 +43,49 @@ INSTANCE = null; } /** * 获取验证码图片 */ @Override public Observable<ResultData<CaptchaImageBean>> getCaptchaImage() { return apiService.getCaptchaImage(); } /** * 登录 * @param loginRequestBean 登录参数 */ @Override public Observable<ResultData<LoginResponseBean>> login(LoginRequestBean loginRequestBean) { return apiService.login(loginRequestBean); } /** * 注册 */ @Override public Observable<ResultData<String>> register(LoginRequestBean loginRequestBean) { return apiService.register(loginRequestBean); } /** * 获取家大事记 */ @Override public Observable<ResultData<FamilyMemorabiliaResponseBean>> getFamilyMemorabilia(Map<String, Object> queryMap) { return apiService.getFamilyMemorabilia(queryMap); } /** * 增加家大事记 */ @Override public Observable<ResultData<String>> addFamilyMemorabilia(FamilyMemorabiliaBean familyMemorabiliaBean) { return apiService.addFamilyMemorabilia(familyMemorabiliaBean); } /** * 删除家大事记 */ @Override public Observable<ResultData<String>> deleteFamilyMemorabilia(String ids) { return apiService.deleteFamilyMemorabilia(ids); } } app/src/main/java/com/application/zhangshi_app_android/ui/function/FamilyMemorabiliaActivity.java
@@ -1,12 +1,35 @@ package com.application.zhangshi_app_android.ui.function; import android.content.DialogInterface; import android.graphics.drawable.ColorDrawable; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; import android.widget.Button; import android.widget.PopupWindow; import android.widget.TextView; import androidx.annotation.IdRes; import androidx.annotation.LayoutRes; import androidx.appcompat.app.AlertDialog; import androidx.drawerlayout.widget.DrawerLayout; import androidx.lifecycle.Observer; import com.android.app_base.base.dialog.BaseDialog; import com.android.app_base.base.dialog.UIDialog; import com.android.app_base.base.view.BaseActivity; import com.android.app_base.utils.ScreenSizeUtils; import com.android.app_base.widget.LinearItemDecoration; import com.application.zhangshi_app_android.BR; import com.application.zhangshi_app_android.R; import com.application.zhangshi_app_android.adapter.FamilyMemorabiliaRvAdapter; import com.application.zhangshi_app_android.bean.FamilyMemorabiliaBean; import com.application.zhangshi_app_android.databinding.ActivityFamilyMemorabiliaBinding; import java.util.List; /** * @author Ljj * @date 2023.03.18. 10:00 @@ -15,6 +38,10 @@ public class FamilyMemorabiliaActivity extends BaseActivity<ActivityFamilyMemorabiliaBinding,FamilyMemorabiliaActivityViewModel> { FamilyMemorabiliaRvAdapter adapter; private PopupWindow mOperatePopupWindow; private PopupWindow mSearchPopupWindow; private int operateType = 0; private int searchType = 0; @Override public int getLayoutId() { @@ -33,26 +60,179 @@ @Override public void initView() { adapter = new FamilyMemorabiliaRvAdapter(this); adapter = new FamilyMemorabiliaRvAdapter(this,viewModel); LinearItemDecoration itemDecoration = new LinearItemDecoration(); itemDecoration.setBottomSpace((int) getResources().getDimension(com.android.app_base.R.dimen.dp_12)); itemDecoration.setHorizontalSpace((int) getResources().getDimension(com.android.app_base.R.dimen.dp_20)); itemDecoration.setFirstTop((int) getResources().getDimension(com.android.app_base.R.dimen.dp_20)); binding.recyclerView.addItemDecoration(itemDecoration); binding.recyclerView.setAdapter(adapter); mOperatePopupWindow = initPopUpWindow(R.layout.pop_operate); mOperatePopupWindow.getContentView().findViewById(R.id.tv_add).setOnClickListener(v -> { //TODO 跳转 新建 }); mOperatePopupWindow.getContentView().findViewById(R.id.tv_select).setOnClickListener(v -> { binding.ivOperate.setBackgroundResource(R.drawable.ic_operate_finish); operateType = 1; adapter.setCheckable(true); mOperatePopupWindow.dismiss(); }); mOperatePopupWindow.getContentView().findViewById(R.id.tv_from_new_to_old).setOnClickListener(v -> { viewModel.changeOrder(true); mOperatePopupWindow.dismiss(); }); mOperatePopupWindow.getContentView().findViewById(R.id.tv_from_old_to_new).setOnClickListener(v -> { viewModel.changeOrder(false); mOperatePopupWindow.dismiss(); }); binding.ivOperate.setOnClickListener(v -> { if (operateType == 0){ mOperatePopupWindow.showAsDropDown(binding.ivOperate,-ScreenSizeUtils.dip2px(this,85) +binding.ivOperate.getWidth(),0); } else if (operateType == 1) { binding.ivOperate.setBackgroundResource(R.drawable.ic_operate); operateType = 0; adapter.setCheckable(false); } else { new UIDialog.Builder(this) .setTitle("您确定要删除项目吗") .setContent("项目删除后将无法恢复") .setConfirm("确定") .setCancel("取消") .setListener(new UIDialog.OnListener() { @Override public void onConfirm(BaseDialog dialog) { viewModel.delete(); } }) .show(); } }); mSearchPopupWindow = initPopUpWindow(R.layout.pop_search); binding.ivSearchType.setOnClickListener(v -> { mSearchPopupWindow.showAsDropDown(binding.etSearch,0,0); }); binding.ivSearchDefault.setOnClickListener(v -> { binding.layoutSearch.setVisibility(View.VISIBLE); binding.layoutDefault.setVisibility(View.GONE); }); binding.fabAdd.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { } }); setOnClickListener( mSearchPopupWindow.getContentView().findViewById(R.id.tv_global_search), mSearchPopupWindow.getContentView().findViewById(R.id.tv_search_in_family_memorabilia), mSearchPopupWindow.getContentView().findViewById(R.id.tv_search_by_title), mSearchPopupWindow.getContentView().findViewById(R.id.tv_search_by_people), mSearchPopupWindow.getContentView().findViewById(R.id.tv_search_by_time), mSearchPopupWindow.getContentView().findViewById(R.id.tv_search_by_place)); binding.etSearch.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { if ((actionId == EditorInfo.IME_ACTION_UNSPECIFIED || actionId == EditorInfo.IME_ACTION_SEARCH) && event != null) { viewModel.getFamilyMemorabilia(searchType); hideSoftKeyboard(); return true; } return false; } }); binding.drawerLayout.setScrimColor(getResources().getColor(R.color.color_shadow)); } @Override public void initData() { adapter.addItem(new FamilyMemorabiliaBean()); adapter.addItem(new FamilyMemorabiliaBean()); adapter.addItem(new FamilyMemorabiliaBean()); adapter.addItem(new FamilyMemorabiliaBean()); adapter.addItem(new FamilyMemorabiliaBean()); viewModel.getFamilyMemorabilia(0); } @Override public void initLiveDataObserve() { viewModel.getCheckListLiveData().observe(this, new Observer<List<FamilyMemorabiliaBean>>() { @Override public void onChanged(List<FamilyMemorabiliaBean> familyMemorabiliaBeans) { if (operateType == 0){ return; } if (familyMemorabiliaBeans.isEmpty()){ binding.ivOperate.setBackgroundResource(R.drawable.ic_operate_finish); operateType = 1; }else{ binding.ivOperate.setBackgroundResource(R.drawable.ic_delete_white); operateType = 2; } } }); viewModel.getDataListLiveData().observe(this, new Observer<List<FamilyMemorabiliaBean>>() { @Override public void onChanged(List<FamilyMemorabiliaBean> familyMemorabiliaBeans) { adapter.setData(familyMemorabiliaBeans); } }); } private PopupWindow initPopUpWindow(@LayoutRes int layoutId){ PopupWindow popupWindow = new PopupWindow(this); // 设置布局文件 popupWindow.setContentView(LayoutInflater.from(this).inflate(layoutId, null)); // 为了避免部分机型不显示,需要重新设置一下宽高 popupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT); popupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT); // 设置pop透明效果 popupWindow.setBackgroundDrawable(new ColorDrawable(0x0000)); // 设置pop出入动画 popupWindow.setAnimationStyle(com.android.app_base.R.style.pop_add); // 设置pop获取焦点,如果为false点击返回按钮会退出当前Activity,如果pop中有Editor的话,focusable必须要为true popupWindow.setFocusable(true); // 设置pop可点击,为false点击事件无效,默认为true popupWindow.setTouchable(true); // 设置点击pop外侧消失,默认为false;在focusable为true时点击外侧始终消失 popupWindow.setOutsideTouchable(true); return popupWindow; } @Override protected void dataNull() { super.dataNull(); } @Override public void onClick(View v) { int id = v.getId(); if (id == R.id.tv_global_search){ searchType = 0; binding.etSearch.setHint("全局搜索"); mSearchPopupWindow.dismiss(); }else if (id == R.id.tv_search_in_family_memorabilia) { searchType = 1; mSearchPopupWindow.dismiss(); binding.etSearch.setHint("在“家大事记”内搜索"); }else if (id == R.id.tv_search_by_title) { searchType = 2; mSearchPopupWindow.dismiss(); binding.etSearch.setHint("按“大事记标题”搜索"); }else if (id == R.id.tv_search_by_people) { searchType = 3; mSearchPopupWindow.dismiss(); binding.etSearch.setHint("按“人物”搜索"); }else if (id == R.id.tv_search_by_time) { searchType = 4; mSearchPopupWindow.dismiss(); binding.etSearch.setHint("按“时间”搜索"); }else if (id == R.id.tv_search_by_place) { searchType = 5; mSearchPopupWindow.dismiss(); binding.etSearch.setHint("按“地点”搜索"); } } } app/src/main/java/com/application/zhangshi_app_android/ui/function/FamilyMemorabiliaActivityViewModel.java
@@ -1,11 +1,29 @@ package com.application.zhangshi_app_android.ui.function; import static com.android.app_base.base.BaseConfig.CODE_SUCCESS; import android.app.Application; import androidx.annotation.NonNull; import androidx.lifecycle.MutableLiveData; import com.android.app_base.base.StateViewEnum; import com.android.app_base.base.viewmodel.BaseViewModel; import com.android.app_base.http.ResultData; import com.android.app_base.utils.RxUtils; import com.application.zhangshi_app_android.bean.FamilyMemorabiliaBean; import com.application.zhangshi_app_android.bean.FamilyMemorabiliaResponseBean; import com.application.zhangshi_app_android.data.DataRepository; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import io.reactivex.Observer; import io.reactivex.disposables.Disposable; /** * @author Ljj @@ -14,6 +32,9 @@ */ public class FamilyMemorabiliaActivityViewModel extends BaseViewModel<DataRepository> { private MutableLiveData<List<FamilyMemorabiliaBean>> checkListLiveData; private MutableLiveData<List<FamilyMemorabiliaBean>> dataListLiveData; private MutableLiveData<String> stringMutableLiveData; public FamilyMemorabiliaActivityViewModel(@NonNull Application application) { super(application); } @@ -22,4 +43,192 @@ protected DataRepository initModel() { return DataRepository.getInstance(); } /** * 获取家大事记 */ public void getFamilyMemorabilia(int searchType) { Map<String, Object> queryMap = new HashMap<>(); queryMap.put("pageNum",1); queryMap.put("pageSize",20); if (searchType == 1){ queryMap.put("remark",stringMutableLiveData.getValue()); } else if (searchType == 2) { queryMap.put("title",stringMutableLiveData.getValue()); }else if (searchType == 3) { queryMap.put("people",stringMutableLiveData.getValue()); } else if (searchType == 4) { queryMap.put("createTime",stringMutableLiveData.getValue()); } else if (searchType == 5) { queryMap.put("address",stringMutableLiveData.getValue()); } model.getFamilyMemorabilia(queryMap) .compose(RxUtils.schedulersTransformer()) .subscribe(new Observer<ResultData<FamilyMemorabiliaResponseBean>>() { @Override public void onSubscribe(Disposable d) { addSubscribe(d); } @Override public void onNext(ResultData<FamilyMemorabiliaResponseBean> data) { if (data.getCode() == CODE_SUCCESS){ if (data.getData().getData().isEmpty()){ changeStateView(StateViewEnum.DATA_NULL); }else { dataListLiveData.postValue(data.getData().getData()); } }else { messageLiveData.postValue(data.getMsg()); } } @Override public void onError(Throwable e) { messageLiveData.postValue(e.getMessage()); } @Override public void onComplete() { } }); } /** * 增加家大事记 */ public void add(FamilyMemorabiliaBean bean) { model.addFamilyMemorabilia(bean) .compose(RxUtils.schedulersTransformer()) .subscribe(new Observer<ResultData<String>>() { @Override public void onSubscribe(Disposable d) { addSubscribe(d); } @Override public void onNext(ResultData<String> stringResultData) { if (stringResultData.getCode() == CODE_SUCCESS){ messageLiveData.postValue("添加成功"); }else { messageLiveData.postValue(stringResultData.getMsg()); } } @Override public void onError(Throwable e) { messageLiveData.postValue(e.getMessage()); } @Override public void onComplete() { } }); } /** * 删除家大事记 */ public void delete() { List<FamilyMemorabiliaBean> deleteList = getCheckListLiveData().getValue(); if (deleteList == null){ return; } StringBuffer sb = new StringBuffer(); deleteList.forEach(familyMemorabiliaBean -> sb.append(familyMemorabiliaBean.getId()).append(",")); sb.deleteCharAt(sb.length()-1); System.out.println(); model.deleteFamilyMemorabilia(sb.toString()) .compose(RxUtils.schedulersTransformer()) .subscribe(new Observer<ResultData<String>>() { @Override public void onSubscribe(Disposable d) { addSubscribe(d); } @Override public void onNext(ResultData<String> stringResultData) { if (stringResultData.getCode() == CODE_SUCCESS){ List<FamilyMemorabiliaBean> list = getDataListLiveData().getValue(); if (list != null) { list.removeAll(getCheckListLiveData().getValue()); } getDataListLiveData().postValue(list); messageLiveData.postValue("删除成功"); getCheckListLiveData().postValue(new ArrayList<>()); }else { messageLiveData.postValue(stringResultData.getMsg()); } } @Override public void onError(Throwable e) { messageLiveData.postValue(e.getMessage()); } @Override public void onComplete() { } }); } public MutableLiveData<List<FamilyMemorabiliaBean>> getCheckListLiveData() { if (checkListLiveData==null){ checkListLiveData = new MutableLiveData<>(); checkListLiveData.postValue(new ArrayList<>()); } if (checkListLiveData.getValue() == null){ checkListLiveData.postValue(new ArrayList<>()); } return checkListLiveData; } public void setCheckListLiveData(MutableLiveData<List<FamilyMemorabiliaBean>> checkListLiveData) { this.checkListLiveData = checkListLiveData; } public MutableLiveData<List<FamilyMemorabiliaBean>> getDataListLiveData() { if (dataListLiveData == null){ dataListLiveData = new MutableLiveData<>(); } return dataListLiveData; } public void setDataListLiveData(MutableLiveData<List<FamilyMemorabiliaBean>> dataListLiveData) { this.dataListLiveData = dataListLiveData; } public MutableLiveData<String> getStringMutableLiveData() { if (stringMutableLiveData == null){ stringMutableLiveData = new MutableLiveData<>(); } return stringMutableLiveData; } public void setStringMutableLiveData(MutableLiveData<String> stringMutableLiveData) { this.stringMutableLiveData = stringMutableLiveData; } public void changeOrder(boolean b) { List<FamilyMemorabiliaBean> dataList = getDataListLiveData().getValue(); if (dataList == null) return; if (b){ dataList.sort(new Comparator<FamilyMemorabiliaBean>() { @Override public int compare(FamilyMemorabiliaBean o1, FamilyMemorabiliaBean o2) { return (int) (o1.getId() - o2.getId()); } }); }else { dataList.sort(new Comparator<FamilyMemorabiliaBean>() { @Override public int compare(FamilyMemorabiliaBean o1, FamilyMemorabiliaBean o2) { return (int) (o2.getId() - o1.getId()); } }); } getDataListLiveData().postValue(dataList); } } app/src/main/java/com/application/zhangshi_app_android/ui/login/LoginActivity.java
@@ -1,12 +1,15 @@ package com.application.zhangshi_app_android.ui.login; import static com.android.app_base.base.BaseConfig.EXTRA_TYPE; import android.content.Intent; import android.view.View; import androidx.annotation.NonNull; import com.android.app_base.base.view.BaseActivity; import com.android.app_base.manager.AppManager; import com.android.app_base.utils.ScreenSizeUtils; import com.android.app_base.manager.UserManager; import com.application.zhangshi_app_android.BR; import com.application.zhangshi_app_android.R; import com.application.zhangshi_app_android.databinding.ActivityLoginBinding; @@ -19,6 +22,7 @@ * @desc 登录注册 Activity */ public class LoginActivity extends BaseActivity<ActivityLoginBinding,LoginActivityViewModel> { private int type; @Override public int getLayoutId() { return R.layout.activity_login; @@ -31,29 +35,56 @@ @Override public void initParam() { System.out.println("token"+UserManager.getInstance().getToken()); if (!UserManager.getInstance().getToken().isEmpty()){ AppManager.getAppManager().startActivity(MainActivity.class); finish(); } type = getIntent().getIntExtra(EXTRA_TYPE,0); } @Override public void initView() { binding.tvLogin.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { AppManager.getAppManager().startActivity(MainActivity.class); } }); if (type == 1){ binding.tvTitle.setText("张氏APP账号注册"); binding.layoutPasswordAgain.setVisibility(View.VISIBLE); binding.layoutWxLogin.setVisibility(View.GONE); binding.tvLogin.setText("注册"); binding.tvRegister.setText("已有账号,立即登录"); } binding.ivPasswordVisibility.setOnClickListener(v -> { viewModel.getPasswordVisibility().postValue(Boolean.FALSE.equals(viewModel.getPasswordVisibility().getValue())); }); binding.ivPasswordAgainVisibility.setOnClickListener(v -> { viewModel.getAgainPasswordVisibility().postValue(Boolean.FALSE.equals(viewModel.getAgainPasswordVisibility().getValue())); }); binding.tvLogin.setOnClickListener(view -> { if (type == 1){ viewModel.register(); }else{ viewModel.login(); } // AppManager.getAppManager().startActivity(MainActivity.class); }); binding.tvRegister.setOnClickListener(v -> { if (type == 1){ finish(); }else{ AppManager.getAppManager().startActivity(new Intent(this, LoginActivity.class).putExtra(EXTRA_TYPE,1)); } }); binding.ivCaptcha.setOnClickListener(v -> viewModel.getCaptchaImage()); } @Override public void initData() { viewModel.getCaptchaImage(); } @Override public void initLiveDataObserve() { } @NonNull @Override protected ImmersionBar createStatusBarConfig() { app/src/main/java/com/application/zhangshi_app_android/ui/login/LoginActivityViewModel.java
@@ -1,11 +1,30 @@ package com.application.zhangshi_app_android.ui.login; import static com.android.app_base.base.BaseConfig.CODE_SUCCESS; import android.app.Application; import android.text.TextUtils; import androidx.annotation.NonNull; import androidx.lifecycle.MutableLiveData; import com.android.app_base.base.StateViewEnum; import com.android.app_base.base.viewmodel.BaseViewModel; import com.android.app_base.http.ResultData; import com.android.app_base.manager.AppManager; import com.android.app_base.manager.UserManager; import com.android.app_base.utils.RxUtils; import com.android.app_base.utils.ToastUtils; import com.application.zhangshi_app_android.bean.CaptchaImageBean; import com.application.zhangshi_app_android.bean.LoginRequestBean; import com.application.zhangshi_app_android.bean.LoginResponseBean; import com.application.zhangshi_app_android.data.DataRepository; import com.application.zhangshi_app_android.ui.main.MainActivity; import java.util.Objects; import io.reactivex.Observer; import io.reactivex.disposables.Disposable; /** * @author Ljj @@ -13,12 +32,198 @@ * @desc 登录注册ViewModel */ public class LoginActivityViewModel extends BaseViewModel<DataRepository> { private MutableLiveData<CaptchaImageBean> captchaImageLiveData = new MutableLiveData<>(); private MutableLiveData<String> username = new MutableLiveData<>(); private MutableLiveData<String> password = new MutableLiveData<>(); private MutableLiveData<String> againPassword = new MutableLiveData<>(); private MutableLiveData<Boolean> passwordVisibility = new MutableLiveData<>(); private MutableLiveData<Boolean> againPasswordVisibility = new MutableLiveData<>(); private MutableLiveData<String> value = new MutableLiveData<>(); public LoginActivityViewModel(@NonNull Application application) { super(application); passwordVisibility.postValue(true); againPasswordVisibility.postValue(true); } @Override protected DataRepository initModel() { return DataRepository.getInstance(); } public void getCaptchaImage(){ model.getCaptchaImage() .compose(RxUtils.schedulersTransformer()) .subscribe(new Observer<ResultData<CaptchaImageBean>>() { @Override public void onSubscribe(Disposable d) { addSubscribe(d); } @Override public void onNext(ResultData<CaptchaImageBean> captchaImageBeanResultData) { if (captchaImageBeanResultData.getCode() == CODE_SUCCESS){ captchaImageLiveData.postValue(captchaImageBeanResultData.getData()); }else { changeStateView(StateViewEnum.DATA_ERROR); messageLiveData.postValue(captchaImageBeanResultData.getMsg()); } } @Override public void onError(Throwable e) { messageLiveData.postValue(e.getMessage()); } @Override public void onComplete() { } }); } public void login(){ if (TextUtils.isEmpty(username.getValue()) || TextUtils.isEmpty(password.getValue())||TextUtils.isEmpty(password.getValue())){ ToastUtils.showShort("请输入账号密码"); return; } if (TextUtils.isEmpty(value.getValue())){ ToastUtils.showShort("请输入验证码"); return; } if (captchaImageLiveData.getValue() != null){ model.login(new LoginRequestBean(username.getValue(),password.getValue(),captchaImageLiveData.getValue().getValue(),captchaImageLiveData.getValue().getUuid())) .compose(RxUtils.schedulersTransformer()) .subscribe(new Observer<ResultData<LoginResponseBean>>() { @Override public void onSubscribe(Disposable d) { addSubscribe(d); } @Override public void onNext(ResultData<LoginResponseBean> loginResponseBeanResultData) { if (loginResponseBeanResultData.getCode() == CODE_SUCCESS){ String token = loginResponseBeanResultData.getData().getToken(); UserManager.getInstance().setToken(token); ToastUtils.showShort("登陆成功"); AppManager.getAppManager().startActivity(MainActivity.class); }else { changeStateView(StateViewEnum.DATA_ERROR); messageLiveData.postValue(loginResponseBeanResultData.getMsg()); } } @Override public void onError(Throwable e) { messageLiveData.postValue(e.getMessage()); } @Override public void onComplete() { } }); } } public void register(){ if (TextUtils.isEmpty(username.getValue()) || TextUtils.isEmpty(password.getValue())||TextUtils.isEmpty(password.getValue())){ ToastUtils.showShort("请输入账号密码"); return; } if (TextUtils.isEmpty(value.getValue())){ ToastUtils.showShort("请输入验证码"); return; } if (!Objects.equals(password.getValue(), againPassword.getValue())){ ToastUtils.showShort("两次密码输入不一致"); return; } if (captchaImageLiveData.getValue() != null){ model.register(new LoginRequestBean(username.getValue(),password.getValue(),captchaImageLiveData.getValue().getValue(),captchaImageLiveData.getValue().getUuid())) .compose(RxUtils.schedulersTransformer()) .subscribe(new Observer<ResultData<String>>() { @Override public void onSubscribe(Disposable d) { addSubscribe(d); } @Override public void onNext(ResultData<String> stringResultData) { if (stringResultData.getCode() == CODE_SUCCESS){ ToastUtils.showShort("注册成功"); AppManager.getAppManager().finishCurrentActivity(); }else { changeStateView(StateViewEnum.DATA_ERROR); messageLiveData.postValue(stringResultData.getMsg()); } } @Override public void onError(Throwable e) { messageLiveData.postValue(e.getMessage()); } @Override public void onComplete() { } }); } } public MutableLiveData<CaptchaImageBean> getCaptchaImageLiveData() { return captchaImageLiveData; } public void setCaptchaImageLiveData(MutableLiveData<CaptchaImageBean> captchaImageLiveData) { this.captchaImageLiveData = captchaImageLiveData; } public MutableLiveData<String> getUsername() { return username; } public void setUsername(MutableLiveData<String> username) { this.username = username; } public MutableLiveData<String> getPassword() { return password; } public MutableLiveData<String> getAgainPassword() { return againPassword; } public void setAgainPassword(MutableLiveData<String> againPassword) { this.againPassword = againPassword; } public void setPassword(MutableLiveData<String> password) { this.password = password; } public MutableLiveData<Boolean> getPasswordVisibility() { return passwordVisibility; } public void setPasswordVisibility(MutableLiveData<Boolean> passwordVisibility) { this.passwordVisibility = passwordVisibility; } public MutableLiveData<Boolean> getAgainPasswordVisibility() { return againPasswordVisibility; } public void setAgainPasswordVisibility(MutableLiveData<Boolean> againPasswordVisibility) { this.againPasswordVisibility = againPasswordVisibility; } public MutableLiveData<String> getValue() { return value; } public void setValue(MutableLiveData<String> value) { this.value = value; } } app/src/main/res/drawable-xhdpi/bg_login_home.pngapp/src/main/res/drawable-xhdpi/function_family_root_net.pngapp/src/main/res/drawable-xhdpi/ic_add.png
app/src/main/res/drawable-xhdpi/ic_checked.png
app/src/main/res/drawable-xhdpi/ic_delete_white.png
app/src/main/res/drawable-xhdpi/ic_operate_add.png
app/src/main/res/drawable-xhdpi/ic_operate_finish.png
app/src/main/res/drawable-xhdpi/ic_operate_order.png
app/src/main/res/drawable-xhdpi/ic_operate_select.png
app/src/main/res/drawable-xhdpi/ic_password_invisible.pngapp/src/main/res/drawable-xhdpi/ic_password_visible.png
app/src/main/res/drawable-xhdpi/ic_search_by.png
app/src/main/res/drawable-xhdpi/ic_search_gray.png
app/src/main/res/drawable-xhdpi/ic_vector_gray.png
app/src/main/res/drawable-xhdpi/ic_vector_pink.png
app/src/main/res/drawable-xhdpi/ic_wx_login.png
app/src/main/res/drawable-xxhdpi/bg_login_home.pngapp/src/main/res/drawable-xxhdpi/function_family_root_net.pngapp/src/main/res/drawable-xxhdpi/ic_add.png
app/src/main/res/drawable-xxhdpi/ic_checked.png
app/src/main/res/drawable-xxhdpi/ic_delete_white.png
app/src/main/res/drawable-xxhdpi/ic_operate_add.png
app/src/main/res/drawable-xxhdpi/ic_operate_finish.png
app/src/main/res/drawable-xxhdpi/ic_operate_order.png
app/src/main/res/drawable-xxhdpi/ic_operate_select.png
app/src/main/res/drawable-xxhdpi/ic_password_invisible.pngapp/src/main/res/drawable-xxhdpi/ic_password_visible.png
app/src/main/res/drawable-xxhdpi/ic_search_by.png
app/src/main/res/drawable-xxhdpi/ic_search_gray.png
app/src/main/res/drawable-xxhdpi/ic_vector_gray.png
app/src/main/res/drawable-xxhdpi/ic_vector_pink.png
app/src/main/res/drawable-xxhdpi/ic_wx_login.png
app/src/main/res/drawable/selector_checkbox.xml
New file @@ -0,0 +1,11 @@ <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android" > <item android:state_checked="true" android:drawable="@drawable/ic_checked" /> <!-- <item--> <!-- android:state_checked="false"--> <!-- android:drawable="@null" />--> <!-- <item--> <!-- android:drawable="@null" /><!– The default one –>--> </selector> app/src/main/res/layout/activity_family_memorabilia.xml
@@ -8,79 +8,752 @@ name="viewModel" type="com.application.zhangshi_app_android.ui.function.FamilyMemorabiliaActivityViewModel"/> </data> <LinearLayout <androidx.drawerlayout.widget.DrawerLayout android:id="@+id/drawerLayout" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".ui.function.FamilyMemorabiliaActivity" android:orientation="vertical"> <com.hjq.bar.TitleBar android:id="@+id/titleBar" tools:openDrawer="start" > <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="@dimen/dp_55" app:layout_constraintTop_toTopOf="parent" android:background="@color/color_title_bar_background" android:paddingHorizontal="@dimen/dp_16" app:leftIcon="@null" app:rightIcon="@null" > android:layout_height="match_parent" tools:context=".ui.function.FamilyMemorabiliaActivity" android:orientation="vertical"> <com.hjq.bar.TitleBar android:id="@+id/titleBar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" app:layout_constraintTop_toTopOf="parent" android:paddingHorizontal="0dp" android:background="@color/color_title_bar_background" app:leftIcon="@null" app:rightIcon="@null" > <ImageView android:id="@+id/iv_menu" android:layout_width="24dp" android:layout_height="24dp" android:layout_marginHorizontal="16dp" android:background="@drawable/ic_menu" android:layout_gravity="center_vertical" /> <FrameLayout android:layout_width="24dp" android:layout_height="24dp" android:layout_marginHorizontal="16dp" android:layout_gravity="center_vertical|end" > <ImageView android:id="@+id/iv_operate" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:background="@drawable/ic_operate" /> </FrameLayout> <LinearLayout android:id="@+id/layout_default" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginHorizontal="56dp" android:gravity="center_vertical" > <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:text="家大事记" android:layout_weight="1" android:textColor="@color/white" android:textSize="@dimen/sp_20" /> <ImageView android:id="@+id/iv_search_default" android:layout_width="@dimen/dp_24" android:layout_height="@dimen/dp_24" android:background="@drawable/ic_search" /> </LinearLayout> <LinearLayout android:id="@+id/layout_search" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginVertical="4dp" android:layout_marginHorizontal="56dp" android:gravity="center_vertical" android:background="@color/white" android:paddingHorizontal="5dp" > <ImageView android:layout_width="24dp" android:layout_height="24dp" android:background="@drawable/ic_search_gray" /> <EditText android:id="@+id/et_search" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:layout_marginStart="5dp" android:textSize="14sp" android:textColor="#61000000" android:background="@null" android:imeOptions="actionSearch" android:text="@={viewModel.stringMutableLiveData}" android:singleLine="true" android:hint="全局搜索" /> <ImageView android:id="@+id/iv_search_type" android:layout_width="24dp" android:layout_height="24dp" android:background="@drawable/ic_search_by" /> </LinearLayout> </com.hjq.bar.TitleBar> <LinearLayout android:id="@+id/layout_data_null" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="start|center_vertical" android:orientation="horizontal" > android:orientation="vertical" android:gravity="center" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/titleBar"> <ImageView android:id="@+id/menu" android:layout_width="@dimen/dp_24" android:layout_height="@dimen/dp_24" android:background="@drawable/ic_menu" android:layout_gravity="center" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/img_sakura" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="@dimen/dp_32" android:text="家大事记" android:textColor="@color/white" android:textSize="@dimen/sp_20" android:layout_marginTop="18dp" android:text="暂时还没有数据哦~\n点击”+”立即创建" android:textSize="14sp" android:textColor="#73000000" /> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="end|center_vertical" android:orientation="horizontal" > <androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" android:layout_height="0dp" android:background="@color/color_normal_background" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toBottomOf="@+id/titleBar" app:layout_constraintVertical_bias="1.0" tools:itemCount="20" tools:layout_editor_absoluteX="-81dp" tools:listitem="@layout/item_family_memorabilia" /> <ImageView android:layout_width="@dimen/dp_24" android:layout_height="@dimen/dp_24" android:background="@drawable/ic_search" /> <ImageView android:layout_width="@dimen/dp_24" android:layout_height="@dimen/dp_24" android:background="@drawable/ic_operate" android:layout_marginStart="@dimen/dp_16" /> </LinearLayout> </com.hjq.bar.TitleBar> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerView" android:layout_width="match_parent" <com.google.android.material.floatingactionbutton.FloatingActionButton android:id="@+id/fab_add" android:layout_width="@dimen/dp_56" android:layout_height="@dimen/dp_56" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="@dimen/dp_25" android:layout_marginBottom="@dimen/dp_44" android:src="@drawable/ic_add" app:fabCustomSize="@dimen/dp_56" /> </androidx.constraintlayout.widget.ConstraintLayout> <androidx.core.widget.NestedScrollView android:layout_width="211dp" android:layout_height="match_parent" android:background="@color/color_normal_background" tools:listitem="@layout/item_family_memorabilia" tools:itemCount="20" /> android:layout_gravity="start" android:background="@color/color_card_pink" android:paddingTop="25dp" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingHorizontal="12dp" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginTop="33dp" android:layout_marginBottom="20dp" android:gravity="center" > <androidx.constraintlayout.utils.widget.ImageFilterView android:layout_width="50dp" android:layout_height="50dp" app:roundPercent="1" android:background="@drawable/img_sakura" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="张喵" android:textSize="18sp" android:textColor="@color/black" android:layout_marginStart="16dp" /> </LinearLayout> <androidx.cardview.widget.CardView android:layout_width="match_parent" android:layout_height="400dp" app:cardBackgroundColor="@color/white" app:cardCornerRadius="10dp" app:cardElevation="0dp" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingVertical="8dp" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="核心板块" android:textColor="@color/black" android:textSize="12sp" android:layout_marginStart="14dp" /> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="#FFF3F3F3" /> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:paddingHorizontal="15dp" android:gravity="center" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/function_family_root_net" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="家根网" android:textColor="@color/black" android:textSize="14sp" android:layout_marginStart="15dp" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/ic_vector_gray" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:paddingHorizontal="15dp" android:gravity="center" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/function_family_root_net" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="家大事记" android:textColor="@color/black" android:textSize="14sp" android:layout_marginStart="15dp" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/ic_vector_gray" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:paddingHorizontal="15dp" android:gravity="center" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/function_family_root_net" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="家庭资产" android:textColor="@color/black" android:textSize="14sp" android:layout_marginStart="15dp" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/ic_vector_gray" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:paddingHorizontal="15dp" android:gravity="center" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/function_family_root_net" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="家庭设备" android:textColor="@color/black" android:textSize="14sp" android:layout_marginStart="15dp" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/ic_vector_gray" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:paddingHorizontal="15dp" android:gravity="center" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/function_family_root_net" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="收藏、荣誉" android:textColor="@color/black" android:textSize="14sp" android:layout_marginStart="15dp" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/ic_vector_gray" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:paddingHorizontal="15dp" android:gravity="center" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/function_family_root_net" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="小医生" android:textColor="@color/black" android:textSize="14sp" android:layout_marginStart="15dp" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/ic_vector_gray" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:paddingHorizontal="15dp" android:gravity="center" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/function_family_root_net" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="保洁、收纳" android:textColor="@color/black" android:textSize="14sp" android:layout_marginStart="15dp" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/ic_vector_gray" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:paddingHorizontal="15dp" android:gravity="center" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/function_family_root_net" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="通讯录" android:textColor="@color/black" android:textSize="14sp" android:layout_marginStart="15dp" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/ic_vector_gray" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:paddingHorizontal="15dp" android:gravity="center" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/function_family_root_net" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="魅宠" android:textColor="@color/black" android:textSize="14sp" android:layout_marginStart="15dp" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/ic_vector_gray" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:paddingHorizontal="15dp" android:gravity="center" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/function_family_root_net" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="家庭收支台账" android:textColor="@color/black" android:textSize="14sp" android:layout_marginStart="15dp" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/ic_vector_gray" /> </LinearLayout> </LinearLayout> </LinearLayout> </androidx.cardview.widget.CardView> <androidx.cardview.widget.CardView android:layout_width="match_parent" android:layout_height="240dp" app:cardBackgroundColor="@color/white" app:cardCornerRadius="10dp" app:cardElevation="0dp" android:layout_marginTop="26dp" android:layout_marginBottom="14dp" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="个人板块" android:textColor="@color/black" android:textSize="12sp" android:layout_marginVertical="8dp" android:layout_marginStart="14dp" /> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="#FFF3F3F3" /> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:paddingHorizontal="15dp" android:gravity="center" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/function_family_root_net" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="成长经历阅历" android:textColor="@color/black" android:textSize="14sp" android:layout_marginStart="15dp" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/ic_vector_gray" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:paddingHorizontal="15dp" android:gravity="center" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/function_family_root_net" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="婚姻" android:textColor="@color/black" android:textSize="14sp" android:layout_marginStart="15dp" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/ic_vector_gray" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:paddingHorizontal="15dp" android:gravity="center" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/function_family_root_net" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="财产" android:textColor="@color/black" android:textSize="14sp" android:layout_marginStart="15dp" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/ic_vector_gray" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:paddingHorizontal="15dp" android:gravity="center" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/function_family_root_net" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="百年心愿" android:textColor="@color/black" android:textSize="14sp" android:layout_marginStart="15dp" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/ic_vector_gray" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:paddingHorizontal="15dp" android:gravity="center" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/function_family_root_net" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="旅游" android:textColor="@color/black" android:textSize="14sp" android:layout_marginStart="15dp" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/ic_vector_gray" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:paddingHorizontal="15dp" android:gravity="center" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/function_family_root_net" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="健康保健" android:textColor="@color/black" android:textSize="14sp" android:layout_marginStart="15dp" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/ic_vector_gray" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:paddingHorizontal="15dp" android:gravity="center" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/function_family_root_net" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="荣誉、证书奖项" android:textColor="@color/black" android:textSize="14sp" android:layout_marginStart="15dp" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/ic_vector_gray" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:paddingHorizontal="15dp" android:gravity="center" > <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/function_family_root_net" /> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="隐私" android:textColor="@color/black" android:textSize="14sp" android:layout_marginStart="15dp" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/ic_vector_gray" /> </LinearLayout> </LinearLayout> </androidx.cardview.widget.CardView> </LinearLayout> </androidx.core.widget.NestedScrollView> </androidx.drawerlayout.widget.DrawerLayout> </layout> app/src/main/res/layout/activity_login.xml
@@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <layout xmlns:app="http://schemas.android.com/apk/res-auto" <layout xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android"> <data> @@ -7,38 +8,40 @@ name="viewModel" type="com.application.zhangshi_app_android.ui.login.LoginActivityViewModel" /> </data> <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="match_parent" android:paddingHorizontal="30dp" android:background="@color/color_normal_background" > <LinearLayout android:layout_width="0dp" <androidx.constraintlayout.widget.ConstraintLayout android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:layout_marginHorizontal="@dimen/dp_30" android:orientation="vertical" app:layout_constraintTop_toTopOf="parent" > <ImageView android:id="@+id/iv_bg_home" android:layout_width="match_parent" android:layout_height="@dimen/dp_165" android:background="@drawable/bg_login_home" /> <androidx.cardview.widget.CardView android:layout_width="match_parent" android:layout_width="wrap_content" android:layout_height="wrap_content" app:cardCornerRadius="@dimen/dp_15" android:layout_marginTop="-15dp" android:background="@drawable/bg_login_home" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <androidx.cardview.widget.CardView android:id="@+id/cardView" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginTop="-20dp" app:cardCornerRadius="15dp" app:cardElevation="0dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="@+id/iv_bg_home" app:layout_constraintStart_toStartOf="@+id/iv_bg_home" app:layout_constraintTop_toBottomOf="@+id/iv_bg_home" > app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/iv_bg_home"> <RelativeLayout android:layout_width="match_parent" @@ -48,151 +51,198 @@ android:id="@+id/iv_bg_zhang" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="@dimen/dp_20" android:background="@drawable/bg_login_zhang" android:layout_centerHorizontal="true" /> android:layout_marginTop="18dp" android:background="@drawable/bg_login_zhang" /> <TextView android:id="@+id/tv_welcome" android:id="@+id/tv_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginHorizontal="@dimen/dp_25" android:layout_centerHorizontal="true" android:layout_marginTop="15dp" android:text="欢迎来到张氏APP" android:textColor="@color/black" android:textSize="@dimen/sp_20" android:textStyle="bold" android:layout_centerHorizontal="true" android:layout_marginVertical="@dimen/dp_20" /> android:textSize="20sp" android:textStyle="bold" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginHorizontal="@dimen/dp_27" android:orientation="vertical" android:layout_below="@id/tv_welcome" > android:layout_below="@id/tv_title" android:layout_marginHorizontal="27dp" android:orientation="vertical"> <TextView android:id="@+id/tv_account" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="账号" android:textColor="#FF484848" android:textSize="@dimen/sp_12" /> android:textSize="12sp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/dp_10" android:background="@drawable/shape_ffd9d9d9_8_stroke" android:paddingVertical="@dimen/dp_12" > android:layout_height="40dp" android:layout_marginTop="7dp" android:background="@drawable/shape_ffd9d9d9_8_stroke"> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginStart="@dimen/dp_16" android:layout_marginStart="16dp" android:background="@null" android:hint="请输入账号" android:inputType="text" android:text="@={viewModel.username}" android:textColor="#FF093878" android:textSize="@dimen/sp_16" android:textColorHint="#FF8F9090" /> android:textSize="14sp" /> </LinearLayout> <TextView android:id="@+id/tv_password" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="@dimen/dp_20" android:layout_marginTop="20dp" android:text="密码" android:textColor="#FF484848" android:textSize="@dimen/sp_12" /> android:textSize="12sp" /> <LinearLayout android:id="@+id/layout_password" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/dp_7" android:paddingVertical="@dimen/dp_12" android:layout_height="40dp" android:layout_marginTop="2dp" android:background="@drawable/shape_ffd9d9d9_8_stroke" android:gravity="center" android:orientation="horizontal"> <EditText android:id="@+id/et_password" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_weight="1" android:background="@null" android:hint="请输入密码" android:inputType="textPassword" android:text="@={viewModel.password}" android:textColor="#FF093878" android:textColorHint="#FF8F9090" android:textSize="14sp" app:passwordVisibility="@{viewModel.passwordVisibility}" /> <ImageView android:id="@+id/iv_password_visibility" android:layout_width="16dp" android:layout_height="20dp" android:layout_marginEnd="12sp" android:background="@{viewModel.passwordVisibility?@drawable/ic_password_visible:@drawable/ic_password_invisible}" /> </LinearLayout> <LinearLayout android:id="@+id/layout_password_again" android:layout_width="match_parent" android:layout_height="40dp" android:layout_marginTop="2dp" android:background="@drawable/shape_ffd9d9d9_8_stroke" android:gravity="center" android:orientation="horizontal" > android:visibility="gone"> <EditText android:id="@+id/et_password_again" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="@dimen/dp_16" android:layout_marginStart="16dp" android:layout_weight="1" android:background="@null" android:hint="请再次输入密码" android:inputType="textPassword" android:text="@={viewModel.againPassword}" android:textColor="#FF093878" android:textSize="@dimen/sp_16" android:hint="请输入账号" android:textColorHint="#FF8F9090" /> android:textSize="14sp" app:passwordVisibility="@{viewModel.againPasswordVisibility}" /> <ImageView android:layout_width="@dimen/dp_16" android:layout_height="@dimen/dp_20" android:layout_marginEnd="@dimen/dp_12" android:background="@drawable/ic_password_invisable" /> android:id="@+id/iv_password_again_visibility" android:layout_width="16dp" android:layout_height="20dp" android:layout_marginEnd="12sp" android:background="@{viewModel.againPasswordVisibility?@drawable/ic_password_visible:@drawable/ic_password_invisible}" /> /> </LinearLayout> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:text="验证码" android:textColor="#FF484848" android:textSize="@dimen/sp_12" android:layout_marginTop="@dimen/dp_20" /> android:textSize="12sp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_marginTop="@dimen/dp_10" > android:layout_marginTop="2dp" android:orientation="horizontal"> <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:background="@drawable/shape_ffd9d9d9_8_stroke" android:paddingVertical="@dimen/dp_12" android:layout_height="40dp" android:layout_weight="6" > android:background="@drawable/shape_ffd9d9d9_8_stroke"> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginStart="@dimen/dp_16" android:layout_marginStart="16dp" android:background="@null" android:hint="请输入验证码" android:inputType="number" android:text="@={viewModel.value}" android:textColor="#FF093878" android:textSize="@dimen/sp_16" android:textColorHint="#FF8F9090" /> android:textSize="14sp" /> </LinearLayout> <ImageView android:id="@+id/iv_captcha" android:layout_width="0dp" android:layout_height="match_parent" android:layout_marginStart="6dp" android:layout_weight="4" android:layout_marginStart="@dimen/dp_6" /> app:imageBase64="@{viewModel.captchaImageLiveData.img}" /> </LinearLayout> <TextView android:id="@+id/tv_login" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/shape_ff093878_10_solid" android:text="注册/登录" android:textColor="@color/white" android:gravity="center" android:paddingVertical="@dimen/dp_10" android:paddingHorizontal="@dimen/dp_77" android:textSize="@dimen/sp_12" android:layout_marginVertical="@dimen/dp_27" android:layout_height="35dp" android:layout_gravity="center" /> android:layout_marginTop="20dp" android:background="@drawable/shape_ff093878_10_solid" android:gravity="center" android:paddingHorizontal="91dp" android:text="登录" android:textColor="@color/white" android:textSize="12sp" /> <TextView android:id="@+id/tv_register" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginVertical="10dp" android:gravity="center" android:text="立即注册" android:textColor="#FF37AADB" android:textSize="10sp" /> </LinearLayout> @@ -200,9 +250,50 @@ </RelativeLayout> </androidx.cardview.widget.CardView> </LinearLayout> <LinearLayout android:id="@+id/layout_wx_login" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:orientation="vertical" app:layout_constraintTop_toBottomOf="@+id/cardView"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginVertical="7dp" android:gravity="center_vertical"> <View android:layout_width="0dp" android:layout_height="0.2dp" android:layout_weight="1" android:background="#80000000" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginHorizontal="18dp" android:text="第三方登录" android:textColor="#80000000" android:textSize="10sp" /> <View android:layout_width="0dp" android:layout_height="0.2dp" android:layout_weight="1" android:background="#80000000" /> </LinearLayout> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/ic_wx_login" /> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout> </layout> app/src/main/res/layout/fragment_function.xml
@@ -16,10 +16,11 @@ android:orientation="vertical" > <com.hjq.bar.TitleBar android:id="@+id/titleBar" android:layout_width="match_parent" android:layout_height="@dimen/dp_55" android:layout_height="wrap_content" android:background="@color/color_title_bar_background" android:paddingHorizontal="@dimen/dp_16" app:layout_constraintEnd_toEndOf="parent" @@ -148,8 +149,8 @@ app:layout_constraintTop_toBottomOf="@id/tv_core_module"> <ImageView android:layout_width="@dimen/dp_24" android:layout_height="@dimen/dp_24" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/function_family_root_net" /> <TextView app/src/main/res/layout/item_family_memorabilia.xml
@@ -15,7 +15,7 @@ <androidx.cardview.widget.CardView android:id="@+id/cardView" android:layout_width="match_parent" android:layout_height="@dimen/dp_40" android:layout_height="40dp" android:layout_margin="@dimen/dp_2" app:cardCornerRadius="@dimen/dp_10" app:cardBackgroundColor="@color/color_card_pink" @@ -24,39 +24,51 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:paddingHorizontal="@dimen/dp_24" > <LinearLayout <RelativeLayout android:id="@+id/layout_title" android:layout_width="match_parent" android:layout_height="@dimen/dp_40" android:gravity="center_vertical" > <CheckBox android:id="@+id/checkbox" android:layout_width="18dp" android:layout_height="18dp" android:layout_marginStart="3dp" android:layout_centerVertical="true" android:button="@drawable/selector_checkbox" android:background="?selectableItemBackgroundBorderless" /> <TextView android:layout_width="0dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginStart="24dp" android:textSize="@dimen/sp_16" android:textColor="@color/black" android:text="张氏app立项" android:text="@{bean.title}" android:layout_weight="1" android:textStyle="bold" /> <TextView android:layout_width="0dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:textSize="@dimen/sp_16" android:textColor="@color/black" android:text="2023.3.1" android:text="@{bean.createTime}" android:textStyle="bold" android:gravity="end" android:layout_marginEnd="24dp" android:layout_alignParentEnd="true" android:layout_centerVertical="true" /> </LinearLayout> </RelativeLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:paddingHorizontal="@dimen/dp_24" > <LinearLayout android:layout_width="match_parent" @@ -75,7 +87,7 @@ <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="01" android:text="@{String.valueOf(bean.id)}" android:textColor="@color/black" android:textSize="@dimen/sp_12" android:textStyle="bold" @@ -98,7 +110,7 @@ <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="张三、李四、张四、李三" android:text="@{bean.people}" android:textColor="@color/black" android:textSize="@dimen/sp_12" android:textStyle="bold" @@ -121,7 +133,7 @@ <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="项目立项" android:text="@{bean.remark}" android:textColor="@color/black" android:textSize="@dimen/sp_12" android:textStyle="bold" app/src/main/res/layout/item_menu_family_root_net.xml
New file @@ -0,0 +1,38 @@ <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content"> <ImageView android:id="@+id/imageView" android:layout_width="13dp" android:layout_height="10dp" android:layout_marginStart="15dp" android:background="@drawable/function_family_root_net" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="家根网" android:textColor="@color/black" android:textSize="10sp" android:layout_marginStart="15dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toEndOf="@+id/imageView" app:layout_constraintTop_toTopOf="parent" /> <ImageView android:id="@+id/imageView2" android:layout_width="15dp" android:layout_height="15dp" android:background="@drawable/ic_delete" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" android:layout_marginEnd="18dp" /> </androidx.constraintlayout.widget.ConstraintLayout> app/src/main/res/layout/pop_operate.xml
New file @@ -0,0 +1,82 @@ <?xml version="1.0" encoding="utf-8"?> <androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" app:cardBackgroundColor="#FFFAD1E0" app:cardCornerRadius="10dp" app:cardElevation="0dp" > <LinearLayout android:layout_width="85dp" android:layout_height="122dp" android:orientation="vertical" android:gravity="center_horizontal" > <TextView android:id="@+id/tv_add" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:text="新建" android:textColor="#FF333333" android:textSize="12sp" app:drawableStartCompat="@drawable/ic_operate_add" android:drawablePadding="5dp" android:layout_weight="1" /> <View android:layout_width="match_parent" android:layout_height="0.3dp" android:background="#FF939393" /> <TextView android:id="@+id/tv_select" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="选择" android:gravity="center" android:textColor="#FF333333" android:textSize="12sp" app:drawableStartCompat="@drawable/ic_operate_select" android:drawablePadding="5dp" android:layout_weight="1" /> <View android:layout_width="match_parent" android:layout_height="0.3dp" android:background="#FF939393" /> <TextView android:id="@+id/tv_from_new_to_old" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="由新到旧" android:gravity="center" android:textColor="#FF333333" android:textSize="12sp" app:drawableStartCompat="@drawable/ic_operate_order" android:drawablePadding="5dp" android:layout_weight="1" /> <View android:layout_width="match_parent" android:layout_height="0.3dp" android:background="#FF939393" /> <TextView android:id="@+id/tv_from_old_to_new" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="由旧到新" android:gravity="center" android:textColor="#FF333333" android:textSize="12sp" app:drawableStartCompat="@drawable/ic_operate_order" android:drawablePadding="5dp" android:layout_weight="1" /> </LinearLayout> </androidx.cardview.widget.CardView> app/src/main/res/layout/pop_search.xml
New file @@ -0,0 +1,106 @@ <?xml version="1.0" encoding="utf-8"?> <androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" app:cardBackgroundColor="#FFFAD1E0" app:cardCornerRadius="10dp" app:cardElevation="0dp" > <LinearLayout android:layout_width="200dp" android:layout_height="180dp" android:orientation="vertical" android:gravity="center_horizontal" > <TextView android:id="@+id/tv_global_search" android:layout_width="match_parent" android:layout_height="0dp" android:gravity="center" android:text="全局搜索" android:textColor="#FF333333" android:textSize="12sp" android:layout_weight="1" /> <View android:layout_width="match_parent" android:layout_height="0.3dp" android:background="#FF939393" /> <TextView android:id="@+id/tv_search_in_family_memorabilia" android:layout_width="match_parent" android:layout_height="0dp" android:gravity="center" android:text="在“家大事记”内搜索" android:textColor="#FF333333" android:textSize="12sp" android:layout_weight="1" /> <View android:layout_width="match_parent" android:layout_height="0.3dp" android:background="#FF939393" /> <TextView android:id="@+id/tv_search_by_title" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:gravity="center" android:text="按“大事记标题”搜索" android:textColor="#FF333333" android:textSize="12sp" /> <View android:layout_width="match_parent" android:layout_height="0.3dp" android:background="#FF939393" /> <TextView android:id="@+id/tv_search_by_people" android:layout_width="match_parent" android:layout_height="0dp" android:gravity="center" android:text="按“人物”搜索" android:textColor="#FF333333" android:textSize="12sp" android:layout_weight="1" /> <View android:layout_width="match_parent" android:layout_height="0.3dp" android:background="#FF939393" /> <TextView android:id="@+id/tv_search_by_time" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:gravity="center" android:text="按“时间”搜索" android:textColor="#FF333333" android:textSize="12sp" /> <View android:layout_width="match_parent" android:layout_height="0.3dp" android:background="#FF939393" /> <TextView android:id="@+id/tv_search_by_place" android:layout_width="match_parent" android:layout_height="0dp" android:gravity="center" android:text="按“地点”搜索" android:textColor="#FF333333" android:textSize="12sp" android:layout_weight="1" /> </LinearLayout> </androidx.cardview.widget.CardView> app/src/main/res/values/colors.xml
@@ -8,11 +8,21 @@ <color name="black">#FF000000</color> <color name="white">#FFFFFFFF</color> <!-- App 样式中引用的颜色 --> <color name="colorPrimary">@color/color_main</color> <color name="colorPrimaryDark">@color/black</color> <color name="colorAccent">#FFF08EBA</color> <color name="windowBackground">#F4F4F4</color> <color name="transparent">#00000000</color> <color name="color_main">#FFF08EBA</color> <color name="color_normal_background">#FFFEF7FC</color> <color name="color_title_bar_background">#FFF08EBA</color> <color name="color_FFF08EBA_text_pink">#FFF08EBA</color> <color name="color_FF666666_text_default">#FF666666</color> <color name="color_card_pink">#FFFFE2EF</color> <color name="color_card_blue">#FFE0EEFE</color> <color name="color_shadow">#88666666</color> </resources> app/src/main/res/values/strings.xml
@@ -1,5 +1,5 @@ <resources> <string name="app_name">zhangshi_app_android</string> <string name="app_name">张氏APP</string> <string name="title_home">首页</string> <string name="title_function">功能</string> app/src/main/res/values/themes.xml
@@ -13,4 +13,31 @@ <item name="android:statusBarColor">?attr/colorPrimaryVariant</item> <!-- Customize your theme here. --> </style> <style name="Theme.app" parent="Theme.AppCompat.DayNight.NoActionBar"> <!-- 窗口背景颜色 --> <item name="android:windowBackground">@color/windowBackground</item> <!-- 应用的主要色调,ActionBar Toolbar 默认使用该颜色 --> <item name="colorPrimary">@color/colorPrimary</item> <!-- 应用的主要暗色调,状态栏默认使用该颜色 --> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <!-- 应用的强调色,CheckBox RadioButton Switch 等一般控件的选中效果默认采用该颜色 --> <item name="colorAccent">@color/colorAccent</item> <!-- 默认文本颜色,Button、TextView 的文字颜色--> <!-- <item name="android:textColor">@color/textColor</item>--> <!-- 默认提示颜色,Button、TextView 的提示文字颜色 --> <!-- <item name="android:textColorHint">@color/textColorHint</item>--> <!-- ActionMode 覆盖 Actionbar 不被顶下来 --> <item name="windowActionModeOverlay">true</item> <item name="android:windowContentOverlay">@null</item> <!-- ActionMode 的颜色 --> <item name="actionModeBackground">@color/colorPrimary</item> <!-- 解决 Android 5.1 及以上版本 Button 英文字符串自动变大写的问题 --> <item name="android:textAllCaps">false</item> <!-- 默认隐藏输入法,开启这个选项后会导致输入对话框在关闭之后不能关闭软键盘 --> <!--<item name="android:windowSoftInputMode">stateHidden</item>--> <!-- 关闭 RecyclerView ScrollView ViewPager 水波纹效果 --> <item name="android:overScrollMode">never</item> </style> </resources> app_base/build.gradle
@@ -58,12 +58,16 @@ // 标题栏框架:https://github.com/getActivity/TitleBar api 'com.github.getActivity:TitleBar:10.0' // 屏幕适配 api 'com.github.JessYanCoding:AndroidAutoSize:v1.2.1' // 基础依赖包,必须要依赖 api 'com.geyifeng.immersionbar:immersionbar:3.2.2' // kotlin扩展(可选) // implementation 'com.geyifeng.immersionbar:immersionbar-ktx:3.2.2' //图片相关 api 'com.github.bumptech.glide:glide:4.11.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0' //内存泄露工具 debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1' app_base/src/main/java/com/android/app_base/base/BaseApplication.java
@@ -7,6 +7,7 @@ import androidx.annotation.NonNull; import com.android.app_base.manager.AppManager; import com.blankj.utilcode.util.Utils; /** * Application基类 @@ -18,6 +19,7 @@ public void onCreate() { super.onCreate(); setApplication(this); Utils.init(this); } /** app_base/src/main/java/com/android/app_base/base/BaseConfig.java
New file @@ -0,0 +1,16 @@ package com.android.app_base.base; /** * @author Ljj * @date 2023.03.02. 15:33 * @desc */ public class BaseConfig { public final static String BASE_URL = "http://47.93.189.255:8080"; public final static int CODE_SUCCESS = 200; public static final int TOKEN_INVALID = 401;//token超时或失效 //页面跳转 public static final String EXTRA_TYPE = "type"; public static final String LOGIN_ACTIVITY = "com.application.zhangshi_app_android.ui.login.LoginActivity"; } app_base/src/main/java/com/android/app_base/base/action/ActivityAction.java
New file @@ -0,0 +1,55 @@ package com.android.app_base.base.action; import android.app.Activity; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; /** * Activity 相关意图 */ public interface ActivityAction { /** * 获取 Context */ Context getContext(); /** * 获取 Activity */ default Activity getActivity() { Context context = getContext(); do { if (context instanceof Activity) { return (Activity) context; } else if (context instanceof ContextWrapper) { context = ((ContextWrapper) context).getBaseContext(); } else { return null; } } while (context != null); return null; } /** * 启动一个 Activity(简化版) */ default void startActivity(Class<? extends Activity> clazz) { startActivity(new Intent(getContext(), clazz)); } /** * 启动一个 Activity */ default void startActivity(Intent intent) { if (!(getContext() instanceof Activity)) { // 如果当前的上下文不是 Activity,调用 startActivity 必须加入新任务栈的标记 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } getContext().startActivity(intent); } } app_base/src/main/java/com/android/app_base/base/action/AnimAction.java
New file @@ -0,0 +1,38 @@ package com.android.app_base.base.action; import com.android.app_base.R; /** * 动画样式 */ public interface AnimAction { /** 默认动画效果 */ int ANIM_DEFAULT = -1; /** 没有动画效果 */ int ANIM_EMPTY = 0; /** 缩放动画 */ int ANIM_SCALE = R.style.ScaleAnimStyle; /** IOS 动画 */ int ANIM_IOS = R.style.IOSAnimStyle; /** 吐司动画 */ int ANIM_TOAST = android.R.style.Animation_Toast; /** 顶部弹出动画 */ int ANIM_TOP = R.style.TopAnimStyle; /** 底部弹出动画 */ int ANIM_BOTTOM = R.style.BottomAnimStyle; /** 左边弹出动画 */ int ANIM_LEFT = R.style.LeftAnimStyle; /** 右边弹出动画 */ int ANIM_RIGHT = R.style.RightAnimStyle; } app_base/src/main/java/com/android/app_base/base/action/ClickAction.java
New file @@ -0,0 +1,31 @@ package com.android.app_base.base.action; import android.view.View; import androidx.annotation.IdRes; /** * 点击行为意图 */ public interface ClickAction extends View.OnClickListener { <V extends View> V findViewById(@IdRes int id); @Override default void onClick(View v) { // 默认不实现,让子类实现 } default void setOnClickListener(@IdRes int... ids) { for (int id : ids) { findViewById(id).setOnClickListener(this); } } default void setOnClickListener(View... views) { for (View view : views) { view.setOnClickListener(this); } } } app_base/src/main/java/com/android/app_base/base/action/HandlerAction.java
New file @@ -0,0 +1,60 @@ package com.android.app_base.base.action; import android.os.Handler; import android.os.Looper; import android.os.SystemClock; /** * 统一处理handler */ public interface HandlerAction { Handler HANDLER = new Handler(Looper.getMainLooper()); /** * 获取 Handler */ default Handler getHandler() { return HANDLER; } /** * 延迟执行 */ default boolean post(Runnable r) { return postDelayed(r, 0); } /** * 延迟一段时间执行 */ default boolean postDelayed(Runnable r, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return postAtTime(r, SystemClock.uptimeMillis() + delayMillis); } /** * 在指定的时间执行 */ default boolean postAtTime(Runnable r, long uptimeMillis) { // 发送和这个 Activity 相关的消息回调 return HANDLER.postAtTime(r, this, uptimeMillis); } /** * 移除单个消息回调 */ default void removeCallbacks(Runnable r) { HANDLER.removeCallbacks(r); } /** * 移除全部消息回调 */ default void removeCallbacks() { HANDLER.removeCallbacksAndMessages(this); } } app_base/src/main/java/com/android/app_base/base/adapter/EditTextAdapter.java
New file @@ -0,0 +1,25 @@ package com.android.app_base.base.adapter; import android.text.method.HideReturnsTransformationMethod; import android.text.method.PasswordTransformationMethod; import android.widget.EditText; import android.widget.ImageView; import androidx.databinding.BindingAdapter; /** * @author Ljj * @date 2023.03.26. 17:38 * @desc */ public class EditTextAdapter { @BindingAdapter({"passwordVisibility"}) public static void setPasswordVisibility(EditText editText, boolean visibility) { if(visibility){ editText.setTransformationMethod(PasswordTransformationMethod.getInstance()); }else { editText.setTransformationMethod(HideReturnsTransformationMethod.getInstance()); } editText.setSelection(editText.length()); } } app_base/src/main/java/com/android/app_base/base/adapter/ImageViewAdapter.java
New file @@ -0,0 +1,32 @@ package com.android.app_base.base.adapter; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.util.Base64; import android.widget.ImageView; import androidx.databinding.BindingAdapter; /** * @author Ljj * @date 2023.03.24. 17:09 * @desc ImageView的 BindingAdapter */ public class ImageViewAdapter { @BindingAdapter({"imageUrl"}) public static void loadImage(ImageView imageView, String url) { } @BindingAdapter({"imageBase64"}) public static void setBase64Image(ImageView imageView, String imageString) { if (imageString == null){ return; } if (imageString.contains(",")){ imageString = imageString.split(",")[1]; } byte[] decodedString = Base64.decode(imageString, Base64.DEFAULT); Bitmap bitmap = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length); imageView.setImageBitmap(bitmap); } } app_base/src/main/java/com/android/app_base/base/dialog/BaseDialog.java
New file @@ -0,0 +1,1345 @@ package com.android.app_base.base.dialog; import static com.blankj.utilcode.util.StringUtils.getString; import android.annotation.SuppressLint; import android.app.Activity; import android.app.Application; import android.content.Context; import android.content.DialogInterface; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Bundle; import android.util.SparseArray; import android.view.Gravity; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import androidx.annotation.ColorInt; import androidx.annotation.DrawableRes; import androidx.annotation.FloatRange; import androidx.annotation.IdRes; import androidx.annotation.LayoutRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.annotation.StyleRes; import androidx.appcompat.app.AppCompatDialog; import androidx.core.content.ContextCompat; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LifecycleRegistry; import com.android.app_base.R; import com.android.app_base.base.BaseApplication; import com.android.app_base.base.action.ActivityAction; import com.android.app_base.base.action.AnimAction; import com.android.app_base.base.action.ClickAction; import com.android.app_base.base.action.HandlerAction; import java.lang.ref.SoftReference; import java.util.ArrayList; import java.util.List; /** * 基类dialog */ public class BaseDialog extends AppCompatDialog implements LifecycleOwner, ActivityAction, AnimAction, HandlerAction, ClickAction,DialogInterface.OnShowListener, DialogInterface.OnCancelListener, DialogInterface.OnDismissListener { private final ListenersWrapper<BaseDialog> mListeners = new ListenersWrapper<>(this); private final LifecycleRegistry mLifecycle = new LifecycleRegistry(this); private List<OnShowListener> mShowListeners; private List<OnCancelListener> mCancelListeners; private List<OnDismissListener> mDismissListeners; public BaseDialog(Context context) { this(context, R.style.BaseDialogStyle); } public BaseDialog(Context context, @StyleRes int themeResId) { super(context, themeResId); } /** * 获取 Dialog 的根布局 */ public View getContentView() { return findViewById(Window.ID_ANDROID_CONTENT); } /** * 获取当前设置重心 */ public int getGravity() { Window window = getWindow(); if (window != null) { WindowManager.LayoutParams params = window.getAttributes(); return params.gravity; } return Gravity.NO_GRAVITY; } /** * 设置宽度 */ public void setWidth(int width) { Window window = getWindow(); if (window != null) { WindowManager.LayoutParams params = window.getAttributes(); params.width = width; window.setAttributes(params); } } /** * 设置高度 */ public void setHeight(int height) { Window window = getWindow(); if (window != null) { WindowManager.LayoutParams params = window.getAttributes(); params.height = height; window.setAttributes(params); } } /** * 设置 Dialog 重心 */ public void setGravity(int gravity) { Window window = getWindow(); if (window != null) { window.setGravity(gravity); } } /** * 设置 Dialog 的动画 */ public void setWindowAnimations(@StyleRes int id) { Window window = getWindow(); if (window != null) { window.setWindowAnimations(id); } } /** * 获取 Dialog 的动画 */ public int getWindowAnimations() { Window window = getWindow(); if (window != null) { return window.getAttributes().windowAnimations; } return BaseDialog.ANIM_DEFAULT; } /** * 设置背景遮盖层开关 */ public void setBackgroundDimEnabled(boolean enabled) { Window window = getWindow(); if (window != null) { if (enabled) { window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); } else { window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); } } } /** * 设置背景遮盖层的透明度(前提条件是背景遮盖层开关必须是为开启状态) */ public void setBackgroundDimAmount(@FloatRange(from = 0.0, to = 1.0) float dimAmount) { Window window = getWindow(); if (window != null) { window.setDimAmount(dimAmount); } } @Override public void dismiss() { removeCallbacks(); View focusView = getCurrentFocus(); if (focusView != null) { BaseApplication.getInstance().getSystemService(InputMethodManager.class).hideSoftInputFromWindow(focusView.getWindowToken(), 0); } super.dismiss(); } /** * 设置一个显示监听器 * * @param listener 显示监听器对象 * @deprecated 请使用 {@link #addOnShowListener(OnShowListener)}} */ @Deprecated @Override public void setOnShowListener(@Nullable DialogInterface.OnShowListener listener) { if (listener == null) { return; } addOnShowListener(new ShowListenerWrapper(listener)); } /** * 设置一个取消监听器 * * @param listener 取消监听器对象 * @deprecated 请使用 {@link #addOnCancelListener(OnCancelListener)} */ @Deprecated @Override public void setOnCancelListener(@Nullable DialogInterface.OnCancelListener listener) { if (listener == null) { return; } addOnCancelListener(new CancelListenerWrapper(listener)); } /** * 设置一个销毁监听器 * * @param listener 销毁监听器对象 * @deprecated 请使用 {@link #addOnDismissListener(OnDismissListener)} */ @Deprecated @Override public void setOnDismissListener(@Nullable DialogInterface.OnDismissListener listener) { if (listener == null) { return; } addOnDismissListener(new DismissListenerWrapper(listener)); } /** * 设置一个按键监听器 * * @param listener 按键监听器对象 * @deprecated 请使用 {@link #setOnKeyListener(OnKeyListener)} */ @Deprecated @Override public void setOnKeyListener(@Nullable DialogInterface.OnKeyListener listener) { super.setOnKeyListener(listener); } public void setOnKeyListener(@Nullable OnKeyListener listener) { super.setOnKeyListener(new KeyListenerWrapper(listener)); } /** * 添加一个显示监听器 * * @param listener 监听器对象 */ public void addOnShowListener(@Nullable OnShowListener listener) { if (mShowListeners == null) { mShowListeners = new ArrayList<>(); super.setOnShowListener(mListeners); } mShowListeners.add(listener); } /** * 添加一个取消监听器 * * @param listener 监听器对象 */ public void addOnCancelListener(@Nullable OnCancelListener listener) { if (mCancelListeners == null) { mCancelListeners = new ArrayList<>(); super.setOnCancelListener(mListeners); } mCancelListeners.add(listener); } /** * 添加一个销毁监听器 * * @param listener 监听器对象 */ public void addOnDismissListener(@Nullable OnDismissListener listener) { if (mDismissListeners == null) { mDismissListeners = new ArrayList<>(); super.setOnDismissListener(mListeners); } mDismissListeners.add(listener); } /** * 移除一个显示监听器 * * @param listener 监听器对象 */ public void removeOnShowListener(@Nullable OnShowListener listener) { if (mShowListeners != null) { mShowListeners.remove(listener); } } /** * 移除一个取消监听器 * * @param listener 监听器对象 */ public void removeOnCancelListener(@Nullable OnCancelListener listener) { if (mCancelListeners != null) { mCancelListeners.remove(listener); } } /** * 移除一个销毁监听器 * * @param listener 监听器对象 */ public void removeOnDismissListener(@Nullable OnDismissListener listener) { if (mDismissListeners != null) { mDismissListeners.remove(listener); } } /** * 设置显示监听器集合 */ private void setOnShowListeners(@Nullable List<OnShowListener> listeners) { super.setOnShowListener(mListeners); mShowListeners = listeners; } /** * 设置取消监听器集合 */ private void setOnCancelListeners(@Nullable List<OnCancelListener> listeners) { super.setOnCancelListener(mListeners); mCancelListeners = listeners; } /** * 设置销毁监听器集合 */ private void setOnDismissListeners(@Nullable List<OnDismissListener> listeners) { super.setOnDismissListener(mListeners); mDismissListeners = listeners; } /** * {@link DialogInterface.OnShowListener} */ @Override public void onShow(DialogInterface dialog) { mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME); if (mShowListeners != null) { for (int i = 0; i < mShowListeners.size(); i++) { mShowListeners.get(i).onShow(this); } } } /** * {@link DialogInterface.OnCancelListener} */ @Override public void onCancel(DialogInterface dialog) { if (mCancelListeners != null) { for (int i = 0; i < mCancelListeners.size(); i++) { mCancelListeners.get(i).onCancel(this); } } } /** * {@link DialogInterface.OnDismissListener} */ @Override public void onDismiss(DialogInterface dialog) { mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY); if (mDismissListeners != null) { for (int i = 0; i < mDismissListeners.size(); i++) { mDismissListeners.get(i).onDismiss(this); } } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE); } @Override protected void onStart() { super.onStart(); mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START); } @Override protected void onStop() { super.onStop(); mLifecycle.handleLifecycleEvent(Lifecycle.Event.ON_STOP); } @SuppressWarnings("unchecked") public static class Builder<B extends Builder> implements LifecycleOwner, ActivityAction,ClickAction{ /** 上下文对象 */ private final Context mContext; /** Dialog 对象 */ private BaseDialog mDialog; /** Dialog 布局 */ private View mContentView; /** 主题样式 */ private int mThemeId = R.style.BaseDialogStyle; /** 动画样式 */ private int mAnimStyle = BaseDialog.ANIM_DEFAULT; /** 重心位置 */ private int mGravity = Gravity.NO_GRAVITY; /** 水平偏移 */ private int mXOffset; /** 垂直偏移 */ private int mYOffset; /** 宽度和高度 */ private int mWidth = ViewGroup.LayoutParams.WRAP_CONTENT; private int mHeight = ViewGroup.LayoutParams.WRAP_CONTENT; /** 背景遮盖层开关 */ private boolean mBackgroundDimEnabled = true; /** 背景遮盖层透明度 */ private float mBackgroundDimAmount = 0.5f; /** 是否能够被取消 */ private boolean mCancelable = true; /** 点击空白是否能够取消 前提是这个对话框可以被取消 */ private boolean mCanceledOnTouchOutside = true; /** Dialog Show 监听 */ private List<OnShowListener> mOnShowListeners; /** Dialog Cancel 监听 */ private List<OnCancelListener> mOnCancelListeners; /** Dialog Dismiss 监听 */ private List<OnDismissListener> mOnDismissListeners; /** Dialog Key 监听 */ private OnKeyListener mOnKeyListener; /** 点击事件集合 */ private SparseArray<OnClickListener> mClickArray; public Builder(Activity activity) { this((Context) activity); } public Builder(Context context) { mContext = context; } /** * 设置主题 id */ public B setThemeStyle(@StyleRes int id) { if (isCreated()) { // Dialog 创建之后不能再设置主题 id throw new IllegalStateException("are you ok?"); } mThemeId = id; return (B) this; } /** * 设置布局 */ public B setContentView(@LayoutRes int id) { // 这里解释一下,为什么要传 new FrameLayout,因为如果不传的话,XML 的根布局获取到的 LayoutParams 对象会为空,也就会导致宽高参数解析不出来 return setContentView(LayoutInflater.from(mContext).inflate(id, new FrameLayout(mContext), false)); } public B setContentView(View view) { mContentView = view; if (isCreated()) { mDialog.setContentView(view); } else { if (mContentView != null) { ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams(); if (layoutParams != null && mWidth == ViewGroup.LayoutParams.WRAP_CONTENT && mHeight == ViewGroup.LayoutParams.WRAP_CONTENT) { // 如果当前 Dialog 的宽高设置了自适应,就以布局中设置的宽高为主 setWidth(layoutParams.width); setHeight(layoutParams.height); } // 如果当前没有设置重心,就自动获取布局重心 if (mGravity == Gravity.NO_GRAVITY) { if (layoutParams instanceof FrameLayout.LayoutParams) { setGravity(((FrameLayout.LayoutParams) layoutParams).gravity); } else if (layoutParams instanceof LinearLayout.LayoutParams) { setGravity(((LinearLayout.LayoutParams) layoutParams).gravity); } else { // 默认重心是居中 setGravity(Gravity.CENTER); } } } } return (B) this; } /** * 设置重心位置 */ public B setGravity(int gravity) { // 适配 Android 4.2 新特性,布局反方向(开发者选项 - 强制使用从右到左的布局方向) mGravity = gravity; if (isCreated()) { mDialog.setGravity(gravity); } return (B) this; } /** * 设置水平偏移 */ public B setXOffset(int offset) { mXOffset = offset; return (B) this; } /** * 设置垂直偏移 */ public B setYOffset(int offset) { mYOffset = offset; return (B) this; } /** * 设置宽度 */ public B setWidth(int width) { mWidth = width; if (isCreated()) { mDialog.setWidth(width); } else { ViewGroup.LayoutParams params = mContentView != null ? mContentView.getLayoutParams() : null; if (params != null) { params.width = width; mContentView.setLayoutParams(params); } } return (B) this; } /** * 设置高度 */ public B setHeight(int height) { mHeight = height; if (isCreated()) { mDialog.setHeight(height); } else { // 这里解释一下为什么要重新设置 LayoutParams // 因为如果不这样设置的话,第一次显示的时候会按照 Dialog 宽高显示 // 但是 Layout 内容变更之后就不会按照之前的设置宽高来显示 // 所以这里我们需要对 View 的 LayoutParams 也进行设置 ViewGroup.LayoutParams params = mContentView != null ? mContentView.getLayoutParams() : null; if (params != null) { params.height = height; mContentView.setLayoutParams(params); } } return (B) this; } /** * 是否可以取消 */ public B setCancelable(boolean cancelable) { mCancelable = cancelable; if (isCreated()) { mDialog.setCancelable(cancelable); } return (B) this; } /** * 是否可以通过点击空白区域取消 */ public B setCanceledOnTouchOutside(boolean cancel) { mCanceledOnTouchOutside = cancel; if (isCreated() && mCancelable) { mDialog.setCanceledOnTouchOutside(cancel); } return (B) this; } /** * 设置动画,已经封装好几种样式,具体可见{@link AnimAction}类 */ public B setAnimStyle(@StyleRes int id) { mAnimStyle = id; if (isCreated()) { mDialog.setWindowAnimations(id); } return (B) this; } /** * 设置背景遮盖层开关 */ public B setBackgroundDimEnabled(boolean enabled) { mBackgroundDimEnabled = enabled; if (isCreated()) { mDialog.setBackgroundDimEnabled(enabled); } return (B) this; } /** * 设置背景遮盖层的透明度(前提条件是背景遮盖层开关必须是为开启状态) */ public B setBackgroundDimAmount(@FloatRange(from = 0.0, to = 1.0) float dimAmount) { mBackgroundDimAmount = dimAmount; if (isCreated()) { mDialog.setBackgroundDimAmount(dimAmount); } return (B) this; } /** * 添加显示监听 */ public B addOnShowListener(@NonNull OnShowListener listener) { if (isCreated()) { mDialog.addOnShowListener(listener); } else { if (mOnShowListeners == null) { mOnShowListeners = new ArrayList<>(); } mOnShowListeners.add(listener); } return (B) this; } /** * 添加取消监听 */ public B addOnCancelListener(@NonNull OnCancelListener listener) { if (isCreated()) { mDialog.addOnCancelListener(listener); } else { if (mOnCancelListeners == null) { mOnCancelListeners = new ArrayList<>(); } mOnCancelListeners.add(listener); } return (B) this; } /** * 添加销毁监听 */ public B addOnDismissListener(@NonNull OnDismissListener listener) { if (isCreated()) { mDialog.addOnDismissListener(listener); } else { if (mOnDismissListeners == null) { mOnDismissListeners = new ArrayList<>(); } mOnDismissListeners.add(listener); } return (B) this; } /** * 设置按键监听 */ public B setOnKeyListener(@NonNull OnKeyListener listener) { if (isCreated()) { mDialog.setOnKeyListener(listener); } else { mOnKeyListener = listener; } return (B) this; } /** * 设置文本 */ public B setText(@IdRes int viewId, @StringRes int stringId) { return setText(viewId, getString(stringId)); } public B setText(@IdRes int id, CharSequence text) { ((TextView) findViewById(id)).setText(text); return (B) this; } /** * 设置文本颜色 */ public B setTextColor(@IdRes int id, @ColorInt int color) { ((TextView) findViewById(id)).setTextColor(color); return (B) this; } /** * 设置提示 */ public B setHint(@IdRes int viewId, @StringRes int stringId) { return setHint(viewId, getString(stringId)); } public B setHint(@IdRes int id, CharSequence text) { ((TextView) findViewById(id)).setHint(text); return (B) this; } /** * 设置可见状态 */ public B setVisibility(@IdRes int id, int visibility) { findViewById(id).setVisibility(visibility); return (B) this; } /** * 设置背景 */ public B setBackground(@IdRes int viewId, @DrawableRes int drawableId) { return setBackground(viewId, ContextCompat.getDrawable(mContext, drawableId)); } public B setBackground(@IdRes int id, Drawable drawable) { findViewById(id).setBackground(drawable); return (B) this; } /** * 设置图片 */ public B setImageDrawable(@IdRes int viewId, @DrawableRes int drawableId) { return setBackground(viewId, ContextCompat.getDrawable(mContext, drawableId)); } public B setImageDrawable(@IdRes int id, Drawable drawable) { ((ImageView) findViewById(id)).setImageDrawable(drawable); return (B) this; } /** * 设置点击事件 */ public B setOnClickListener(@IdRes int id, @NonNull OnClickListener listener) { if (isCreated()) { View view = mDialog.findViewById(id); if (view != null) { view.setOnClickListener(new ViewClickWrapper(mDialog, listener)); } } else { if (mClickArray == null) { mClickArray = new SparseArray<>(); } mClickArray.put(id, listener); } return (B) this; } /** * 创建 */ @SuppressLint("RtlHardcoded") public BaseDialog create() { // 判断布局是否为空 if (mContentView == null) { throw new IllegalArgumentException("are you ok?"); } // 如果当前没有设置重心,就设置一个默认的重心 if (mGravity == Gravity.NO_GRAVITY) { mGravity = Gravity.CENTER; } // 如果当前没有设置动画效果,就设置一个默认的动画效果 if (mAnimStyle == BaseDialog.ANIM_DEFAULT) { switch (mGravity) { case Gravity.TOP: mAnimStyle = BaseDialog.ANIM_TOP; break; case Gravity.BOTTOM: mAnimStyle = BaseDialog.ANIM_BOTTOM; break; case Gravity.LEFT: mAnimStyle = BaseDialog.ANIM_LEFT; break; case Gravity.RIGHT: mAnimStyle = BaseDialog.ANIM_RIGHT; break; default: mAnimStyle = BaseDialog.ANIM_DEFAULT; break; } } mDialog = createDialog(mContext, mThemeId); mDialog.setContentView(mContentView); mDialog.setCancelable(mCancelable); if (mCancelable) { mDialog.setCanceledOnTouchOutside(mCanceledOnTouchOutside); } // 设置参数 Window window = mDialog.getWindow(); if (window != null) { WindowManager.LayoutParams params = window.getAttributes(); params.width = mWidth; params.height = mHeight; params.gravity = mGravity; params.x = mXOffset; params.y = mYOffset; params.windowAnimations = mAnimStyle; window.setAttributes(params); if (mBackgroundDimEnabled) { window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); window.setDimAmount(mBackgroundDimAmount); } else { window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND); } } if (mOnShowListeners != null) { mDialog.setOnShowListeners(mOnShowListeners); } if (mOnCancelListeners != null) { mDialog.setOnCancelListeners(mOnCancelListeners); } if (mOnDismissListeners != null) { mDialog.setOnDismissListeners(mOnDismissListeners); } if (mOnKeyListener != null) { mDialog.setOnKeyListener(mOnKeyListener); } for (int i = 0; mClickArray != null && i < mClickArray.size(); i++) { mContentView.findViewById(mClickArray.keyAt(i)).setOnClickListener(new ViewClickWrapper(mDialog, mClickArray.valueAt(i))); } Activity activity = getActivity(); if (activity != null) { DialogLifecycle.with(activity, mDialog); } return mDialog; } /** * 显示 */ public BaseDialog show() { if (!isCreated()) { create(); } mDialog.show(); return mDialog; } /** * 销毁当前 Dialog */ public void dismiss() { if (mDialog != null) { mDialog.dismiss(); } } @Override public Context getContext() { return mContext; } /** * 当前 Dialog 是否创建了 */ public boolean isCreated() { return mDialog != null; } /** * 当前 Dialog 是否显示了 */ public boolean isShowing() { return mDialog != null && mDialog.isShowing(); } /** * 创建 Dialog 对象(子类可以重写此方法来改变 Dialog 类型) */ protected BaseDialog createDialog(Context context, @StyleRes int themeId) { return new BaseDialog(context, themeId); } /** * 延迟执行 */ public final void post(Runnable r) { if (isShowing()) { mDialog.post(r); } else { addOnShowListener(new ShowPostWrapper(r)); } } /** * 延迟一段时间执行 */ public final void postDelayed(Runnable r, long delayMillis) { if (isShowing()) { mDialog.postDelayed(r, delayMillis); } else { addOnShowListener(new ShowPostDelayedWrapper(r, delayMillis)); } } /** * 在指定的时间执行 */ public final void postAtTime(Runnable r, long uptimeMillis) { if (isShowing()) { mDialog.postAtTime(r, uptimeMillis); } else { addOnShowListener(new ShowPostAtTimeWrapper(r, uptimeMillis)); } } /** * 获取 Dialog 的根布局 */ public View getContentView() { return mContentView; } /** * 根据 id 查找 View */ @Override public <V extends View> V findViewById(@IdRes int id) { if (mContentView == null) { // 没有 setContentView 就想 findViewById ? throw new IllegalStateException("are you ok?"); } return mContentView.findViewById(id); } /** * 获取当前 Dialog 对象 */ @Nullable public BaseDialog getDialog() { return mDialog; } @Nullable @Override public Lifecycle getLifecycle() { if (mDialog != null) { return mDialog.getLifecycle(); } return null; } } /** * Dialog 生命周期管理 */ private static final class DialogLifecycle implements Application.ActivityLifecycleCallbacks, OnShowListener, OnDismissListener { private static void with(Activity activity, BaseDialog dialog) { new DialogLifecycle(activity, dialog); } private BaseDialog mDialog; private Activity mActivity; /** Dialog 动画样式(避免 Dialog 从后台返回到前台后再次触发动画效果) */ private int mDialogAnim; private DialogLifecycle(Activity activity, BaseDialog dialog) { mActivity = activity; dialog.addOnShowListener(this); dialog.addOnDismissListener(this); } @Override public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {} @Override public void onActivityStarted(@NonNull Activity activity) {} @Override public void onActivityResumed(@NonNull Activity activity) { if (mActivity != activity) { return; } if (mDialog != null && mDialog.isShowing()) { // 还原 Dialog 动画样式(这里必须要使用延迟设置,否则还是有一定几率会出现) mDialog.postDelayed(() -> { if (mDialog != null && mDialog.isShowing()) { mDialog.setWindowAnimations(mDialogAnim); } }, 100); } } @Override public void onActivityPaused(@NonNull Activity activity) { if (mActivity != activity) { return; } if (mDialog != null && mDialog.isShowing()) { // 获取 Dialog 动画样式 mDialogAnim = mDialog.getWindowAnimations(); // 设置 Dialog 无动画效果 mDialog.setWindowAnimations(BaseDialog.ANIM_EMPTY); } } @Override public void onActivityStopped(@NonNull Activity activity) {} @Override public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {} @Override public void onActivityDestroyed(@NonNull Activity activity) { if (mActivity != activity) { return; } if (mDialog != null) { mDialog.removeOnShowListener(this); mDialog.removeOnDismissListener(this); if (mDialog.isShowing()) { mDialog.dismiss(); } mDialog = null; } unregisterActivityLifecycleCallbacks(); // 释放 Activity 对象 mActivity = null; } @Override public void onShow(BaseDialog dialog) { mDialog = dialog; registerActivityLifecycleCallbacks(); } @Override public void onDismiss(BaseDialog dialog) { mDialog = null; unregisterActivityLifecycleCallbacks(); } /** * 注册 Activity 生命周期监听 */ private void registerActivityLifecycleCallbacks() { if (mActivity == null) { return; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { mActivity.registerActivityLifecycleCallbacks(this); } else { mActivity.getApplication().registerActivityLifecycleCallbacks(this); } } /** * 反注册 Activity 生命周期监听 */ private void unregisterActivityLifecycleCallbacks() { if (mActivity == null) { return; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { mActivity.unregisterActivityLifecycleCallbacks(this); } else { mActivity.getApplication().unregisterActivityLifecycleCallbacks(this); } } } /** * Dialog 监听包装类(修复原生 Dialog 监听器对象导致的内存泄漏) */ private static final class ListenersWrapper<T extends DialogInterface.OnShowListener & DialogInterface.OnCancelListener & DialogInterface.OnDismissListener> extends SoftReference<T> implements DialogInterface.OnShowListener, DialogInterface.OnCancelListener, DialogInterface.OnDismissListener { private ListenersWrapper(T referent) { super(referent); } @Override public void onShow(DialogInterface dialog) { if (get() != null) { get().onShow(dialog); } } @Override public void onCancel(DialogInterface dialog) { if (get() != null) { get().onCancel(dialog); } } @Override public void onDismiss(DialogInterface dialog) { if (get() != null) { get().onDismiss(dialog); } } } /** * 点击事件包装类 */ private static final class ViewClickWrapper implements View.OnClickListener { private final BaseDialog mDialog; private final OnClickListener mListener; private ViewClickWrapper(BaseDialog dialog, OnClickListener listener) { mDialog = dialog; mListener = listener; } @SuppressWarnings("unchecked") @Override public final void onClick(View v) { mListener.onClick(mDialog, v); } } /** * 显示监听包装类 */ private static final class ShowListenerWrapper extends SoftReference<DialogInterface.OnShowListener> implements OnShowListener { private ShowListenerWrapper(DialogInterface.OnShowListener referent) { super(referent); } @Override public void onShow(BaseDialog dialog) { // 在横竖屏切换后监听对象会为空 if (get() != null) { get().onShow(dialog); } } } /** * 取消监听包装类 */ private static final class CancelListenerWrapper extends SoftReference<DialogInterface.OnCancelListener> implements OnCancelListener { private CancelListenerWrapper(DialogInterface.OnCancelListener referent) { super(referent); } @Override public void onCancel(BaseDialog dialog) { // 在横竖屏切换后监听对象会为空 if (get() != null) { get().onCancel(dialog); } } } /** * 销毁监听包装类 */ private static final class DismissListenerWrapper extends SoftReference<DialogInterface.OnDismissListener> implements OnDismissListener { private DismissListenerWrapper(DialogInterface.OnDismissListener referent) { super(referent); } @Override public void onDismiss(BaseDialog dialog) { // 在横竖屏切换后监听对象会为空 if (get() != null) { get().onDismiss(dialog); } } } /** * 按键监听包装类 */ private static final class KeyListenerWrapper implements DialogInterface.OnKeyListener { private final OnKeyListener mListener; private KeyListenerWrapper(OnKeyListener listener) { mListener = listener; } @Override public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { // 在横竖屏切换后监听对象会为空 if (mListener != null && dialog instanceof BaseDialog) { mListener.onKey((BaseDialog) dialog, event); } return false; } } /** * post 任务包装类 */ private static final class ShowPostWrapper implements OnShowListener { private final Runnable mRunnable; private ShowPostWrapper(Runnable r) { mRunnable = r; } @Override public void onShow(BaseDialog dialog) { if (mRunnable != null) { dialog.removeOnShowListener(this); dialog.post(mRunnable); } } } /** * postDelayed 任务包装类 */ private static final class ShowPostDelayedWrapper implements OnShowListener { private final Runnable mRunnable; private final long mDelayMillis; private ShowPostDelayedWrapper(Runnable r, long delayMillis) { mRunnable = r; mDelayMillis = delayMillis; } @Override public void onShow(BaseDialog dialog) { if (mRunnable != null) { dialog.removeOnShowListener(this); dialog.postDelayed(mRunnable, mDelayMillis); } } } /** * postAtTime 任务包装类 */ private static final class ShowPostAtTimeWrapper implements OnShowListener { private final Runnable mRunnable; private final long mUptimeMillis; private ShowPostAtTimeWrapper(Runnable r, long uptimeMillis) { mRunnable = r; mUptimeMillis = uptimeMillis; } @Override public void onShow(BaseDialog dialog) { if (mRunnable != null) { dialog.removeOnShowListener(this); dialog.postAtTime(mRunnable, mUptimeMillis); } } } /** * 点击监听器 */ public interface OnClickListener<V extends View> { void onClick(BaseDialog dialog, V view); } /** * 显示监听器 */ public interface OnShowListener { /** * Dialog 显示了 */ void onShow(BaseDialog dialog); } /** * 取消监听器 */ public interface OnCancelListener { /** * Dialog 取消了 */ void onCancel(BaseDialog dialog); } /** * 销毁监听器 */ public interface OnDismissListener { /** * Dialog 销毁了 */ void onDismiss(BaseDialog dialog); } /** * 按键监听器 */ public interface OnKeyListener { /** * 触发了按键 */ boolean onKey(BaseDialog dialog, KeyEvent event); } } app_base/src/main/java/com/android/app_base/base/dialog/UIDialog.java
New file @@ -0,0 +1,145 @@ package com.android.app_base.base.dialog; import static com.blankj.utilcode.util.StringUtils.getString; import android.content.Context; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import androidx.annotation.LayoutRes; import androidx.annotation.Nullable; import androidx.annotation.StringRes; import com.android.app_base.R; /** * 具体实现类dialog,通用类型 */ public final class UIDialog { @SuppressWarnings("unchecked") public static class Builder<B extends UIDialog.Builder<?>> extends BaseDialog.Builder<B> { @Nullable private OnListener mListener; private boolean mAutoDismiss = true; private final ViewGroup mContainerLayout; private final TextView mTitleView; private final TextView mContentView; private final TextView mCancelView; private final TextView mConfirmView; public Builder(Context context) { super(context); setContentView(R.layout.dialog_ui); setAnimStyle(BaseDialog.ANIM_IOS); setGravity(Gravity.CENTER); mContainerLayout = findViewById(R.id.ll_ui_container); mTitleView = findViewById(R.id.tv_ui_title); mContentView = findViewById(R.id.tv_content); mCancelView = findViewById(R.id.tv_ui_cancel); mConfirmView = findViewById(R.id.tv_ui_confirm); setOnClickListener(mCancelView, mConfirmView); } public B setCustomView(@LayoutRes int id) { return setCustomView(LayoutInflater.from(getContext()).inflate(id, mContainerLayout, false)); } public B setCustomView(View view) { mContainerLayout.addView(view, 1); return (B) this; } public B setTitle(@StringRes int id) { return setTitle(getString(id)); } public B setTitle(CharSequence text) { mTitleView.setText(text); return (B) this; } public B setContent(CharSequence text) { mContentView.setText(text); return (B) this; } public B setCancel(@StringRes int id) { return setCancel(getString(id)); } public B setCancel(CharSequence text) { mCancelView.setText(text); return (B) this; } public B setConfirm(@StringRes int id) { return setConfirm(getString(id)); } public B setConfirm(CharSequence text) { mConfirmView.setText(text); return (B) this; } public B setAutoDismiss(boolean dismiss) { mAutoDismiss = dismiss; return (B) this; } public void autoDismiss() { if (mAutoDismiss) { dismiss(); } } public B setListener(OnListener listener) { mListener = listener; return (B) this; } @Override public BaseDialog show() { return super.show(); } @Override public void onClick(View view) { int viewId = view.getId(); if (viewId == R.id.tv_ui_confirm) { autoDismiss(); if (mListener == null) { return; } mListener.onConfirm(getDialog()); } else if (viewId == R.id.tv_ui_cancel) { autoDismiss(); if (mListener == null) { return; } mListener.onCancel(getDialog()); } } } public interface OnListener { /** * 点击确定时回调 */ void onConfirm(BaseDialog dialog); /** * 点击取消时回调 */ default void onCancel(BaseDialog dialog) {} } } app_base/src/main/java/com/android/app_base/base/view/BaseActivity.java
@@ -20,12 +20,12 @@ import com.android.app_base.action.TitleBarAction; import com.android.app_base.base.BaseApplication; import com.android.app_base.base.action.ClickAction; import com.android.app_base.base.viewmodel.BaseViewModel; import com.android.app_base.base.StateViewEnum; import com.android.app_base.utils.ScreenSizeUtils; import com.blankj.utilcode.util.AdaptScreenUtils; import com.blankj.utilcode.util.ToastUtils; import com.gyf.immersionbar.ImmersionBar; import com.hjq.bar.OnTitleBarListener; import com.hjq.bar.TitleBar; import java.lang.reflect.ParameterizedType; @@ -34,7 +34,7 @@ /** * Activity基类,所有的 Activity 都要继承此类 */ public abstract class BaseActivity<V extends ViewDataBinding,VM extends BaseViewModel> extends AppCompatActivity implements TitleBarAction{ public abstract class BaseActivity<V extends ViewDataBinding,VM extends BaseViewModel> extends AppCompatActivity implements TitleBarAction, ClickAction { protected V binding; protected VM viewModel; private int viewModelId; @@ -49,10 +49,6 @@ private ImmersionBar mImmersionBar; @Override protected void onResume() { super.onResume(); } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { @@ -63,13 +59,16 @@ initParam(); //页面view初始化方法 initView(); //页面数据初始化方法 initData(); //页面事件监听的方法,用于ViewModel层转到View层的事件注册 initLiveDataObserve(); ScreenSizeUtils.setCustomDensity(this, BaseApplication.getInstance()); } @Override protected void onResume() { super.onResume(); //页面数据初始化方法 initData(); } @Override protected void onDestroy() { @@ -163,6 +162,12 @@ default: break; } } }); viewModel.getMessageLivaData().observe(this, new Observer<String>() { @Override public void onChanged(String message) { ToastUtils.showShort(message); } }); } @@ -287,6 +292,7 @@ InputMethodManager manager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); if (manager != null && manager.isActive(view)) { manager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS); view.clearFocus(); } } } app_base/src/main/java/com/android/app_base/base/viewmodel/BaseViewModel.java
@@ -31,7 +31,8 @@ /** * 控制状态视图的LiveData */ private MutableLiveData<StateViewEnum> stateViewLiveData; protected MutableLiveData<StateViewEnum> stateViewLiveData; protected MutableLiveData<String> messageLiveData; //管理RxJava,主要针对RxJava异步操作造成的内存泄漏 private CompositeDisposable mCompositeDisposable; @@ -66,6 +67,12 @@ } return stateViewLiveData; } public LiveData<String> getMessageLivaData(){ if(messageLiveData == null){ messageLiveData = new MutableLiveData<>(); } return messageLiveData; } /** * 更改状态视图的状态 */ app_base/src/main/java/com/android/app_base/http/OkHttpHelper.java
@@ -7,6 +7,7 @@ import com.android.app_base.BuildConfig; import com.android.app_base.base.BaseApplication; import com.android.app_base.http.interceptor.CacheInterceptor; import com.android.app_base.http.interceptor.LogInterceptor; import com.blankj.utilcode.util.LogUtils; import com.franmontiel.persistentcookiejar.PersistentCookieJar; import com.franmontiel.persistentcookiejar.cache.SetCookieCache; @@ -69,6 +70,7 @@ return chain.proceed(build); } }); clientBuilder.addInterceptor(new LogInterceptor());//拦截器添加公共参数 //log日志拦截 if (BuildConfig.DEBUG) { clientBuilder.addInterceptor(new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() { app_base/src/main/java/com/android/app_base/http/ResultData.java
@@ -13,7 +13,7 @@ /** * 提示信息 */ private String message; private String msg; /** * 返回数据 */ @@ -35,11 +35,11 @@ this.code = code; } public String getMessage() { return message; public String getMsg() { return msg; } public void setMessage(String message) { this.message = message; public void setMsg(String msg) { this.msg = msg; } } app_base/src/main/java/com/android/app_base/http/interceptor/LogInterceptor.java
New file @@ -0,0 +1,93 @@ package com.android.app_base.http.interceptor; import android.annotation.SuppressLint; import android.text.TextUtils; import com.android.app_base.base.BaseConfig; import com.android.app_base.manager.AppManager; import com.android.app_base.manager.UserManager; import com.blankj.utilcode.util.ActivityUtils; import com.blankj.utilcode.util.DeviceUtils; import com.blankj.utilcode.util.NetworkUtils; import com.blankj.utilcode.util.PhoneUtils; import com.blankj.utilcode.util.RomUtils; import com.blankj.utilcode.util.ToastUtils; import org.json.JSONException; import org.json.JSONObject; import java.io.IOException; import java.nio.charset.Charset; import okhttp3.HttpUrl; import okhttp3.Interceptor; import okhttp3.Request; import okhttp3.Response; import okhttp3.ResponseBody; import okio.Buffer; import okio.BufferedSource; /** * 网络请求拦截器,添加公共参数 */ public class LogInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException { Request request = chain.request(); //以参数的方式添加 //重定向URL @SuppressLint("MissingPermission") HttpUrl modifiedUrl = request.url().newBuilder() //添加的公共参数 .addQueryParameter("deviceId", PhoneUtils.getDeviceId()) .addQueryParameter("udid", "") .addQueryParameter("channel", "") .addQueryParameter("version", "") .addQueryParameter("brand", DeviceUtils.getManufacturer())//手机品牌 .addQueryParameter("model", DeviceUtils.getModel()) // .addQueryParameter("isWifi", NetworkUtils.isWifiConnected() ? "1" : "0") .addQueryParameter("ui", RomUtils.getRomInfo().getName()) .addQueryParameter("uiVersion", RomUtils.getRomInfo().getVersion()) .addQueryParameter("os", "android") .addQueryParameter("osVersion", DeviceUtils.getSDKVersionName()) .addQueryParameter("isSimulator", DeviceUtils.isEmulator() ? "1" : "0") .addQueryParameter("imei", PhoneUtils.getIMEI()) .addQueryParameter("oaid", "android") .addQueryParameter("androidId", DeviceUtils.getAndroidID()) // .addQueryParameter("networkType", NetworkUtils.getNetworkType().name()) // .addQueryParameter("mac", DeviceUtils.getMacAddress()) .build(); Request.Builder builder = request.newBuilder(); //添加头部token String token = UserManager.getInstance().getToken(); if (!TextUtils.isEmpty(token)) { builder.addHeader("Authorization", token); } Request newRequest = builder.url(modifiedUrl).build(); Response response = chain.proceed(newRequest); //解决response.body().string();只能打印一次 ResponseBody responseBody = response.body(); BufferedSource source = responseBody.source(); source.request(Long.MAX_VALUE); // Buffer the entire body. Buffer buffer = source.getBuffer(); Charset UTF8 = Charset.forName("UTF-8"); String string = buffer.clone().readString(UTF8); try { JSONObject jsonObject = new JSONObject(string); int code = jsonObject.getInt("code"); if (code == BaseConfig.TOKEN_INVALID ) { ToastUtils.showShort("登录状态失效,请重新登录"); UserManager.getInstance().clearToken(); AppManager.getAppManager().finishAllActivity(); AppManager.getAppManager().startActivityForName(BaseConfig.LOGIN_ACTIVITY); } } catch (JSONException e) { throw new RuntimeException(e); } return response; } } app_base/src/main/java/com/android/app_base/manager/AppManager.java
@@ -2,6 +2,7 @@ import android.app.Activity; import android.content.Intent; import android.text.TextUtils; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; @@ -93,6 +94,14 @@ return ActivityUtils.startActivity(intent); } public void startActivityForName(String name) { if(TextUtils.isEmpty(name))return; try { startActivity(Class.forName(name)); } catch (ClassNotFoundException e) { e.printStackTrace(); } } /** * 结束当前Activity(堆栈中最后一个压入的) */ app_base/src/main/java/com/android/app_base/manager/UserManager.java
New file @@ -0,0 +1,34 @@ package com.android.app_base.manager; import com.android.app_base.utils.SPUtils; /** * @author Ljj * @date 2023.03.25. 19:50 * @desc */ public class UserManager { private static UserManager instance; private UserManager(){ } public static UserManager getInstance() { if (instance == null){ instance = new UserManager(); } return instance; } public void setToken(String token){ SPUtils.getInstance("tokenInfo").put("token",token); } public void clearToken(){ SPUtils.getInstance("tokenInfo").clear(); } public String getToken(){ return SPUtils.getInstance("tokenInfo").getString("token"); } } app_base/src/main/java/com/android/app_base/utils/RxUtils.java
New file @@ -0,0 +1,24 @@ package com.android.app_base.utils; import io.reactivex.Observable; import io.reactivex.ObservableSource; import io.reactivex.ObservableTransformer; import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.schedulers.Schedulers; /** * @author Ljj * @date 2023.03.24. 17:42 * @desc */public class RxUtils { public static <T> ObservableTransformer<T, T> schedulersTransformer() { return upstream -> upstream.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); } } app_base/src/main/java/com/android/app_base/utils/ScreenSizeUtils.java
@@ -89,6 +89,7 @@ return 0; } //今日头条屏幕适配方案 private static float sNoncompatDensity; private static float sNoncompatScaledDensity; public static void setCustomDensity(@NonNull Activity activity, @NonNull final Application application){ app_base/src/main/java/com/android/app_base/widget/CustomScrollView.java
File was deleted app_base/src/main/res/anim/bottom_in_window.xml
New file @@ -0,0 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="400" android:fromYDelta="100%p" /> </set> app_base/src/main/res/anim/bottom_out_window.xml
New file @@ -0,0 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="400" android:toYDelta="100%p" /> </set> app_base/src/main/res/anim/ios_in_window.xml
New file @@ -0,0 +1,17 @@ <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <scale android:duration="300" android:fromXScale="1.1" android:fromYScale="1.1" android:pivotX="50%" android:pivotY="50%" android:toXScale="1.0" android:toYScale="1.0" /> <alpha android:duration="300" android:fromAlpha="0.0" android:toAlpha="1.0" /> </set> app_base/src/main/res/anim/ios_out_window.xml
New file @@ -0,0 +1,18 @@ <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <scale android:duration="300" android:fromXScale="1.0" android:fromYScale="1.0" android:pivotX="50%" android:pivotY="50%" android:toXScale="1.1" android:toYScale="1.1" /> <alpha android:duration="300" android:fromAlpha="1.0" android:toAlpha="0.0" /> </set> app_base/src/main/res/anim/left_in_window.xml
New file @@ -0,0 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="400" android:fromXDelta="-100%p" /> </set> app_base/src/main/res/anim/left_out_window.xml
New file @@ -0,0 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="400" android:toXDelta="-100%p" /> </set> app_base/src/main/res/anim/pop_add_hide.xml
New file @@ -0,0 +1,16 @@ <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <alpha android:duration="200" android:fromAlpha="1.0" android:toAlpha="0.0"/> <scale android:duration="200" android:fromXScale="1.0" android:fromYScale="1.0" android:interpolator="@android:anim/accelerate_interpolator" android:pivotX="85%" android:pivotY="0%" android:toXScale="0" android:toYScale="0"/> </set> app_base/src/main/res/anim/pop_add_show.xml
New file @@ -0,0 +1,16 @@ <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <alpha android:duration="200" android:fromAlpha="0.0" android:toAlpha="1.0"/> <scale android:duration="200" android:fromXScale="0" android:fromYScale="0" android:interpolator="@android:anim/accelerate_interpolator" android:pivotX="85%" android:pivotY="0%" android:toXScale="1.0" android:toYScale="1.0"/> </set> app_base/src/main/res/anim/popup_down.xml
New file @@ -0,0 +1,10 @@ <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="200"> <scale android:fromXScale="1.0" android:fromYScale="0.0" android:interpolator="@android:anim/accelerate_decelerate_interpolator" android:toXScale="1.0" android:toYScale="1.0" /> </set> app_base/src/main/res/anim/popup_up.xml
New file @@ -0,0 +1,10 @@ <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="200"> <scale android:fromXScale="1.0" android:fromYScale="1.0" android:interpolator="@android:anim/accelerate_decelerate_interpolator" android:toXScale="1.0" android:toYScale="0.0"/> </set> app_base/src/main/res/anim/right_in_window.xml
New file @@ -0,0 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="400" android:fromXDelta="100%p" /> </set> app_base/src/main/res/anim/right_out_window.xml
New file @@ -0,0 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="400" android:toXDelta="100%p" /> </set> app_base/src/main/res/anim/scale_in_window.xml
New file @@ -0,0 +1,39 @@ <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" > <scale android:duration="135" android:fromXScale="0.8" android:fromYScale="0.8" android:pivotX="50%" android:pivotY="50%" android:toXScale="1.05" android:toYScale="1.05" /> <scale android:duration="105" android:fromXScale="1.05" android:fromYScale="1.05" android:pivotX="50%" android:pivotY="50%" android:startOffset="135" android:toXScale="0.95" android:toYScale="0.95" /> <scale android:duration="60" android:fromXScale="0.95" android:fromYScale="0.95" android:pivotX="50%" android:pivotY="50%" android:startOffset="240" android:toXScale="1.0" android:toYScale="1.0" /> <alpha android:duration="90" android:fromAlpha="0.0" android:interpolator="@android:anim/accelerate_interpolator" android:toAlpha="1.0" /> </set> app_base/src/main/res/anim/scale_out_window.xml
New file @@ -0,0 +1,19 @@ <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" > <scale android:duration="150" android:fromXScale="1.0" android:fromYScale="1.0" android:pivotX="50%" android:pivotY="50%" android:toXScale="0.6" android:toYScale="0.6" /> <alpha android:duration="150" android:fromAlpha="1.0" android:interpolator="@android:anim/accelerate_interpolator" android:toAlpha="0.0" /> </set> app_base/src/main/res/anim/top_in_window.xml
New file @@ -0,0 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="400" android:fromYDelta="-100%p" /> </set> app_base/src/main/res/anim/top_out_window.xml
New file @@ -0,0 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android"> <translate android:duration="400" android:toYDelta="-100%p" /> </set> app_base/src/main/res/layout/dialog_ui.xml
New file @@ -0,0 +1,73 @@ <?xml version="1.0" encoding="utf-8"?> <androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="@dimen/dp_240" android:layout_height="wrap_content" android:layout_gravity="center" app:cardBackgroundColor="#FFFFFF" app:cardCornerRadius="15dp" app:cardElevation="0px" > <LinearLayout android:id="@+id/ll_ui_container" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" android:paddingTop="@dimen/dp_20"> <TextView android:id="@+id/tv_ui_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:textColor="#DE000000" android:textSize="20sp" android:textStyle="bold" tools:text="标题" /> <TextView android:id="@+id/tv_content" android:padding="10dp" android:text="内容" android:gravity="center" android:textColor="#FF757575" android:textSize="16sp" android:layout_width="match_parent" android:layout_height="wrap_content"/> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <TextView android:id="@+id/tv_ui_cancel" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:focusable="true" android:gravity="center" android:paddingVertical="@dimen/dp_15" android:text="取消" android:textColor="#FFF83F39" android:textSize="@dimen/sp_14" /> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/tv_ui_confirm" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:focusable="true" android:gravity="center" android:paddingVertical="15dp" android:text="确定" android:textColor="#2B83DD" android:textSize="14sp" /> </LinearLayout> </LinearLayout> </androidx.cardview.widget.CardView> app_base/src/main/res/values-sw1024dp/dimens.xml
File was deleted app_base/src/main/res/values-sw1280dp/dimens.xml
File was deleted app_base/src/main/res/values-sw1365dp/dimens.xml
File was deleted app_base/src/main/res/values-sw1440dp/dimens.xml
File was deleted app_base/src/main/res/values-sw240dp/dimens.xml
File was deleted app_base/src/main/res/values-sw320dp/dimens.xml
File was deleted app_base/src/main/res/values-sw360dp/dimens.xml
File was deleted app_base/src/main/res/values-sw384dp/dimens.xml
File was deleted app_base/src/main/res/values-sw392dp/dimens.xml
File was deleted app_base/src/main/res/values-sw400dp/dimens.xml
File was deleted app_base/src/main/res/values-sw410dp/dimens.xml
File was deleted app_base/src/main/res/values-sw411dp/dimens.xml
File was deleted app_base/src/main/res/values-sw432dp/dimens.xml
File was deleted app_base/src/main/res/values-sw480dp/dimens.xml
File was deleted app_base/src/main/res/values-sw533dp/dimens.xml
File was deleted app_base/src/main/res/values-sw592dp/dimens.xml
File was deleted app_base/src/main/res/values-sw600dp/dimens.xml
File was deleted app_base/src/main/res/values-sw640dp/dimens.xml
File was deleted app_base/src/main/res/values-sw662dp/dimens.xml
File was deleted app_base/src/main/res/values-sw720dp/dimens.xml
File was deleted app_base/src/main/res/values-sw768dp/dimens.xml
File was deleted app_base/src/main/res/values-sw800dp/dimens.xml
File was deleted app_base/src/main/res/values-sw811dp/dimens.xml
File was deleted app_base/src/main/res/values-sw820dp/dimens.xml
File was deleted app_base/src/main/res/values-sw960dp/dimens.xml
File was deleted app_base/src/main/res/values-sw961dp/dimens.xml
File was deleted app_base/src/main/res/values/arrts.xml
@@ -9,4 +9,5 @@ <attr name="border_radius" format="dimension"/> </declare-styleable> </resources> app_base/src/main/res/values/styles.xml
New file @@ -0,0 +1,77 @@ <?xml version="1.0" encoding="utf-8"?> <resources> <style name="pop_add"> <item name="android:windowEnterAnimation">@anim/pop_add_show</item> <item name="android:windowExitAnimation">@anim/pop_add_hide</item> </style> <!-- 对话框默认样式 --> <style name="BaseDialogStyle" parent="Theme.AppCompat.DayNight.Dialog.Alert"><!-- @android:style/Theme.Dialog --> <!-- 无边框 --> <item name="android:windowFrame">@null</item> <!-- 浮在 Activity 之上 --> <item name="android:windowIsFloating">true</item> <!-- 半透明 --> <item name="android:windowIsTranslucent">true</item> <!-- 背景透明 --> <item name="android:windowBackground">@android:color/transparent</item> <!-- 遮盖层 --> <item name="android:backgroundDimEnabled">true</item> <!-- 无标题 --> <item name="android:windowNoTitle">true</item> <!-- 动画效果 --> <item name="android:windowEnterAnimation">@anim/scale_in_window</item> <item name="android:windowExitAnimation">@anim/scale_out_window</item> <!-- Base.Theme.AppCompat.Light.Dialog.Alert 特有的属性,用于指定默认宽度,这里需要禁用 --> <item name="android:windowMinWidthMajor">0dp</item> <item name="android:windowMinWidthMinor">0dp</item> <!-- 解决 ActionBar 占位导致 Dialog 无法全屏显示的问题 --> <item name="windowActionBar">false</item> <item name="windowNoTitle">true</item> <!-- ActionMode 覆盖 Actionbar,不顶下来 --> <item name="windowActionModeOverlay">true</item> <item name="android:windowContentOverlay">@null</item> <!-- 不感知敏感的切换 --> <!--<item name="android:configChanges">orientation|screenSize|keyboardHidden</item>--> <!-- 默认隐藏输入法 --> <!--<item name="android:windowSoftInputMode">stateHidden</item>--> <!-- Dialog 全屏显示 --> <!--<item name="android:windowFullscreen">true</item>--> </style> <!-- 缩放动画 --> <style name="ScaleAnimStyle" parent="android:Animation"> <item name="android:windowEnterAnimation">@anim/scale_in_window</item> <item name="android:windowExitAnimation">@anim/scale_out_window</item> </style> <!-- ios 动画 --> <style name="IOSAnimStyle" parent="android:Animation"> <item name="android:windowEnterAnimation">@anim/ios_in_window</item> <item name="android:windowExitAnimation">@anim/ios_out_window</item> </style> <!-- 顶部弹出动画 --> <style name="TopAnimStyle" parent="android:Animation"> <item name="android:windowEnterAnimation">@anim/top_in_window</item> <item name="android:windowExitAnimation">@anim/top_out_window</item> </style> <!-- 底部弹出动画 --> <style name="BottomAnimStyle" parent="android:Animation"> <item name="android:windowEnterAnimation">@anim/bottom_in_window</item> <item name="android:windowExitAnimation">@anim/bottom_out_window</item> </style> <!-- 左边弹出动画 --> <style name="LeftAnimStyle" parent="android:Animation"> <item name="android:windowEnterAnimation">@anim/left_in_window</item> <item name="android:windowExitAnimation">@anim/left_out_window</item> </style> <!-- 右边弹出动画 --> <style name="RightAnimStyle" parent="android:Animation"> <item name="android:windowEnterAnimation">@anim/right_in_window</item> <item name="android:windowExitAnimation">@anim/right_out_window</item> </style> </resources>