滑动框选图片,自定义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
原创粉丝点击