【0113】【项目实战】-【Android通用框架设计与完整电商APP开发】-【13】评价晒单功能实现(自定义评分控件和仿微信自动多图选择控件)

1. 晒单评价

1.1 点击页面跳转的实现

【说明】布局会使用自定义控件;java

 

【点击事件的处理】android

 

【效果】微信

 

1.2 自定义评价订单的布局实现

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3  xmlns:app="http://schemas.android.com/apk/res-auto"
 4  android:layout_width="match_parent"
 5  android:layout_height="match_parent"
 6  android:orientation="vertical">
 7 
 8     <android.support.v7.widget.Toolbar  9         android:id="@+id/tb_shop_cart"
10  android:layout_width="match_parent"
11  android:layout_height="75dp"
12  android:background="@android:color/holo_orange_dark"
13  android:gravity="center">
14 
15         <android.support.v7.widget.AppCompatTextView 16             android:layout_width="wrap_content"
17  android:layout_height="wrap_content"
18  android:layout_gravity="center"
19  android:text="评价晒单"
20  android:textColor="@android:color/white"
21  android:textSize="20sp" />
22 
23         <android.support.v7.widget.AppCompatTextView 24             android:id="@+id/top_tv_comment_commit"
25  android:layout_width="wrap_content"
26  android:layout_height="wrap_content"
27  android:layout_gravity="right"
28  android:layout_marginRight="20dp"
29  android:text="提交"
30  android:textColor="@android:color/white"
31  android:textSize="20sp" />
32     </android.support.v7.widget.Toolbar>
33 
34     <RelativeLayout 35         android:layout_width="match_parent"
36  android:layout_height="100dp">
37 
38         <android.support.v7.widget.AppCompatImageView 39             android:id="@+id/img_order_comment"
40  android:layout_width="80dp"
41  android:layout_height="80dp"
42  android:layout_centerVertical="true"
43  android:layout_marginLeft="10dp" />
44 
45         <TextView 46             android:id="@+id/tv_comment_title"
47  android:layout_width="wrap_content"
48  android:layout_height="wrap_content"
49  android:layout_marginLeft="20dp"
50  android:layout_marginTop="10dp"
51  android:layout_toRightOf="@id/img_order_comment"
52  android:text="评分"
53  android:textColor="#323232" />
54 
55         <com.flj.latte.ui.widget.StarLayout 56             android:id="@+id/custom_star_layout"
57  android:layout_width="match_parent"
58  android:layout_height="match_parent"
59  android:layout_below="@+id/tv_comment_title"
60  android:layout_toRightOf="@id/img_order_comment" />
61 
62     </RelativeLayout>
63 
64     <android.support.v7.widget.AppCompatEditText 65         android:id="@+id/et_order_comment"
66  android:layout_width="match_parent"
67  android:layout_height="120dp"
68  android:background="@android:color/white"
69  android:gravity="top|left"
70  android:hint="写下评论"
71  android:padding="10dp" />
72 
73     <com.flj.latte.ui.widget.AutoPhotoLayout 74         android:id="@+id/custom_auto_photo_layout"
75  android:layout_width="wrap_content"
76  android:layout_height="wrap_content"
77  app:icon_size="10sp"
78  app:item_margin="3"
79  app:line_count="5"
80  app:max_count="5" />
81 
82 </LinearLayout> 

1.3 星星布局的实现

 

 1 package com.flj.latte.ui.widget;  2 
 3 import android.content.Context;  4 import android.graphics.Color;  5 import android.support.v7.widget.LinearLayoutCompat;  6 import android.util.AttributeSet;  7 import android.view.Gravity;  8 import android.view.View;  9 import android.view.ViewGroup;  10 
 11 import com.flj.latte.ui.R;  12 import com.joanzapata.iconify.widget.IconTextView;  13 
 14 import java.util.ArrayList;  15 
 16 
 17 public class StarLayout extends LinearLayoutCompat implements View.OnClickListener {  18 
 19     private static final CharSequence ICON_UN_SELECT = "{fa-star-o}";  //空心图标
 20     private static final CharSequence ICON_SELECTED = "{fa-star}";  //实心图标
 21     private static final int STAR_TOTAL_COUNT = 5;  //星星的数量
 22     private static final ArrayList<IconTextView> STARS = new ArrayList<>();  23 
 24     public StarLayout(Context context) {  25         this(context, null);  26  }  27 
 28     public StarLayout(Context context, AttributeSet attrs) {  29         this(context, attrs, 0);  30  }  31 
 32     public StarLayout(Context context, AttributeSet attrs, int defStyleAttr) {  33         super(context, attrs, defStyleAttr);  34  initStarIcon();  35  }  36     //初始化星星
 37     private void initStarIcon() {  38         for (int i = 0; i < STAR_TOTAL_COUNT; i++) {  39             final IconTextView star = new IconTextView(getContext());  40  star.setGravity(Gravity.CENTER);  41             final LayoutParams lp =
 42                     new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,  43  ViewGroup.LayoutParams.MATCH_PARENT);  44             lp.weight = 1;  45  star.setLayoutParams(lp);  46  star.setText(ICON_UN_SELECT);  47  star.setTag(R.id.star_count, i);  48             star.setTag(R.id.star_is_select, false);  //默认没有选中
 49             star.setOnClickListener(this);  50             STARS.add(star); //建立的星星放到布局中;
 51             this.addView(star); //加到布局中;
 52  }  53  }  54 
 55     public int getStarCount() {  56         int count = 0;  57         for (int i = 0; i < STAR_TOTAL_COUNT; i++) {  58             final IconTextView star = STARS.get(i);  59             final boolean isSelect = (boolean) star.getTag(R.id.star_is_select);  60             if (isSelect) {  61                 count++;  62  }  63  }  64         return count;  65  }  66 
 67     private void selectStar(int count) {  68         for (int i = 0; i <= count; i++) {  69             if (i <= count) {  70                 final IconTextView star = STARS.get(i);  71  star.setText(ICON_SELECTED);  72  star.setTextColor(Color.RED);  73                 star.setTag(R.id.star_is_select, true);  74  }  75  }  76  }  77 
 78     private void unSelectStar(int count) {  79         for (int i = 0; i < STAR_TOTAL_COUNT; i++) {  80             if (i >= count) {  81                 final IconTextView star = STARS.get(i);  82  star.setText(ICON_UN_SELECT);  83  star.setTextColor(Color.GRAY);  84                 star.setTag(R.id.star_is_select, false);  85  }  86  }  87  }  88 
 89  @Override  90     public void onClick(View v) {  91         final IconTextView star = (IconTextView) v;  92         //获取第几个星星
 93         final int count = (int) star.getTag(R.id.star_count);  94         //获取点击状态
 95         final boolean isSelect = (boolean) star.getTag(R.id.star_is_select);  96         if (!isSelect) {  97  selectStar(count);  98         } else {  99  unSelectStar(count); 100  } 101  } 102 }

 

【效果】1-评价星星点击选择的效果.gifapp

 

2. 仿微信自动多图及删除控件

2.1 属性值及控件的定义

【属性值的定义】ide

【使用属性值】布局

 

【为加号增长包边】动画

 

【加号按钮的设置和布局】ui

 

2.2 图片初始化方法onMearsure()方法

 1 package com.flj.latte.ui.widget;  2 
 3 import android.content.Context;  4 import android.content.res.TypedArray;  5 import android.graphics.Color;  6 import android.graphics.drawable.ColorDrawable;  7 import android.net.Uri;  8 import android.support.v7.app.AlertDialog;  9 import android.support.v7.widget.AppCompatImageView;  10 import android.support.v7.widget.LinearLayoutCompat;  11 import android.util.AttributeSet;  12 import android.view.Gravity;  13 import android.view.View;  14 import android.view.Window;  15 import android.view.WindowManager;  16 import android.view.animation.AlphaAnimation;  17 
 18 import com.bumptech.glide.Glide;  19 import com.bumptech.glide.load.engine.DiskCacheStrategy;  20 import com.bumptech.glide.request.RequestOptions;  21 import com.flj.latte.delegates.LatteDelegate;  22 import com.flj.latte.ui.R;  23 import com.joanzapata.iconify.widget.IconTextView;  24 
 25 import java.util.ArrayList;  26 
 27 public final class AutoPhotoLayout extends LinearLayoutCompat {  28 
 29     private int mCurrentNum = 0;  //首先判断是第几张图片
 30     private final int mMaxNum;   //最大允许多少张图片;
 31     private final int mMaxLineNum;  //一行图片的数量;
 32     private IconTextView mIconAdd = null;  //增长图片的按钮,是一张图片;
 33     private LayoutParams mParams = null;  //公共的一些属性值;
 34 
 35     /**
 36  * 【效果】若是添加了图片,要删除图片,则会弹出dialog,删除以后“加号按钮”会自动向前移动;  37      */
 38     //要删除的图片ID
 39     private int mDeleteId = 0;  40     private AppCompatImageView mTargetImageVew = null; //选中的图片;
 41     private final int mImageMargin; //图片的间距
 42     private LatteDelegate mDelegate = null;  //对图片的操做
 43     private ArrayList<View> mLineViews = null;  //将每行增长的图片存在arraylist中;
 44     private AlertDialog mTargetDialog = null;  //删除图片的确认框;
 45     private static final String ICON_TEXT = "{fa-plus}";  //加号图标;
 46     private final float mIconSize;  //加号图标的大小;  47     //存储全部的View;存储方式是一行一行存储的;若是有两行就存储两行全部的View;
 48     private final ArrayList<ArrayList<View>> ALL_VIEWS = new ArrayList<>();  49     private final ArrayList<Integer> LINE_HEIGHTS = new ArrayList<>(); //存储每个行的高度;  50 
 51 
 52 
 53     //防止屡次的测量和布局过程
 54     private boolean mIsOnceInitOnMeasure = false;  55     private boolean mHasInitOnLayout = false;  56 
 57     private static final RequestOptions OPTIONS = new RequestOptions()  58  .centerCrop()  59  .diskCacheStrategy(DiskCacheStrategy.NONE);  60 
 61     public AutoPhotoLayout(Context context) {  62         this(context, null);  63  }  64 
 65     public AutoPhotoLayout(Context context, AttributeSet attrs) {  66         this(context, attrs, 0);  67  }  68 
 69     public AutoPhotoLayout(Context context, AttributeSet attrs, int defStyleAttr) {  70         super(context, attrs, defStyleAttr);  71         //从定义的attr.xml中将值取出;
 72         final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.camera_flow_layout);  73         mMaxNum = typedArray.getInt(R.styleable.camera_flow_layout_max_count, 1);  74         mMaxLineNum = typedArray.getInt(R.styleable.camera_flow_layout_line_count, 3);  //一行中什么都没有传递,则默认值是3个“加号”
 75         mImageMargin = typedArray.getInt(R.styleable.camera_flow_layout_item_margin, 0); //无图片上传,则默认没有间隙;
 76         mIconSize = typedArray.getDimension(R.styleable.camera_flow_layout_icon_size, 20); //无图片,则默认是20的大小;
 77         typedArray.recycle(); //回收typedArray,防止内存泄露;
 78  }  79 
 80     public final void setDelegate(LatteDelegate delegate) {  81         this.mDelegate = delegate;  82  }  83 
 84     public final void onCropTarget(Uri uri) {  85  createNewImageView();  86  Glide.with(mDelegate)  87  .load(uri)  88  .apply(OPTIONS)  89  .into(mTargetImageVew);  90  }162 
163  @Override 164     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 165         final int sizeWith = MeasureSpec.getSize(widthMeasureSpec); 166         final int modeWith = MeasureSpec.getMode(widthMeasureSpec); 167         final int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); 168         final int modeHeight = MeasureSpec.getMode(heightMeasureSpec); 169         //wrap_content
170         int width = 0; 171         int height = 0; 172         //记录每一行的宽度与高度
173         int lineWith = 0; 174         int lineHeight = 0; 175         //获得内部元素个数
176         int cCount = getChildCount(); 177         for (int i = 0; i < cCount; i++) { 178             final View child = getChildAt(i); 179             //测量子View的宽和高
180  measureChild(child, widthMeasureSpec, heightMeasureSpec); 181             //的搭配LayoutParams
182             final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); 183             //子View占据的宽度
184             final int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; 185             //子View占据的高度
186             final int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; 187             //开始换行
188             if (lineWith + childWidth > sizeWith - getPaddingLeft() - getPaddingRight()) { 189                 //对比获得最大宽度
190                 width = Math.max(width, lineWith); 191                 //重置lineWidth
192                 lineWith = childWidth; 193                 height += lineHeight; 194                 lineHeight = childHeight; 195             } else { 196                 //未换行 197                 //叠加行宽
198                 lineWith += childWidth; 199                 //获得当前最大的高度
200                 lineHeight = Math.max(lineHeight, childHeight); 201  } 202             //最后一个子控件
203             if (i == cCount - 1) { 204                 width = Math.max(lineWith, width); 205                 //判断是否超过最大拍照限制
206                 height += lineHeight; 207  } 208  } 209  setMeasuredDimension( 210                 modeWith == MeasureSpec.EXACTLY ? sizeWith : width + getPaddingLeft() + getPaddingRight(), 211                 modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height + getPaddingTop() + getPaddingBottom() 212  ); 213         //设置一行全部图片的宽高
214         final int imageSideLen = sizeWith / mMaxLineNum; 215         //只初始化一次
216         if (!mIsOnceInitOnMeasure) { 217             mParams = new LayoutParams(imageSideLen, imageSideLen); 218             mIsOnceInitOnMeasure = true; 219  } 220  } 221 

2.3 【设置避免重复测量的onMeasure()】

 

【设置boolean值】this

2.4  onLayout()方法的书写

 【须要防止屡次布局】spa

 1 @Override  2     protected void onLayout(boolean changed, int l, int t, int r, int b) {  3         ALL_VIEWS.clear();  //清楚掉全部的以前的尺寸和参数;
 4  LINE_HEIGHTS.clear();  5         // 当前ViewGroup的宽度 声明须要使用的变量
 6         final int width = getWidth();  7         int lineWidth = 0;  8         int lineHeight = 0;  9         if (!mHasInitOnLayout) { 10             mLineViews = new ArrayList<>(); 11             mHasInitOnLayout = true; 12  } 13         final int cCount = getChildCount(); 14         for (int i = 0; i < cCount; i++) { 15             final View child = getChildAt(i); 16             final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); 17             final int childWith = child.getMeasuredWidth(); 18             final int childHeight = child.getMeasuredHeight(); 19             //若是须要换行
20             if (childWith + lineWidth + lp.leftMargin + lp.rightMargin >
21                     width - getPaddingLeft() - getPaddingRight()) { 22                 //记录lineHeight
23  LINE_HEIGHTS.add(lineHeight); 24                 //记录当前一行的Views
25  ALL_VIEWS.add(mLineViews); 26                 //重置宽和高
27                 lineWidth = 0; 28                 lineHeight = childHeight + lp.topMargin + lp.bottomMargin; 29                 //重置View集合
30  mLineViews.clear(); 31  } 32             lineWidth += childWith + lp.leftMargin + lp.rightMargin; 33             lineHeight = Math.max(lineHeight, lineHeight + lp.topMargin + lp.bottomMargin); 34  mLineViews.add(child); 35  } 36         //处理最后一行
37  LINE_HEIGHTS.add(lineHeight); 38  ALL_VIEWS.add(mLineViews); 39         //设置子View位置
40         int left = getPaddingLeft(); 41         int top = getPaddingTop(); 42         //行数
43         final int lineNum = ALL_VIEWS.size(); 44         for (int i = 0; i < lineNum; i++) { 45             //当前行全部的View
46             mLineViews = ALL_VIEWS.get(i); 47             lineHeight = LINE_HEIGHTS.get(i); 48             final int size = mLineViews.size(); 49             for (int j = 0; j < size; j++) { 50                 final View child = mLineViews.get(j); 51                 //判断child的状态
52                 if (child.getVisibility() == GONE) { 53                     continue; 54  } 55                 final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); 56                 //设置子View的边距
57                 final int lc = left + lp.leftMargin; 58                 final int tc = top + lp.topMargin; 59                 final int rc = lc + child.getMeasuredWidth() - mImageMargin; 60                 final int bc = tc + child.getMeasuredHeight(); 61                 //为子View进行布局
62  child.layout(lc, tc, rc, bc); 63                 left += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; 64  } 65             left = getPaddingLeft(); 66             top += lineHeight; 67  } 68  mIconAdd.setLayoutParams(mParams); 69         mHasInitOnLayout = false; 70     }

3. 对加号增长图片事件的响应

3.1 增长图片

【建立图片和对图片的剪裁】

 

 

【效果】能够增长两种图片,可是不能删除;

 3.2 增长对图片的删除功能

 【删除图片的对话框的布局】

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3  android:layout_width="match_parent"
 4  android:layout_height="wrap_content"
 5  android:layout_gravity="center"
 6  android:layout_marginLeft="10dp"
 7  android:layout_marginRight="10dp"
 8  android:background="@android:color/transparent"
 9  android:orientation="vertical"
10  android:paddingBottom="10dp">
11 
12     <Button 13         android:id="@+id/dialog_image_clicked_btn_delete"
14  android:layout_width="match_parent"
15  android:layout_height="50dp"
16  android:background="@drawable/btn_border_takephoto"
17  android:gravity="center"
18  android:text="删除"
19  android:textColor="#323232" />
20 
21     <View 22         android:layout_width="match_parent"
23  android:layout_height="0.5dp"
24  android:layout_gravity="center"
25  android:background="@android:color/transparent"
26  android:gravity="center" />
27 
28 
29     <Button 30         android:id="@+id/dialog_image_clicked_btn_undetermined"
31  android:layout_width="match_parent"
32  android:layout_height="50dp"
33  android:layout_gravity="center"
34  android:background="@drawable/btn_border_nativephoto"
35  android:text="待定"
36  android:textColor="#323232" />
37 
38     <View 39         android:layout_width="match_parent"
40  android:layout_height="10dp"
41  android:layout_gravity="center"
42  android:background="@android:color/transparent"
43  android:gravity="center" />
44 
45     <Button 46         android:id="@+id/dialog_image_clicked_btn_cancel"
47  android:layout_width="match_parent"
48  android:layout_height="50dp"
49  android:layout_gravity="center"
50  android:background="@drawable/btn_border"
51  android:text="取消"
52  android:textColor="#323232" />
53 
54 </LinearLayout>

 

 

 1     private void createNewImageView() {  2         mTargetImageVew = new AppCompatImageView(getContext());  3  mTargetImageVew.setId(mCurrentNum);  4  mTargetImageVew.setLayoutParams(mParams);  5         mTargetImageVew.setOnClickListener(new OnClickListener() {  6  @Override  7             public void onClick(View v) {  8                 //获取要删除的图片ID
 9                 mDeleteId = v.getId(); 10  mTargetDialog.show(); 11                 final Window window = mTargetDialog.getWindow(); 12                 if (window != null) { 13  window.setContentView(R.layout.dialog_image_click_panel); 14  window.setGravity(Gravity.BOTTOM); 15  window.setWindowAnimations(R.style.anim_panel_up_from_bottom); 16                     window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); 17                     final WindowManager.LayoutParams params = window.getAttributes(); 18                     params.width = WindowManager.LayoutParams.MATCH_PARENT; 19                     params.flags = WindowManager.LayoutParams.FLAG_DIM_BEHIND; 20                     params.dimAmount = 0.5f; 21  window.setAttributes(params); 22  window.findViewById(R.id.dialog_image_clicked_btn_delete) //删除按钮的事件 23                             .setOnClickListener(new OnClickListener() { 24  @Override 25                                 public void onClick(View v) { 26                                     //获得要删除的图片
27                                     final AppCompatImageView deleteImageViwe =
28  (AppCompatImageView) findViewById(mDeleteId); 29                                     //设置图片逐渐消失的动画
30                                     final AlphaAnimation animation = new AlphaAnimation(1, 0); 31                                     animation.setDuration(500); 32                                     animation.setRepeatCount(0); 33                                     animation.setFillAfter(true); 34                                     animation.setStartOffset(0); 35  deleteImageViwe.setAnimation(animation); 36  animation.start(); 37                                     AutoPhotoLayout.this.removeView(deleteImageViwe); 38                                     mCurrentNum -= 1; 39                                     //当数目达到上限时隐藏添加按钮,不足时显示
40                                     if (mCurrentNum < mMaxNum) { 41  mIconAdd.setVisibility(VISIBLE); 42  } 43  mTargetDialog.cancel(); 44  } 45  }); 46  window.findViewById(R.id.dialog_image_clicked_btn_undetermined) 47                             .setOnClickListener(new OnClickListener() { 48  @Override 49                                 public void onClick(View v) { 50  mTargetDialog.cancel(); 51  } 52  }); 53  window.findViewById(R.id.dialog_image_clicked_btn_cancel) //取消按钮的事件 54                             .setOnClickListener(new OnClickListener() { 55  @Override 56                                 public void onClick(View v) { 57  mTargetDialog.cancel(); 58  } 59  }); 60  } 61  } 62  }); 63         //添加子View的时候传入位置
64         this.addView(mTargetImageVew, mCurrentNum); 65         mCurrentNum++; 66         //当添加数目大于mMaxNum时,自动隐藏添加按钮
67         if (mCurrentNum >= mMaxNum) { 68  mIconAdd.setVisibility(View.GONE); 69  } 70     }

 

相关文章
相关标签/搜索