滑动框选图片,自定义RecyclerView

好久没写了,今天主要记录一下最近项目里用到的一个自定义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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值