【說明】佈局會使用自定義控件;java
【點擊事件的處理】android
【效果】微信
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 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
【屬性值的定義】ide
【使用屬性值】佈局
【爲加號增長包邊】動畫
【加號按鈕的設置和佈局】ui
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
【設置boolean值】this
【須要防止屢次佈局】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 }
【建立圖片和對圖片的剪裁】
【效果】能夠增長兩種圖片,可是不能刪除;
【刪除圖片的對話框的佈局】
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 }