滑动框选图片,自定义RecyclerView
来源:互联网 发布:返利机器人源码 编辑:程序博客网 时间:2024/06/05 15:40
好久没写了,今天主要记录一下最近项目里用到的一个自定义View。
效果图不会搞,跳过。描述一下大概就是有很多图片,做一个展示,可以左右滑动来浏览图片,类似一个Gallery的效果,用RecyclerView做的。可以截取选中其中的一段,是用一个框,两边是两个手柄,拖动手柄可以调整选中的范围。
直接贴代码吧,测试代码里面有一些hardcode,不要介意。
Activity布局文件
<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context="com.example.testselectframgallery.MainActivity"> <com.example.testselectframgallery.MyGallery android:layout_gravity="center_vertical" android:layout_width="match_parent" android:layout_height="wrap_content"/></FrameLayout>
可以看到就放了一个MyGallery。所以Activity代码就不放了。接下来是MyGallery的布局文件
<?xml version="1.0" encoding="utf-8"?><merge xmlns:android="http://schemas.android.com/apk/res/android" > <android.support.v7.widget.RecyclerView android:id="@+id/my_gallery" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#00aa0000" android:layout_gravity="center_vertical"/> <com.example.testselectframgallery.MyGallerySelector android:id="@+id/test_selector" android:background="#00000000" android:layout_width="match_parent" android:layout_height="100px"/></merge>
MyGallery代码
package com.example.testselectframgallery;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.PixelFormat;import android.graphics.drawable.Drawable;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.util.AttributeSet;import android.view.LayoutInflater;import android.widget.FrameLayout;/** * Created by kay.xu on 11/4/16. */public class MyGallery extends FrameLayout{ private RecyclerView mRecyclerView; private MyGallerySelector mGallerySelector; public MyGallery(Context context, AttributeSet attrs) { super(context, attrs); LayoutInflater.from(context).inflate(R.layout.my_gallery_layout, this, true); mRecyclerView = (RecyclerView) findViewById(R.id.my_gallery); mGallerySelector = (MyGallerySelector) findViewById(R.id.test_selector); Bitmap bitmap = drawableToBitmap(getResources().getDrawable(R.drawable.geo_opt_in_graphic, null)); MyGalleryAdapter adapter = new MyGalleryAdapter(getContext(), 100, 100); for (int i = 0; i < 15; i ++) { adapter.addBitmap(bitmap); } init(adapter, null, null, 5, 0, 14); } public void init(MyGalleryAdapter adapter, MyGalleryAdapter.OnItemClickListener onItemClickListener, OnItemSelectedListener onItemSelectedListener, int minItemCount, int start, int end) { LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext()); linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); mRecyclerView.setLayoutManager(linearLayoutManager); mRecyclerView.setAdapter(adapter); adapter.setOnItemClickListener(onItemClickListener); mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); mGallerySelector.onGalleryScrolled(dx); } }); mGallerySelector.init(adapter.getWidth(), minItemCount, start, end); mGallerySelector.setOnItemSelectedListener(onItemSelectedListener); } public interface OnItemSelectedListener { void onStartChanged(int index); void onEndChanged(int index); } //这个是方便测试,直接把一张资源里面的图片转成bitmap,实际上很可能用不到 private Bitmap drawableToBitmap(Drawable drawable) { Bitmap bitmap = Bitmap.createBitmap( drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); drawable.draw(canvas); return bitmap; }}
MyGallery的Adapter
package com.example.testselectframgallery;import android.content.Context;import android.graphics.Bitmap;import android.support.v7.widget.RecyclerView;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.ImageView;import java.util.ArrayList;import java.util.List;/** * Created by kay.xu on 10/26/16. */public class MyGalleryAdapter extends RecyclerView.Adapter<MyGalleryAdapter.ViewHolder> { private List<Bitmap> mDatas; private LayoutInflater mInflater; private OnItemClickListener mOnItemClickListener; private int mWidth, mHeight; public MyGalleryAdapter(Context context, int width, int height) { mInflater = LayoutInflater.from(context); mDatas = new ArrayList<>(); mWidth = width; mHeight = height; } public interface OnItemClickListener { void onItemClick(View view, int position); } public void setOnItemClickListener(OnItemClickListener mOnItemClickListener) { this.mOnItemClickListener = mOnItemClickListener; } public static class ViewHolder extends RecyclerView.ViewHolder { public ViewHolder(View arg0) { super(arg0); } ImageView mImg; } @Override public int getItemCount() { return mDatas.size(); } public void addBitmap(Bitmap image) { mDatas.add(image); } @Override public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) { View view = mInflater.inflate(R.layout.my_gallery_item_layout, viewGroup, false); ViewHolder viewHolder = new ViewHolder(view); viewHolder.mImg = (ImageView) view .findViewById(R.id.my_gallery_item_image); ViewGroup.LayoutParams params = viewHolder.mImg.getLayoutParams(); params.width = mWidth; params.height = mHeight; viewHolder.mImg.setLayoutParams(params); return viewHolder; } @Override public void onBindViewHolder(final ViewHolder viewHolder, final int i) { viewHolder.mImg.setImageBitmap(mDatas.get(i)); if (mOnItemClickListener != null) { viewHolder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mOnItemClickListener.onItemClick(viewHolder.itemView, viewHolder.getPosition()); } }); } } public int getWidth() { return mWidth; } public int getHeight() { return mHeight; } public void clear() { if (mDatas != null) { for (Bitmap bitmap : mDatas) { bitmap.recycle(); bitmap = null; } } mDatas.clear(); }}
Adapter Item的布局文件
<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2016 Tcl Corporation Limited --><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" > <ImageView android:id="@+id/my_gallery_item_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:scaleType="centerCrop" /></RelativeLayout>
选择图片的框(Selector)
package com.example.testselectframgallery;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.util.AttributeSet;import android.util.Log;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.View;import android.widget.FrameLayout;/** * Created by kay.xu on 10/19/16. */public class MyGallerySelector extends FrameLayout implements View.OnTouchListener{ private final Paint mPaintFill; private final Paint mPaintStroke; private MyHandle mHandleLeft; private MyHandle mHandleRight; private int mLastXLeft; private int mLastYLeft; private int mLastXRight; private int mLastYRight; private int mItemWidth; private int mMinItemCount; private static final int RADIUS = 20; private static final int STROKE_WIDTH = 2; private MyGallery.OnItemSelectedListener mOnItemSelectedListener; private int mStart; private int mEnd; public MyGallerySelector(Context context, AttributeSet attrs) { super(context, attrs); LayoutInflater.from(context).inflate(R.layout.my_gallery_selector_layout, this, true); mHandleLeft = (MyHandle) findViewById(R.id.handle_left); mHandleRight = (MyHandle) findViewById(R.id.handle_right); mHandleLeft.setOnTouchListener(this); mHandleRight.setOnTouchListener(this); mPaintFill = new Paint(); mPaintFill.setColor(0x700000ff); mPaintStroke = new Paint(); mPaintStroke.setColor(Color.BLACK); mPaintStroke.setStyle(Paint.Style.STROKE); mPaintStroke.setStrokeWidth(STROKE_WIDTH); } public void init(int itemWidth, int minItemCount, int start, int end) { mItemWidth = itemWidth; mMinItemCount = minItemCount; mStart = start; mEnd = end; scrollTo(start * itemWidth, 0); } public void onGalleryScrolled(int dx) { scrollBy(dx, 0); } private void notifyOnItemSelected(View view) { int location = (int) (view.getX() + view.getWidth()/2); boolean isLeft = view == mHandleLeft; int index = 0; //if move over middle of the image,index +1 int offset = location % mItemWidth; if (offset > mItemWidth/2) { index += 1; } if (isLeft) { index += location / mItemWidth; if (mStart != index) { mStart = index; Log.d("xxx", "notifyOnItemSelected start :" + mStart); if (mOnItemSelectedListener != null) { mOnItemSelectedListener.onStartChanged(mStart); } } } else { index += location / mItemWidth - 1; if (mEnd != index) { mEnd = index; Log.d("xxx", "notifyOnItemSelected end :" + mEnd); if (mOnItemSelectedListener != null) { mOnItemSelectedListener.onEndChanged(mEnd); } } } } public void setOnItemSelectedListener(MyGallery.OnItemSelectedListener listener) { this.mOnItemSelectedListener = listener; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(MeasureSpec.makeMeasureSpec( (mEnd +1) * mItemWidth, MeasureSpec.EXACTLY), heightMeasureSpec); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); mHandleLeft.layout(mStart * mItemWidth - mHandleLeft.getMeasuredWidth()/2, 0, mStart * mItemWidth + mHandleLeft.getMeasuredWidth()/2, mHandleLeft.getMeasuredHeight()); mHandleRight.layout(getWidth() - mHandleLeft.getMeasuredWidth()/2, 0, getWidth() + mHandleLeft.getMeasuredWidth()/2, mHandleRight.getMeasuredHeight()); } private void onMoveEnd(View movedView) { float offset = (movedView.getX() + movedView.getWidth()/2) % mItemWidth; boolean overdMiddle = offset > mItemWidth/2; float difference = mItemWidth - offset; if (overdMiddle) { movedView.layout((int) (movedView.getLeft() + difference), movedView.getTop(), (int)(movedView.getRight() + difference), movedView.getBottom()); } else { movedView.layout((int)(movedView.getLeft() - offset), movedView.getTop(), (int)(movedView.getRight() - offset), movedView.getBottom()); } invalidate(); notifyOnItemSelected(movedView); } @Override protected void onDraw(Canvas canvas) { float left = mHandleLeft.getX() + mHandleLeft.getWidth()/2; float right = mHandleRight.getX() + mHandleRight.getWidth()/2; if (right > left) { canvas.drawRoundRect(left, 0, right, getHeight(), RADIUS ,RADIUS, mPaintFill); canvas.drawRoundRect(left, STROKE_WIDTH, right, getHeight() - STROKE_WIDTH, RADIUS ,RADIUS, mPaintStroke); }else { canvas.drawRoundRect(right, 0, left, getHeight(), RADIUS, RADIUS, mPaintFill); canvas.drawRoundRect(right, STROKE_WIDTH, left, getHeight() - RADIUS, STROKE_WIDTH, RADIUS, mPaintStroke); } super.onDraw(canvas); }// private boolean isTouchInView(View view, MotionEvent event) {// int touchX = (int) event.getRawX();// int touchY = (int) event.getRawY();// int[] viewLocation = new int[2];// view.getLocationOnScreen(viewLocation);// int viewLeft = viewLocation[0];// int viewRight = viewLocation[0] + view.getWidth();// int viewTop = viewLocation[1];// int viewBottom = viewLocation[1] + view.getHeight();// return touchX > viewLeft && touchX < viewRight && touchY > viewTop && touchY < viewBottom;// } @Override public boolean onTouch(View v, MotionEvent event) { int action = event.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: if (v == mHandleLeft) { mLastXLeft = (int) event.getRawX(); mLastYLeft = (int) event.getRawY(); } else { mLastXRight = (int) event.getRawX(); mLastYRight = (int) event.getRawY(); } break; case MotionEvent.ACTION_MOVE: int dx = (int) event.getRawX() - (v == mHandleLeft ? mLastXLeft : mLastXRight); int dy = (int) event.getRawY() - (v == mHandleLeft ? mLastYLeft : mLastYRight); //never move over min count. if ((mHandleRight.getX() - mHandleLeft.getX() + (v == mHandleLeft ? -dx : dx)) < mMinItemCount * mItemWidth) { return true; } v.layout(v.getLeft() + dx, v.getTop(), v.getRight() + dx, v.getBottom()); notifyOnItemSelected(v); if (v == mHandleLeft) { mLastXLeft = (int) event.getRawX(); mLastYLeft = (int) event.getRawY(); } else { mLastXRight = (int) event.getRawX(); mLastYRight = (int) event.getRawY(); } invalidate(); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: onMoveEnd(v); break; } return true; }}
Selector布局文件
<?xml version="1.0" encoding="utf-8"?><merge xmlns:android="http://schemas.android.com/apk/res/android" > <com.example.testselectframgallery.MyHandle android:id="@+id/handle_left" android:layout_width="26dp" android:layout_height="match_parent" /> <com.example.testselectframgallery.MyHandle android:id="@+id/handle_right" android:layout_width="26dp" android:layout_height="match_parent" /></merge>
最后就是手柄的代码
package com.example.testselectframgallery;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.util.AttributeSet;import android.view.View;public class MyHandle extends View { private Paint mPaint; public MyHandle(Context context, AttributeSet attrs) { super(context, attrs); mPaint = new Paint(); mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(Color.YELLOW); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawCircle(getWidth()/2, getHeight()/2, getResources().getDimensionPixelSize(R.dimen.trimming_selector_handles_circle_radius),mPaint); }}
很简单,但我感觉还蛮实用的。另外这个由于用到了RecyclerView,需要添加一下jar包的依赖。
0 0
- 滑动框选图片,自定义RecyclerView
- 自定义RecyclerView实现垂直滑动的ViewPager
- 利用RecyclerView实现仿陌陌滑动浏览图片
- RecyclerView滑动停止加载图片,空闲时间加载图片
- 自定义RecyclerView 支持 横向纵向,滑动删除Item
- 利用自定义的 RecyclerView 实现相册的滑动功能
- 自定义View导致的RecyclerView滑动卡顿
- 自定义 LayoutManager 实现弧形以及滑动放大效果 RecyclerView
- 自定义 LayoutManager 实现弧形以及滑动放大效果 RecyclerView
- RecyclerView使用 及 滑动时加载图片优化方案
- RecyclerView使用 及 滑动时加载图片优化方案
- RecyclerView使用 及 滑动时加载图片优化方案
- RecyclerView使用 及 滑动时加载图片优化方案
- RecyclerView如何实现滑动过程中暂停图片加载
- RecyclerView+PopupWindow 自定义弹框
- RecyclerView嵌套RecyclerView滑动冲突
- 自定义RecyclerView
- 利用RecyclerView和自定义Image Loader实现本地图片加载
- unity shader中有哪些属性如何使用
- java.lang.NoSuchMethodException: org.apache.catalina.deploy.WebXml addFilter
- HTTPS详解
- mysql创建用户报错ERROR 1364 (HY000): Field 'ssl_cipher' doesn't have a default value
- python-"is" v.s. "=="
- 滑动框选图片,自定义RecyclerView
- ASimpleCache 轻量级缓存
- 创建vert和frag函数
- NGUI 粒子系统裁剪
- cxf框架Demo1
- log4j学习(二)不同类的日志输出到不同的文件
- Java List(ArrayList初始化)删除元素
- android webview 常用设置 - 记录
- Mac常用快捷键