【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     }

 

相關文章
相關標籤/搜索