900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > 自定义九宫格图片

自定义九宫格图片

时间:2022-07-25 18:09:08

相关推荐

自定义九宫格图片

注:此Demo只是为了学习自定义相关知识,不建议在项目中引用使用.

已实现功能:

1.可设置每行显示的列数、删除图标、加号图片、设置padding,删除图标与图片的间距,

行和列的间距以及删除图标的大小;

2.match_parent模式下自动计算宽高,wrap_content模式下可设置图片的最小宽高,超过了

屏幕的宽度,则按match_parent计算

3.超过满屏可滑动查看,可设置是否拖拽和是否可以滑动,以及设置显示图片的数量

待实现和优化修改:

1.拖拽时屏幕自动滚动;

2.开启可滑动时,超出满屏时,拖拽view错乱问题;

3.拖拽以及拖拽动画优化;

4.支持margin

在不超过满屏的情况下,滑动和拖拽可同时开启,超过了满屏同时开启的话拖拽会出现问题(待修改问题)。

先看一下效果:

xml布局:

xmlns:app="/apk/res-auto"<com.example.administrator.myapplication.view.PhotosDisplayViewandroid:id="@+id/photosDisplayView"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@color/colorAccent"android:padding="10dp"app:defaultAddImage="@mipmap/add_image"app:defaultDeleteImage="@mipmap/delete_image"app:dividerHeWidth="10dp"app:dividerVeWidth="10dp"app:isCanScroller="true"app:isOpenAnimation="true"app:linePhotoNum="4"app:maxPhotoNum="8">

Activity代码:

public class Main3Activity extends AppCompatActivity implements PhotosDisplayView.OnItemClickListener {@BindView(id = R.id.photosDisplayView)private PhotosDisplayView photosDisplayView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main3);BindUtils.initBindView(this);photosDisplayView.setOnItemClickListener(this);photosDisplayView.post(new Runnable() {@Overridepublic void run() {Rect outRect2 = new Rect();getWindow().findViewById(Window.ID_ANDROID_CONTENT).getDrawingRect(outRect2);int height = outRect2.height();photosDisplayView.getPMHeight(height);}});}private int index;@Overridepublic void addImageClick() {index++;photosDisplayView.addShowImage(System.currentTimeMillis() + "", index);}@Overridepublic void lookImageClick(String imageUrl) {}}

PhotosDisplayView 代码:

import android.animation.LayoutTransition;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Rect;import android.text.TextUtils;import android.util.AttributeSet;import android.util.DisplayMetrics;import android.view.DragEvent;import android.view.Gravity;import android.view.MotionEvent;import android.view.VelocityTracker;import android.view.View;import android.view.ViewConfiguration;import android.view.ViewGroup;import android.view.ViewParent;import android.view.WindowManager;import android.widget.FrameLayout;import android.widget.ImageView;import android.widget.Scroller;import com.example.administrator.myapplication.R;import java.util.ArrayList;import java.util.List;public class PhotosDisplayView extends ViewGroup {//默认一列4个private int defaultLinePhotoNum;//最大可添加图片数量private int defaultMaxPhotoNum;//删除图片与图片之间的间距大小private int defaultSmallImgSpace;private int defaultSmallImgSize;//是否打开删除动画private boolean isOpenAnimation = true;//是否可拖拽private boolean isCanDrag = true;private boolean isCanScroller = true;//是否可以滑动private View mDragView;//拖拽的viewprivate List<String> imageList = new ArrayList<>();//如果父控件不是match_parent,则使用默认宽高(正方形),private int defaultImageWidth;//默认间距private int defaultHeDividerWidth;//横向private int defaultVeDividerWidth;//纵向private int deleteImageId;//默认删除的图片private int addImageId;//默认添加的图片private int mScreenWidth; //屏幕宽度private VelocityTracker mVelocityTracker;private int mMinimumVelocity;//最小速率private int mMaximumVelocity;//最大速率private int mScaledTouchSlop; //最小距离private boolean mIsBeingDragged = false;//是否在拖动状态private int display;//view绘制区域的高度private int paddingLeft;private int paddingRight; //paddingprivate int paddingTop;private int paddingBottom;private int mLastMotionY;private Scroller mScroller;private Context mContext;private OnItemClickListener onItemClickListener;public PhotosDisplayView(Context context) {super(context, null);}public PhotosDisplayView(Context context, AttributeSet attrs) {super(context, attrs, 0);mContext = context;mScreenWidth = getScreenSize(mContext).widthPixels;defaultImageWidth = dip2px(context, 120);defaultSmallImgSize = dip2px(context, 15);defaultSmallImgSpace = dip2px(context, 8);mScroller = new Scroller(context);ViewConfiguration viewConfiguration = ViewConfiguration.get(context);mMinimumVelocity = viewConfiguration.getScaledMinimumFlingVelocity();mMaximumVelocity = viewConfiguration.getScaledMaximumFlingVelocity();mScaledTouchSlop = viewConfiguration.getScaledTouchSlop();TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.PhotosDisplayView);defaultLinePhotoNum = typedArray.getInt(R.styleable.PhotosDisplayView_linePhotoNum, defaultLinePhotoNum);defaultSmallImgSpace = (int) typedArray.getDimension(R.styleable.PhotosDisplayView_defaultSmallImgSpace, defaultSmallImgSpace);defaultMaxPhotoNum = typedArray.getInt(R.styleable.PhotosDisplayView_maxPhotoNum, defaultMaxPhotoNum);isCanDrag = typedArray.getBoolean(R.styleable.PhotosDisplayView_isCanDrag, isCanDrag);isOpenAnimation = typedArray.getBoolean(R.styleable.PhotosDisplayView_isOpenAnimation, isOpenAnimation);isCanScroller = typedArray.getBoolean(R.styleable.PhotosDisplayView_isCanScroller, isCanScroller);defaultImageWidth = (int) typedArray.getDimension(R.styleable.PhotosDisplayView_minImageWidth, defaultImageWidth);defaultSmallImgSize = (int) typedArray.getDimension(R.styleable.PhotosDisplayView_defaultSmallImgSize, defaultSmallImgSize);defaultHeDividerWidth = (int) typedArray.getDimension(R.styleable.PhotosDisplayView_dividerHeWidth, defaultHeDividerWidth);defaultVeDividerWidth = (int) typedArray.getDimension(R.styleable.PhotosDisplayView_dividerVeWidth, defaultVeDividerWidth);addImageId = typedArray.getResourceId(R.styleable.PhotosDisplayView_defaultAddImage, R.mipmap.add_image);deleteImageId = typedArray.getResourceId(R.styleable.PhotosDisplayView_defaultDeleteImage, R.mipmap.delete_image);typedArray.recycle();if (isOpenAnimation) {//列表动画LayoutTransition transition = new LayoutTransition();transition.setDuration(300);setLayoutTransition(transition);setOnDragListener(mOnDragListener);}showAddImage();}public PhotosDisplayView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}private int[] s = new int[]{R.mipmap.one, R.mipmap.two, R.mipmap.three};/*** 默认添加加号图片** @param imageUrl* @param index*/private void addImage(String imageUrl, int index) {final FrameLayout frameLayout = new FrameLayout(mContext);ImageView imageView = new ImageView(mContext);imageView.setImageResource(s[index % 3]);imageView.setAdjustViewBounds(true);FrameLayout.LayoutParams layoutParams1 = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);layoutParams1.setMargins(defaultSmallImgSpace, defaultSmallImgSpace, defaultSmallImgSpace, defaultSmallImgSpace);imageView.setLayoutParams(layoutParams1);imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);frameLayout.addView(imageView);ImageView deleteView = new ImageView(mContext);deleteView.setImageResource(deleteImageId);FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(defaultSmallImgSize, defaultSmallImgSize);layoutParams.gravity = Gravity.RIGHT | Gravity.TOP;deleteView.setLayoutParams(layoutParams);deleteView.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {removeView(frameLayout);if (!isHaveDeleteImage()) {showAddImage();}}});frameLayout.addView(deleteView);frameLayout.setTag(imageUrl);addView(frameLayout, 0);}/*** 添加图片*/private void showAddImage() {FrameLayout frameLayout = new FrameLayout(mContext);ImageView imageView = new ImageView(mContext);imageView.setImageResource(addImageId);imageView.setAdjustViewBounds(true);FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);imageView.setLayoutParams(layoutParams);imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);frameLayout.addView(imageView);frameLayout.setTag("");addView(frameLayout);}/*** 是否包含加号图片** @return*/private boolean isHaveDeleteImage() {boolean have = false;for (int i = 0; i < getChildCount(); i++) {View childAt = getChildAt(i);if (childAt.getTag().equals("")) {have = true;break;}}return have;}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);int widthSize = MeasureSpec.getSize(widthMeasureSpec);int heightSize = MeasureSpec.getSize(heightMeasureSpec);int widthMode = MeasureSpec.getMode(widthMeasureSpec);int heightMode = MeasureSpec.getMode(heightMeasureSpec);paddingLeft = getPaddingLeft();paddingTop = getPaddingTop();paddingRight = getPaddingRight();paddingBottom = getPaddingBottom();int totalWidth;//宽高初始值为加号图片的占用空间int totalHeight = defaultImageWidth;int childCount = getChildCount();//是否是match_parentboolean isHeightExactly = false;if (widthMode == MeasureSpec.EXACTLY) {totalWidth = widthSize;getSelfWidth(totalWidth);} else {//图片高度 * 行数 + 上下padding + 多行图片之间间隔的总间距totalWidth = defaultImageWidth * defaultLinePhotoNum + (defaultLinePhotoNum - 1) * defaultVeDividerWidth + paddingLeft + paddingRight;if (totalWidth > mScreenWidth) {//占用宽度超过了屏幕宽度,就设置为屏幕宽度,则不使用自定义的defaultImageWidth,按match_parent来算totalWidth = mScreenWidth;getSelfWidth(totalWidth);}}if (heightMode == MeasureSpec.EXACTLY) {totalHeight = heightSize;isHeightExactly = true;}for (int i = 0; i < childCount; i++) {View childAt = getChildAt(i);childAt.setLayoutParams(new ViewGroup.MarginLayoutParams(defaultImageWidth, defaultImageWidth));measureChild(childAt, widthMeasureSpec, heightMeasureSpec);//排除match_parent, 累加高度if (!isHeightExactly && i % defaultLinePhotoNum == 0 && i != 0) {totalHeight = totalHeight + defaultHeDividerWidth + defaultImageWidth;}}totalHeight += paddingTop + paddingBottom;setMeasuredDimension(totalWidth, totalHeight);}public void getSelfWidth(int totalWidth) {//(总宽-左右padding-多行图片之间间隔的总间距) / 列数defaultImageWidth = (totalWidth - paddingLeft - paddingRight - (defaultLinePhotoNum - 1) * defaultVeDividerWidth) / defaultLinePhotoNum;}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {int childCount = getChildCount();int left = paddingLeft, top = paddingTop, right;for (int i = 0; i < childCount; i++) {final View childAt = getChildAt(i);if (i % defaultLinePhotoNum == 0) {if (i != 0)top = top + childAt.getMeasuredHeight() + defaultHeDividerWidth;left = paddingLeft;} else {left = left + childAt.getMeasuredWidth() + defaultVeDividerWidth;}right = left + childAt.getMeasuredWidth();childAt.layout(left, top, right, top + childAt.getMeasuredHeight());childAt.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {if (null == onItemClickListener) {return;}if (v.getTag().equals("")) {onItemClickListener.addImageClick();} else {onItemClickListener.lookImageClick(v.getTag().toString());}}});childAt.setOnLongClickListener(new OnLongClickListener() {@Overridepublic boolean onLongClick(View v) {if (!isCanDrag || v.getTag().equals("")) {return true;}v.startDrag(null, new DragShadowBuilder(v), null, 0);mDragView = v;return true;}});}}/*** 拖拽监听*/private OnDragListener mOnDragListener = new OnDragListener() {private Rect[] mRect;//记录每个子view的位置private void initRect() {int childCount = getChildCount();mRect = new Rect[childCount];for (int i = 0; i < childCount; i++) {View childAt = getChildAt(i);mRect[i] = new Rect(childAt.getLeft(), childAt.getTop(), childAt.getRight(), childAt.getBottom());}}//已经拖动到了其他view的区域private int getChildIndex(int x, int y) {for (int i = 0; i < mRect.length; i++) {if (mRect[i].contains(x, y)) {return i;}}return -1;}@Overridepublic boolean onDrag(View v, DragEvent event) {if (!isCanDrag) {return true;}switch (event.getAction()) {case DragEvent.ACTION_DRAG_STARTED:initRect();break;case DragEvent.ACTION_DRAG_LOCATION:int childIndex = getChildIndex((int) event.getX(), (int) event.getY());if (childIndex >= 0 && getChildAt(childIndex) != mDragView && !getChildAt(childIndex).getTag().equals("")) {removeView(mDragView);addView(mDragView, childIndex);}break;case DragEvent.ACTION_DRAG_ENDED:/*ScaleAnimation animation1 = new ScaleAnimation(1.5f, 1.0f, 1.5f, 1.0f,Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);animation1.setDuration(300);animation1.setFillAfter(true);mDragingView.startAnimation(animation1);*/break;}return true;}};@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {if (isCanScroller) {final int action = ev.getAction();if ((action == MotionEvent.ACTION_MOVE) && mIsBeingDragged) {return true;}if (super.onInterceptTouchEvent(ev)) {return true;}switch (action) {case MotionEvent.ACTION_DOWN: {mLastMotionY = (int) ev.getY();initOrResetVelocityTracker();mVelocityTracker.addMovement(ev);mIsBeingDragged = !mScroller.isFinished();break;}case MotionEvent.ACTION_MOVE: {final int y = (int) ev.getY();final int yDiff = Math.abs(y - mLastMotionY);//根据最小距离,判断是滑动,还是点击if (yDiff > mScaledTouchSlop) {mIsBeingDragged = true;mLastMotionY = y;initVelocityTrackerIfNotExists();mVelocityTracker.addMovement(ev);}final ViewParent parent = getParent();if (parent != null) {parent.requestDisallowInterceptTouchEvent(true);}break;}case MotionEvent.ACTION_CANCEL:case MotionEvent.ACTION_UP:mIsBeingDragged = false;recycleVelocityTracker();break;}return mIsBeingDragged;} elsereturn super.onInterceptTouchEvent(ev);}@Overridepublic boolean onTouchEvent(MotionEvent event) {if (isCanScroller) {initVelocityTrackerIfNotExists();switch (event.getAction()) {case MotionEvent.ACTION_DOWN: {if ((mIsBeingDragged = !mScroller.isFinished())) {final ViewParent parent = getParent();if (parent != null) {parent.requestDisallowInterceptTouchEvent(true);}}if (!mScroller.isFinished()) {mScroller.abortAnimation();}// mLastMotionY = (int) event.getY();break;}case MotionEvent.ACTION_MOVE: {final int y = (int) event.getY();int deltaY = mLastMotionY - y;/* if (!mIsBeingDragged && Math.abs(deltaY) > mScaledTouchSlop) {final ViewParent parent = getParent();if (parent != null) {parent.requestDisallowInterceptTouchEvent(true);}mIsBeingDragged = true;if (deltaY > 0) {deltaY -= mScaledTouchSlop;} else {deltaY += mScaledTouchSlop;}}*/if (mIsBeingDragged) {scrollBy(0, deltaY);}mLastMotionY = y;break;}case MotionEvent.ACTION_UP: {if (mIsBeingDragged) {final VelocityTracker velocityTracker = mVelocityTracker;puteCurrentVelocity(1000, mMaximumVelocity);int initialVelocity = (int) velocityTracker.getYVelocity();View lastChild = getChildAt(getChildCount() - 1);//获取最大可滑动距离(最后一行View的Y值和高度,也就是lastChild底部到整个ViewGroup的距离减去View的绘制区域(屏幕除去状态栏和标题栏的剩下的内容的高度))int lastChildH = (int) (lastChild.getY() + lastChild.getHeight() - display + paddingBottom);//大于最小滑动速率,则进行惯性滑动if ((Math.abs(initialVelocity) > mMinimumVelocity)) {mScroller.fling(0, getScrollY(), 0, -initialVelocity, 0, 0, 0, lastChildH);}//超过顶部和底部则回弹if (getScrollY() < 0)scrollTo(0, 0);if (getScrollY() >= lastChildH)if (lastChildH < 0)scrollTo(0, 0);elsescrollTo(0, lastChildH);mIsBeingDragged = false;recycleVelocityTracker();}break;}}if (mVelocityTracker != null) {mVelocityTracker.addMovement(event);}return true;} else return super.onTouchEvent(event);}private void initOrResetVelocityTracker() {if (mVelocityTracker == null) {mVelocityTracker = VelocityTracker.obtain();} else {mVelocityTracker.clear();}}private void initVelocityTrackerIfNotExists() {if (mVelocityTracker == null) {mVelocityTracker = VelocityTracker.obtain();}}private void recycleVelocityTracker() {if (mVelocityTracker != null) {mVelocityTracker.recycle();mVelocityTracker = null;}}@Overridepublic void computeScroll() {if (puteScrollOffset()) {scrollTo(0, mScroller.getCurrY());postInvalidate();}puteScroll();}@Overrideprotected LayoutParams generateDefaultLayoutParams() {return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);}@Overridepublic LayoutParams generateLayoutParams(AttributeSet attrs) {return new MarginLayoutParams(this.getContext(), attrs);}@Overrideprotected LayoutParams generateLayoutParams(LayoutParams p) {return new MarginLayoutParams(p);}//获取图片集合public List<String> getImageList() {imageList.clear();for (int i = 0; i < getChildCount(); i++) {String string = getChildAt(i).getTag().toString();if (!TextUtils.isEmpty(string)) {imageList.add(getChildAt(i).getTag().toString());}}return imageList;}public void addShowImage(String imageUrl, int index) {addImage(imageUrl, index);if (getChildCount() > defaultMaxPhotoNum) {removeViewAt(getChildCount() - 1);}}public static DisplayMetrics getScreenSize(Context context) {DisplayMetrics metrics = new DisplayMetrics();WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);wm.getDefaultDisplay().getMetrics(metrics);return metrics;}public interface OnItemClickListener {void addImageClick();void lookImageClick(String imageUrl);}public void setOnItemClickListener(OnItemClickListener onItemClickListener) {this.onItemClickListener = onItemClickListener;}public void getPMHeight(int display) {this.display = display;}public static int dip2px(Context context, float px) {final float scale = getScreenDensity(context);return (int) (px * scale + 0.5);}public static float getScreenDensity(Context context) {return context.getResources().getDisplayMetrics().density;}}

demo下载地址

/download/qq_31427095/10964914

参考链接

/p/4170cb0e8696

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。