欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 运维知识 > Android >内容正文

Android

云炬Android开发笔记 15评价晒单功能实现(自定义评分控件和仿微信自动多图选择控件)

发布时间:2025/3/15 Android 41 豆豆
生活随笔 收集整理的这篇文章主要介绍了 云炬Android开发笔记 15评价晒单功能实现(自定义评分控件和仿微信自动多图选择控件) 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

阅读目录


1. 晒单评价

1.1 点击页面跳转的实现
1.2 自定义评价订单的布局实现
1.3 星星布局的实现
2. 仿微信自动多图及删除控件

2.1 属性值及控件的定义
2.2 图片初始化方法onMearsure()方法
2.3 【设置避免重复测量的onMeasure()】
2.4  onLayout()方法的书写
3. 对加号增加图片事件的响应

3.1 增加图片
 3.2 增加对图片的删除功能


 

 

 

  •  

回到顶部

1. 晒单评价

回到顶部

1.1 点击页面跳转的实现

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

 

【点击事件的处理】

 

【效果】

 

回到顶部

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.Toolbar9 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 @Override90 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-评价星星点击选择的效果.gif

 

回到顶部

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

回到顶部

2.1 属性值及控件的定义

【属性值的定义】

【使用属性值】

 

【为加号增加包边】

 

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

 

回到顶部

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 //要删除的图片ID39 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值】

回到顶部

2.4  onLayout()方法的书写

 【需要防止多次布局】

1 @Override2 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 @Override7 public void onClick(View v) {8 //获取要删除的图片ID9 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 }

 

 

总结

以上是生活随笔为你收集整理的云炬Android开发笔记 15评价晒单功能实现(自定义评分控件和仿微信自动多图选择控件)的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。