个人中心、图片裁剪、图片上传、收货地址、消息推送、权限管理等功能开发与一键式封装(一)
1、个人中心界面实现
1.1 个人中心中RecycleView内地址和设置的item实现
1.2 收货地址和设置的item类型
1.3 收货地址和设置的item数据适配器
1.4 个人中心根类
1.5 效果图
2、订单列表逻辑梳理和实现-1
2.1 订单数据转换类
2.2 订单数据适配类
2.3 订单的根类
2.4 个人中心根类
2.5 效果图
3、个人信息更新实现-1
3.1 个人信息布局实现
3.2 个人信息界面更改的设置
4、个人信息更新实现-2
4.1 更新生日、性别
4.2 效果图
5、一键式相机,图片处理剪裁和动态权限封装
5.1 照片处理类
5.2 存储照片处理相关值
5.3 请求码存储类
5.4 照片处理类,补充拍照、从相册选择的逻辑
5.5 照相机调用类
5.6 动态权限处理类
5.7 头像的图片剪裁逻辑处理
6、收货地址管理功能实现
6.1 地址管理的入口
6.2 个人中心根类设置地址信息
6.3 效果图
在个人中心根类中,1)设置了每个按钮的点击事件以及要跳转的Fragment的逻辑,2)在RecyclerView中添加了两条item,设置了数据,给RecyclerView设置了item的点击的监听事件;在监听事件中根据item的id选择跳转的Fragment。
位于latte-ec模块main->personal->list包下的ListBean。
主要作用:RecycleView内的数据处理,采用构造者模式,传入和保存数据。
public class ListBean implements MultiItemEntity {
private int mItemType = 0;//item的类型
private String mImageUrl = null;//头像
private String mText = null;
private String mValue = null;
private int mId = 0;
private LatteDelegate mDelegate = null;//需要跳转,传入根布局
private CompoundButton.OnCheckedChangeListener mOnCheckedChangeListener = null;//推送设置
public ListBean(int mItemType, String mImageUrl, String mText, String mValue, int mId, LatteDelegate mDelegate, CompoundButton.OnCheckedChangeListener mOnCheckedChangeListener) {
this.mItemType = mItemType;
this.mImageUrl = mImageUrl;
this.mText = mText;
this.mValue = mValue;
this.mId = mId;
this.mDelegate = mDelegate;
this.mOnCheckedChangeListener = mOnCheckedChangeListener;
}
public String getImageUrl() {
return mImageUrl;
}
public String getText() {
if (mText == null) {
return "";
}
return mText;
}
public String getValue() {
if (mValue == null) {
return "";
}
return mValue;
}
public int getId() {
return mId;
}
public LatteDelegate getDelegate() {
return mDelegate;
}
public CompoundButton.OnCheckedChangeListener getmOnCheckedChangeListener() {
return mOnCheckedChangeListener;
}
@Override
public int getItemType() {
return mItemType;
}
public static final class Builder {
private int id = 0;
private int itemType = 0;
private String imageUrl = null;
private String text = null;
private String value = null;
private CompoundButton.OnCheckedChangeListener onCheckedChangeListener = null;
private LatteDelegate delegate = null;
public Builder setId(int id) {
this.id = id;
return this;
}
public Builder setItemType(int itemType) {
this.itemType = itemType;
return this;
}
public Builder setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
return this;
}
public Builder setText(String text) {
this.text = text;
return this;
}
public Builder setValue(String value) {
this.value = value;
return this;
}
public Builder setOnCheckedChangeListener(CompoundButton.OnCheckedChangeListener onCheckedChangeListener) {
this.onCheckedChangeListener = onCheckedChangeListener;
return this;
}
public Builder setDelegate(LatteDelegate delegate) {
this.delegate = delegate;
return this;
}
public ListBean build() {
return new ListBean(itemType, imageUrl, text, value, id, delegate, onCheckedChangeListener);
}
}
}
位于latte-ec模块main->personal->list包下的ListItemType。
主要作用:RecycleView内的数据的item类型。
public class ListItemType {
public static final int ITEM_NORMAL = 20;//数据信息类型
}
位于latte-ec模块main->personal->list包下的ListItemAdapter。
主要作用:RecycleView内的数据适配器,对ListBean中数据进行转化。
public class ListAdapter extends BaseMultiItemQuickAdapter {
public ListAdapter(List data) {
super(data);
addItemType(ListItemType.ITEM_NORMAL, R.layout.arrow_item_layout);
}
@Override
protected void convert(BaseViewHolder helper, ListBean item) {//转化数据,将设置的数据匹配到view中
switch (helper.getItemViewType()){
case 20:
helper.setText(R.id.tv_arrow_text,item.getText());
helper.setText(R.id.tv_arrow_value,item.getValue());
break;
default:
break;
}
}
}
位于latte-ec模块main->personal包下的PersonalDelegate。
主要作用:个人中心根类,传入设置和地址的item数据,通过adapter进行显示。
public class PersonalDelegate extends BottomItemDelegate {
@BindView(R2.id.rv_personal_setting)
RecyclerView mRvSettings = null;
@Override
public Object setLayout() {
return R.layout.delegate_personal;
}
@Override
public void onBindView(@Nullable Bundle savedInstanceState, View rootView) {
final ListBean address = new ListBean.Builder()//为recycleView添加的item
.setItemType(ListItemType.ITEM_NORMAL)
.setId(1)
.setText("收货地址")
.build();
final ListBean system = new ListBean.Builder()
.setItemType(ListItemType.ITEM_NORMAL)
.setId(2)
.setText("系统地址")
.build();
final List data = new ArrayList<>();
data.add(address);
data.add(system);
//设置RecycleView
final LinearLayoutManager manager = new LinearLayoutManager(getContext());
mRvSettings.setLayoutManager(manager);
final ListAdapter adapter = new ListAdapter(data);
mRvSettings.setAdapter(adapter);
}
}
位于latte-ec模块main->personal->list->order包下的OrderListDataConverter。
主要作用:订单中点击事件的list数据转换,将JSON数据保存到ENTITY中。
public class OrderListDataConverter extends DataConverter {
@Override
public ArrayList convert() {
final JSONArray array = JSON.parseObject(getJsonData()).getJSONArray("data");
final int size = array.size();
for (int i = 0; i < size; i++) {
final JSONObject data = array.getJSONObject(i);
final String thumb = data.getString("thumb");
final String title = data.getString("title");
final int id = data.getInteger("id");
final double price = data.getDouble("price");
final String time = data.getString("time");
final MultipleItemEntity entity = MultipleItemEntity.builder()
.setItemType(OrderListItemType.ITEM_ORDER_LIST)
.setField(MultipleFields.ID, id)
.setField(MultipleFields.IMAGE_URL, thumb)
.setField(MultipleFields.TITLE, title)
.setField(OrderItemFields.PRICE, price)
.setField(OrderItemFields.TIME, time)
.build();
ENTITIES.add(entity);
}
return ENTITIES;
}
}
位于latte-ec模块main->personal->list->order包下的OrderListAdapter。
主要作用:将从Conterver中存储的ENTITY中,通过key获取值,将值与视图View绑定。
public class OrderListAdapter extends MultipleRecyclerAdapter {
private static final RequestOptions OPTIONS = new RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.ALL)
.centerCrop()
.dontAnimate();
protected OrderListAdapter(List data) {
super(data);
addItemType(OrderListItemType.ITEM_ORDER_LIST, R.layout.item_order_list);
}
@SuppressLint("SetTextI18n")
@Override
protected void convert(MultipleViewHolder holder, MultipleItemEntity entity) {
super.convert(holder, entity);
switch (holder.getItemViewType()) {
case OrderListItemType.ITEM_ORDER_LIST:
final AppCompatImageView imageView = holder.getView(R.id.image_order_list);
final AppCompatTextView title = holder.getView(R.id.tv_order_list_title);
final AppCompatTextView price = holder.getView(R.id.tv_order_list_price);
final AppCompatTextView time = holder.getView(R.id.tv_order_list_time);
final String titleVal = entity.getFiled(MultipleFields.TITLE);
final String timeVal = entity.getFiled(OrderItemFields.TIME);
final double priceVal = entity.getFiled(OrderItemFields.PRICE);
final String imageUrl = entity.getFiled(MultipleFields.IMAGE_URL);
Glide.with(mContext)//加载图片
.load(imageUrl)
.apply(OPTIONS)
.into(imageView);
title.setText(titleVal);//视图与JSON数据绑定
price.setText("价格" + String.valueOf(priceVal));
time.setText("时间" + timeVal);
break;
default:
break;
}
}
}
位于latte-ec模块main->personal->list->order包下的OrderListDelegate。
主要作用:订单点击事件进入的list的根布局。
public class OrderListDelegate extends LatteDelegate {
private String mType = null;//根据不同type设置不同的orderList
@BindView(R2.id.rv_order_list)
RecyclerView mRecyclerView = null;
@Override
public Object setLayout() {
return R.layout.delegate_order_list;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Bundle args = getArguments();
mType = args.getString(PersonalDelegate.ORDER_TYPE);//获取type,根据type请求api,后端根据get或post不同的参数,返回不同的JSON字段,实现不同的type返回不同的list列表-->同样的ui模板呈现不同的ui内容
}
@Override
public void onBindView(@Nullable Bundle savedInstanceState, View rootView) {
}
@Override
public void onLazyInitView(@Nullable Bundle savedInstanceState) {
super.onLazyInitView(savedInstanceState);
RestClient.builder()
.loader(getContext())
.url("order_list.php")
.params("type", mType)//根据不同的类型,获取不同的JSON数据
.success(new ISuccess() {
@Override
public void (String response) {
final LinearLayoutManager manager = new LinearLayoutManager(getContext());
mRecyclerView.setLayoutManager(manager);
final List data =
new OrderListDataConverter().setJsonData(response).convert();
final OrderListAdapter adapter = new OrderListAdapter(data);
mRecyclerView.setAdapter(adapter);
}
})
.build()
.get();
}
}
位于latte-ec模块main->personal包下的PersonalDelegate。
主要作用:个人中心根类,通过按钮跳转到订单类。
public class PersonalDelegate extends BottomItemDelegate {
......
public static final String ORDER_TYPE = "ORDER_TYPE";
private Bundle mArgs = null;
@Override
public Object setLayout() {
return R.layout.delegate_personal;
}
private void startOrderListByType(){//根据不同的type打开不同的orderList
final OrderListDelegate delegate = new OrderListDelegate();
delegate.setArguments(mArgs);//传递参数,可以根据参数可以获取delegate
getParentDelegate().getSupportDelegate().start(delegate);//getParentDelegate():从父布局跳转
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mArgs = new Bundle();
}
@OnClick(R2.id.tv_all_order)//绑定了全部订单,通过全部订单按钮,跳转
void onClickAllOrder(){
mArgs.putString(ORDER_TYPE,"all");//传入type类型
startOrderListByType();
}
......
}
位于latte-ec模块main->personal->profile包下的UserProfileDelegate。
主要作用:个人信息根类,设置内部数据,每条信息的更改。
布局:内含一个toolbar和recycleView(有一个一个list信息组成)
public class UserProfileDelegate extends LatteDelegate {
@BindView(R2.id.rv_user_profile)
RecyclerView mRecyclerView = null;//个人信息内的recycleView的处理,在里面添加一条一条的list信息
@Override
public Object setLayout() {
return R.layout.delegate_user_profile;
}
@Override
public void onBindView(@Nullable Bundle savedInstanceState, View rootView) {
final ListBean image = new ListBean.Builder()
.setItemType(ListItemType.ITEM_AVATAR)
.setId(1)
.setImageUrl("http://i9.qhimg.com/t017d891ca365ef60b5.jpg")
.build();
final ListBean name = new ListBean.Builder()
.setItemType(ListItemType.ITEM_NORMAL)
.setId(2)
.setText("姓名")
.setDelegate(new NameDelegate())
.setValue("未设置姓名")
.build();
final ListBean gender = new ListBean.Builder()
.setItemType(ListItemType.ITEM_NORMAL)
.setId(3)
.setText("性别")
.setValue("未设置性别")
.build();
final ListBean birth = new ListBean.Builder()
.setItemType(ListItemType.ITEM_NORMAL)
.setId(4)
.setText("生日")
.setValue("未设置生日")
.build();
final List data = new ArrayList<>();
data.add(image);
data.add(name);
data.add(gender);
data.add(birth);
//设置RecyclerView
final LinearLayoutManager manager = new LinearLayoutManager(getContext());
mRecyclerView.setLayoutManager(manager);
final ListAdapter adapter = new ListAdapter(data);
mRecyclerView.setAdapter(adapter);
mRecyclerView.addOnItemTouchListener(new UserProfileClickListener(this));
}
}
1、个人信息每条的数据类型
位于latte-ec模块main->personal->profile包下的ListItemType。
主要作用:RecycleView内的数据的item类型。
public class ListItemType {
public static final int ITEM_NORMAL = 20;//数据信息类型
public static final int ITEM_AVATAR = 21;//头像信息数据类型
}
2、 个人信息内部的数据适配器
位于latte-ec模块main->personal->list包下的ListItemAdapter。
主要作用:RecycleView内的数据适配器,对ListBean中数据进行转化,新增头像修改样式,与其他普通的item修改样式不同。
public class ListAdapter extends BaseMultiItemQuickAdapter {
** private static final RequestOptions OPTIONS = new RequestOptions()//加载图像
.diskCacheStrategy(DiskCacheStrategy.ALL)
.centerCrop()
.dontAnimate();
public ListAdapter(List data) {
super(data);
addItemType(ListItemType.ITEM_NORMAL, R.layout.arrow_item_layout);
** addItemType(ListItemType.ITEM_AVATAR, R.layout.arrow_item_avatar);
}
@Override
protected void convert(BaseViewHolder helper, ListBean item) {
switch (helper.getItemViewType()) {
case ListItemType.ITEM_NORMAL://文字部分的数据与view绑定加载
helper.setText(R.id.tv_arrow_text, item.getText());
helper.setText(R.id.tv_arrow_value, item.getValue());
break;
case ListItemType.ITEM_AVATAR://头像部分的数据与view绑定加载
** Glide.with(mContext)
.load(item.getImageUrl())
.apply(OPTIONS)
.into((ImageView) helper.getView(R.id.img_arrow_avatar));
break;
default:
break;
}
}
}
3、 个人中心根布局
位于latte-ec模块main->personal包下的PersonalDelegate。
主要作用:个人中心根类,通过点击头像跳转到个人信息Fragment。
public class PersonalDelegate extends BottomItemDelegate {
......
@OnClick(R2.id.img_user_avatar)//点击头像,跳转delegate
void onClickAvatar(){
getParentDelegate().getSupportDelegate().start(new UserProfileDelegate());
}
......
}
4、 效果图
姓名:打开新的页面,输入条输入姓名(NameDelegate)
性别:双选
生日:data数据框
1、姓名item的更改
位于latte-ec模块main->personal->profile包下的UserProfileDelegate。
主要作用:个人信息根类,设置内部数据,每条信息的更改。
public class UserProfileDelegate extends LatteDelegate {
......
@Override
public void onBindView(@Nullable Bundle savedInstanceState, View rootView) {
......
final ListBean name = new ListBean.Builder()
.setItemType(ListItemType.ITEM_NORMAL)
.setId(2)
.setText("姓名")
** .setDelegate(new NameDelegate())//要跳转的界面
.setValue("未设置姓名")
.build();
......
//设置RecyclerView
final LinearLayoutManager manager = new LinearLayoutManager(getContext());
mRecyclerView.setLayoutManager(manager);
final ListAdapter adapter = new ListAdapter(data);
mRecyclerView.setAdapter(adapter);
** mRecyclerView.addOnItemTouchListener(new UserProfileClickListener(this));//为RecyclerView添加点击事件
}
}
2、recycleView中item的点击事件监听
位于latte-ec模块main->personal->profile包下的UserProfileClickListener。
主要作用:每个item的监听事件
public class UserProfileClickListener extends SimpleClickListener {
private final LatteDelegate DELEGATE;
private String[] mGenders = new String[]{"男", "女", "保密"};//性别数组
public UserProfileClickListener(LatteDelegate delegate) {
DELEGATE = delegate;
}
@Override
public void onItemClick(BaseQuickAdapter adapter, final View view, int position) {
final ListBean bean = (ListBean) baseQuickAdapter.getData().get(position);
final int id = bean.getId();
switch (id) {//根据id判断点击的是第几个:1:头像,2:姓名...
case 1:
//开始照相机或选择图片
break;
case 2:
final LatteDelegate nameDelegate = bean.getDelegate();
DELEGATE.getSupportDelegate().start(nameDelegate);//点击的是姓名,跳转修改name的界面3、
break;
case 3:
getGenderDialog(new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
final TextView textView = view.findViewById(R.id.tv_arrow_value);//取出横向textView,为了将性别信息写入
}
});
break;
case 4:
break;
default:
break;
}
}
private void getGenderDialog(DialogInterface.OnClickListener listener) {//通过dialog呈现信息
final AlertDialog.Builder builder = new AlertDialog.Builder(DELEGATE.getContext());
builder.setSingleChoiceItems(mGenders, 0, listener);//默认选择第一个:男
builder.show();
}
@Override
public void onItemLongClick(BaseQuickAdapter adapter, View view, int position) {
}
@Override
public void onItemChildClick(BaseQuickAdapter adapter, View view, int position) {
}
@Override
public void onItemChildLongClick(BaseQuickAdapter adapter, View view, int position) {
}
}
3、姓名根页面
位于latte-ec模块main->personal->profile->settings包下的NameDelegate。
主要作用:姓名根布局页面
public class NameDelegate extends LatteDelegate {
@Override
public Object setLayout() {
return null;
}
@Override
public void onBindView(@Nullable Bundle savedInstanceState, View rootView) {
}
}
1、创建日期修改工具类
位于latte-ui模块main->date包下的DateDialogUtil。
主要作用:修改日期工具类,个人信息中修改日期,弹出框的工具类
public class DateDialogUtil {
public interface IDataListener {//当选择日期进行回调的接口
void onDateChange(String date);
}
private IDataListener mDataListener = null;
public void setDataListener(IDataListener listener) {
this.mDataListener = listener;
}
public void showDialog(Context context) {//展示dialog
final LinearLayout ll = new LinearLayout(context);
final DatePicker picker = new DatePicker(context);//日期选择器
final LinearLayout.LayoutParams lp =
new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
picker.setLayoutParams(lp);
picker.init(1990, 1, 1, new DatePicker.OnDateChangedListener() {//初试时间
@Override
public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
final Calendar calendar = Calendar.getInstance();
calendar.set(year, monthOfYear, dayOfMonth);
final SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日", Locale.getDefault());//时间格式化,Locale.getDefault():系统默认时区
final String data = format.format(calendar.getTime());//获取时间值
if (mDataListener != null) {
mDataListener.onDateChange(data);
}
}
});
ll.addView(picker);//加入布局
new AlertDialog.Builder(context)
.setTitle("选择日期")
.setView(ll)
.setPositiveButton("确定", new DialogInterface.OnClickListener() {//确定按钮
@Override
public void onClick(DialogInterface dialog, int which) {
}
})
.setNegativeButton("取消", new DialogInterface.OnClickListener() {//取消按钮
@Override
public void onClick(DialogInterface dialog, int which) {
}
})
.show();
}
}
2、recycleView中生日、性别item的点击事件监听
位于latte-ec模块main->personal->profile包下的UserProfileClickListener。
主要作用:每个item的监听事件,生日选择的点击事件
public class UserProfileClickListener extends SimpleClickListener {
......
@Override
public void onItemClick(BaseQuickAdapter adapter, final View view, int position) {
final ListBean bean = (ListBean) baseQuickAdapter.getData().get(position);
final int id = bean.getId();
switch (id) {
case 1:
......
case 3:
getGenderDialog(new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
final TextView textView = view.findViewById(R.id.tv_arrow_value);
textView.setText(mGenders[which]);//设置性别
dialog.cancel();
}
});
break;
case 4:
final DateDialogUtil dateDialogUtil = new DateDialogUtil();
dateDialogUtil.setDataListener(new DateDialogUtil.IDataListener() {
@Override
public void onDateChange(String date) {
final TextView textView = view.findViewById(R.id.tv_arrow_value);
textView.setText(date);//时间改变,设置新的时间
}
});
dateDialogUtil.showDialog(DELEGATE.getContext());
break;
default:
break;
}
}
private void getGenderDialog(DialogInterface.OnClickListener listener) {
final AlertDialog.Builder builder = new AlertDialog.Builder(DELEGATE.getContext());
builder.setSingleChoiceItems(mGenders, 0, listener);
builder.show();
}
......
}
点击头像 -> 修改个人信息 -> 修改姓名 -> 修改性别 -> 修改生日
相关的类:
Android模式->latte-ec->java->com.example.latte.ui->main包->新建camera包(处理照片)->新建CameraHandler.java类(照片处理类)
Android模式->latte-ec->java->com.example.latte.ui->main包->新建camera包(处理照片)->新建LatteCamera.java类(照相机调用类)
Android模式->latte-ec->java->com.example.latte.ui->main包->新建camera包(处理照片)->新建RequestCodes.java类(请求码存储)
Android模式->latte-ec->java->com.example.latte.ui->main包->新建camera包(处理照片)->新建CameraImageBean.java类(存储一些中间值)
位于latte-ui模块main->camera包下的CameraHandler。
主要作用:照片处理类,拍照页面弹出的效果以及拍照的逻辑处理。
public class CameraHandler implements View.OnClickListener{
private final AlertDialog DIALOG;
private final PermissionCheckerDelegate DELEGATE;//PermissionCheckerDelegate自己定义的,继承LatteDelegate
public CameraHandler(AlertDialog dialog, PermissionCheckerDelegate delegate) {
this.DIALOG = dialog;
this.DELEGATE = delegate;
}
final void beginCameraDialog(){//打开一个从下向上的pancel,选择事件:照相机,从文件系统获取照片,取消
DIALOG.show();
final Window window = DIALOG.getWindow();
if (window!=null){
window.setContentView(R.layout.dialog_camera_panel);
window.setGravity(Gravity.BOTTOM);
window.setWindowAnimations(R.style.anim_panel_up_from_bottom);
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
//设置属性
final WindowManager.LayoutParams params = window.getAttributes();
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.flags = WindowManager.LayoutParams.FLAG_DIM_BEHIND;
params.dimAmount = 0.5f;
window.setAttributes(params);
window.findViewById(R.id.photodialog_btn_cancel).setOnClickListener(this);
window.findViewById(R.id.photodialog_btn_take).setOnClickListener(this);
window.findViewById(R.id.photodialog_btn_native).setOnClickListener(this);
}
}
private String getPhotoName(){//获取照片名字
return FileUtil.getFileNameByTime("IMG","jpg");//传入前缀、后缀
}
private void takePhoto(){//拍照的逻辑
final String currentPhotoName = getPhotoName();
final Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//拍照的意图
final File tempFile = new File(FileUtil.CAMERA_PHOTO_DIR,currentPhotoName);//FileUtil.CAMERA_PHOTO_DIR:系统目录,在刷相册,拍照就显示出来了
//兼容7.0及以上写法,应用外文件访问
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){//7.0以上系统
final ContentValues contentValues = new ContentValues(1);//一次传入一个数据
contentValues.put(MediaStore.Images.Media.DATA,tempFile.getPath());
final Uri uri = DELEGATE.getContext().getContentResolver().
insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,contentValues);//插入数据
//需要将uri转化为实际路径
}
}
@Override
public void onClick(View v) {//不同按钮的点击事件
int id = v.getId();
if (id == R.id.photodialog_btn_cancel){
DIALOG.cancel();
}else if(id == R.id.photodialog_btn_take){
DIALOG.cancel();
}else if(id == R.id.photodialog_btn_native){
DIALOG.cancel();
}
}
}
位于latte-ui模块main->camera包下的CameraImageBean。
主要作用:存储一些中间值。
public final class CameraImageBean {
private Uri mPath = null;
private static final CameraImageBean INSTANCE = new CameraImageBean();
public static CameraImageBean getInstance(){//饿汉的单例模式
return INSTANCE;
}
public Uri getPath() {
return mPath;
}
public void setPath(Uri mPath) {
this.mPath = mPath;
}
}
位于latte-ui模块main->camera包下的RequestCodes。
主要作用:存储照片拍照或从相册选择的请求码。
public class RequestCodes {
public static final int TAKE_PHOTO = 4;
public static final int PICK_PHOTO = 5;
public static final int CROP_PHOTO = UCrop.REQUEST_CROP;
public static final int TAKE_ERROR = UCrop.RESULT_ERROR;
public static final int SCAN = 7;
}
位于latte-ui模块main->camera包下的CameraHandler。
主要作用:照片处理类,拍照页面弹出的效果以及拍照的逻辑处理。
public class CameraHandler implements View.OnClickListener {
......
private void takePhoto() {//拍照
......
//兼容7.0及以上写法
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
......
//需要将uri转化为实际路径
final File realFile =
FileUtils.getFileByPath(FileUtil.getRealFilePath(DELEGATE.getContext(),uri));
final Uri realUri = Uri.fromFile(realFile);
CameraImageBean.getInstance().setPath(realUri);
intent.putExtra(MediaStore.EXTRA_OUTPUT,uri);//加入参数
}else {
final Uri fileUri = Uri.fromFile(tempFile);
CameraImageBean.getInstance().setPath(fileUri);
intent.putExtra(MediaStore.EXTRA_OUTPUT,fileUri);
}
DELEGATE.startActivityForResult(intent,RequestCodes.TAKE_PHOTO);//调用Activity
}
private void pickPhoto(){//选择图片
final Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
DELEGATE.startActivityForResult(Intent.createChooser(intent,"选择获取图片的方式"),RequestCodes.PICK_PHOTO);
//选择器,上拉选择框,上拉选择框的标题"选择获取图片的方式",调用Activity
}
......加到点击事件中
}
位于latte-ui模块main->camera包下的LatteCamera。
主要作用:照相机调用类。
public class LatteCamera {
public static Uri createCropFile(){//剪裁文件的地址
return Uri.parse
(FileUtil.createFile("crop_image",
FileUtil.getFileNameByTime("IMG","jpg")).getPath());
}
public static void start(PermissionCheckerDelegate delegate){
new CameraHandler(delegate).beginCameraDialog();//进入到具体的拍照/选择照片中
}
}
位于latte-core模块main->delegates包下的PermissionCheckerDelegate。
主要作用:拍照的动态权限处理。
@RuntimePermissions
public abstract class PermissionCheckerDelegate extends BaseDelegate {
//不是直接调用方法,为了生成代码使用的
@NeedsPermission(Manifest.permission.CAMERA)
void startCamera(){
LatteCamera.start(this);
}
//这个是真正调用的方法
public void startCameraWithCheck(){
PermissionCheckerDelegatePermissionsDispatcher.startCameraWithPermissionCheck(this);//调用Camera,通过权限
}
@OnPermissionDenied(Manifest.permission.CAMERA)//动态权限
void onCameraDenied(){
Toast.makeText(getContext(),"不允许拍照",Toast.LENGTH_LONG).show();
}
@OnNeverAskAgain(Manifest.permission.CAMERA)
void onCameraNever() {
Toast.makeText(getContext(), "永久拒绝权限", Toast.LENGTH_LONG).show();
}
@OnShowRationale(Manifest.permission.CAMERA)
void onCameraRationale(PermissionRequest request){
showRationaleDialog(request);//权限管理,弹出dialog,让用户选择
}
private void showRationaleDialog(final PermissionRequest request) {
new AlertDialog.Builder(getContext())
.setPositiveButton("同意使用", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
request.proceed();
}
})
.setNegativeButton("拒绝使用", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
request.cancel();
}
})
.setCancelable(false)
.setMessage("权限管理")
.show();
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
PermissionCheckerDelegatePermissionsDispatcher.onRequestPermissionsResult(this,requestCode,grantResults);
}
}
1、剪裁标记值
位于latte-core模块util->callback包下的CallbackType。
主要作用:剪裁标记值。
public enum CallbackType {
ON_CROP//剪裁后参数
}
2、裁剪的回调方法
位于latte-core模块util->callback包下的IGlobalCallback。
主要作用:剪裁标记值。
public interface IGlobalCallback {//T:剪裁后需要传的值,比如uri
void executeCallback(T args);
}
3、裁剪的回调处理类
位于latte-core模块util->callback包下的CallbackManager。
主要作用:裁剪的回调处理类。
public class CallbackManager {
private static final WeakHashMap
4、动态权限处理-裁剪部分的处理
位于latte-core模块main->delegates包下的PermissionCheckerDelegate。
主要作用:拍照的动态权限处理,处理裁剪的逻辑。
@RuntimePermissions
public abstract class PermissionCheckerDelegate extends BaseDelegate {
……
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {//处理得到照片后,将照片剪裁成图片的方法。
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK) {//方法正确进入选项,选择图片处理方式
switch (requestCode) {
case RequestCodes.TAKE_PHOTO:
final Uri resultUri = CameraImageBean.getInstance().getPath();//图片的路径
UCrop.of(resultUri, resultUri)//进行图片剪裁,剪裁后的图片覆盖原图片
.withMaxResultSize(400, 400)
.start(getContext(), this);
break;
case RequestCodes.PICK_PHOTO:
if (data!=null){
final Uri pickPath = data.getData();
//从相册选择后需要有个路径存放剪裁过的图片
final String pickCropPath = LatteCamera.createCropFile().getPath();
UCrop.of(pickPath, Uri.parse(pickCropPath))
.withMaxResultSize(400, 400)
.start(getContext(), this);
}
break;
case RequestCodes.CROP_PHOTO:
final Uri cropUri = UCrop.getOutput(data);
//拿到剪裁后的数据进行处理
@SuppressWarnings("unchecked")
final IGlobalCallback callback = CallbackManager//2、3、4获取回调
.getInstance()
.getCallback(CallbackType.ON_CROP);//剪裁时的类型
if (callback!=null){
callback.executeCallback(cropUri);//可以在任何时候处理回调
}
break;
case RequestCodes.TAKE_ERROR:
Toast.makeText(getContext(),"剪裁出错",Toast.LENGTH_SHORT).show();
break;
default:
break;
}
}
}
}
5、个人中心设置入口
位于latte-ec模块main->personal->profile包下的UserProfileClickListener。
主要作用:每个item的监听事件,照片选择的点击事件
public class UserProfileClickListener extends SimpleClickListener {
……
@Override
public void onItemClick(BaseQuickAdapter adapter, final View view, int position) {
final ListBean bean = (ListBean) baseQuickAdapter.getData().get(position);
final int id = bean.getId();
switch (id) {
case 1:
//开始照相机或选择图片
CallbackManager.getInstance()
.addCallback(CallbackType.ON_CROP, new IGlobalCallback() {
@Override
public void executeCallback(Uri args) {
LatteLogger.d("ON_CROP", args);
final ImageView avatar = view.findViewById(R.id.img_arrow_avatar);//获取放图片的地方
Glide.with(DELEGATE.getContext())//加载图片
.load(args)
.into(avatar);
RestClient.builder()//上传头像
.url(UploadConfig.UPLOAD_IMG)
.loader(DELEGATE.getContext())
.file(args.getPath())//穿的图片地址
.success(new ISuccess() {
@Override
public void onSuccess(String response) {
LatteLogger.d("ON_CROP_UPLOAD", response);
String path = JSON.parseObject(response).getJSONObject("result").getString("path");//获取图像位置信息
//通知服务器更新信息,得到用户信息,在GreenDao数据库中avatar进行更改,本地的也会更新
RestClient.builder()
.url("user_profile.php")
.params("avatar",path)//头像更新
.loader(DELEGATE.getContext())
.success(new ISuccess() {
@Override
public void onSuccess(String response) {
//获取更新后的用户信息,然后更新本地数据库
//没有本地数据库的App,每次打开App都请求API,获取信息
}
})
.build()
.post();
}
})
.build()
.upload();
}
});
DELEGATE.startCameraWithCheck();
break;
case 2:
……
}
逻辑:从个人中心根布局设置入口,为每个item设置点击事件,通过id判别是哪个点击事件,进入该事件的Fragment的根页面进行逻辑处理(内含数据适配器,数据转换等)
AddressDataConverter.java:将JSON数据转换,存储成key-value。
AddressAdapter.java:将转换的JSON数据与试图绑定
AddressItemType.java:存储type类型的key
AddressItemFields.java:存储JSON数据类型的key
AddressDelegate.java:地址的跟布局
位于latte-ec模块main->personal->profile包下的UserProfileClickListener。
主要作用:每个item的监听事件,根据id跳转地址界面
public class PersonalClickListener extends SimpleClickListener {
private final LatteDelegate DELEGATE;
public PersonalClickListener(LatteDelegate delegate) {
this.DELEGATE = delegate;
}
@Override
public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
ListBean bean = (ListBean) baseQuickAdapter.getData().get(position);
int id = bean.getId();
switch (id){
case 1://根据不同id对点击事件进行处理
DELEGATE.getParentDelegate().getSupportDelegate().start(bean.getDelegate());//在外部处理
break;
case 2:
DELEGATE.getParentDelegate().getSupportDelegate().start(bean.getDelegate());
break;
default:
break;
}
}
……
}
位于latte-ec模块main->personal包下的PersonalDelegate。
主要作用:个人中心根类,传入地址的item数据,地址具体页面的delegate。
@Override
public void onBindView(@Nullable Bundle savedInstanceState, View rootView) {
final ListBean address = new ListBean.Builder()
.setItemType(ListItemType.ITEM_NORMAL)
.setId(1)
** .setDelegate(new AddressDelegate())
.setText("收货地址")
.build();
//设置RecycleView
final LinearLayoutManager manager = new LinearLayoutManager(getContext());
mRvSettings.setLayoutManager(manager);
final ListAdapter adapter = new ListAdapter(data);
mRvSettings.setAdapter(adapter);
** mRvSettings.addOnItemTouchListener(new PersonalClickListener(this));//给每条数据新增点击事件
}
点击收货地址进入页面,点击删除会删除地址信息