自定义可以来回拖拽的控件,通过拖拽改变图片顺序

本文介绍如何在Android中创建一个可拖拽的自定义控件,通过拖动来改变图片显示的顺序。通过这个控件,用户能够直观地调整图片布局,提升用户体验。
首先穿件一个ReportBaseCell
package com.ankoninc.esdiagnose.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.ankoninc.esdiagnose.R;

public class ReportBaseCell extends LinearLayout {

    private TextView mTitleView;
    private WrappedButton mButton;

    private String mTitle;

    public ReportBaseCell(Context context) {
        this(context, null);
    }

    public ReportBaseCell(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ReportBaseCell(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ReportCellItem);
        if (a != null) {
            mTitle = a.getString(R.styleable.ReportCellItem_reportTitleText);
            a.recycle();
        }

        setupViews(context);
    }

    private void setupViews(Context context) {

        setOrientation(VERTICAL);

        View titleContainer = inflate(context, R.layout.report_cell_title, this);
        mTitleView = (TextView) titleContainer.findViewById(R.id.title);
        mTitleView.setText(mTitle);

        mButton = (WrappedButton) titleContainer.findViewById(R.id.button);
    }

    public void setTitle(int resId) {
        mTitleView.setText(resId);
    }

    public void setTitle(String text) {
        mTitleView.setText(text);
    }

    public void setButtonText(int resId) {
        mButton.setText(resId);
    }

    public void setButtonText(String text) {
        mButton.setText(text);
    }

    public void setButtonClickListener(OnClickListener listener) {
        mButton.setOnClickListener(listener);
    }

    public void setButtonVisibility(boolean visible) {
        mButton.setVisibility(visible ? VISIBLE : GONE);
    }
}

第二步:
package com.ankoninc.esdiagnose.view;

import android.content.Context;
import android.graphics.Point;
import android.graphics.PointF;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;

import com.ankoninc.data.MedicalExamination;
import com.ankoninc.esdiagnose.R;
import com.ankoninc.esdiagnose.report.DragManager;
import com.ankoninc.esdiagnose.report.DragState;
import com.ankoninc.esdiagnose.report.ReportImageAdapter;
import com.ankoninc.imageview.model.DownloadResult;
import com.ankoninc.imageview.model.ImageDiagnoseItem;
import com.ankoninc.utils.Log;

import java.util.List;

/**
 * 报告图片的,item之间可移动交换
 * Created by zengna on 2016/6/8.
 */
public class ReportImageCell extends ReportBaseCell implements RecyclerView.OnItemTouchListener, ReportImageAdapter.ImageDragListener {

    private static final String LOG_TAG = "ReportImageCell";

    private TextView mNotifyView;
    private RecyclerView mImageContainer;
    private ReportImageAdapter mAdapter;
    private GridLayoutManager mLayoutManager;
    private DragManager dragManager;
    private final PointF dragTouchPoint = new PointF();

    private MedicalExamination mPatientExamination;
    private DownloadResult mDownloadResult;
    private ImageListener mImageListener;
    private GestureDetector mGestureDetector;

    public ReportImageCell(Context context) {
        this(context, null);
    }

    public ReportImageCell(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ReportImageCell(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        setupViews(context);
        init(context);
    }

    private void setupViews(Context context) {

        setTitle(R.string.report_examination_image);
        setButtonText(R.string.finish);
        setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                mAdapter.switchMode(false);
            }
        });
        setButtonVisibility(false);

        View view = inflate(context, R.layout.report_image_cell, this);
        mNotifyView = (TextView) view.findViewById(R.id.image_diagnose_notify);
        mImageContainer = (RecyclerView) view.findViewById(R.id.report_image_container);
    }

    private void init(Context context) {

        updateNotify();
        mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onDown(MotionEvent e) {
                Log.d(LOG_TAG, "onDown");
                View itemView  = mImageContainer.findChildViewUnder(e.getX(),e.getY());
                return super.onDown(e);
            }

            @Override
            public boolean onSingleTapConfirmed(MotionEvent e) {
                Log.d(LOG_TAG, "onSingleTapConfirmed");
                onItemTouched(mImageContainer, e);
                return super.onSingleTapConfirmed(e);
            }

            @Override
            public boolean onDoubleTap(MotionEvent e) {
                Log.d(LOG_TAG, "onDoubleTap");
                onItemTouched(mImageContainer, e);
                return super.onDoubleTap(e);
            }

            @Override
            public void onLongPress(MotionEvent e) {
                Log.d(LOG_TAG, "onLongPress");
                super.onLongPress(e);
            }

            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                return super.onScroll(e1, e2, distanceX, distanceY);
            }
        });

        mAdapter = new ReportImageAdapter(this, mPatientExamination, mDownloadResult,this);
        mLayoutManager = new GridLayoutManager(context, 2, VERTICAL, false);
        mImageContainer.setLayoutManager(mLayoutManager);
        mImageContainer.setAdapter(mAdapter);
        mImageContainer.addOnItemTouchListener(this);
        dragManager = new DragManager(mImageContainer, mAdapter);
        dragManager.setCanDrag(true);
        mImageContainer.setOnDragListener(dragManager);
    }

    public void updateNotify() {
            //捕获图片数量
        int capturedImagesCount = 0;
            //选中图片的数量
        int selectedImagesCount = 0;
        if (mDownloadResult != null) {
            List<ImageDiagnoseItem> items = mDownloadResult.findCapturedItems();
            if (items != null) {
                capturedImagesCount = items.size();
                List<ImageDiagnoseItem> selectedImages = DownloadResult.findSelectedImages(items);
                selectedImagesCount = selectedImages == null ? 0 : selectedImages.size();
            }
        }

        if (selectedImagesCount > 0) {
            mNotifyView.setText(getContext().getString(R.string.report_diagnose_notify_text, capturedImagesCount, selectedImagesCount));
        } else {
            mNotifyView.setText(R.string.report_cannot_upload_notify);
        }

        if (mImageListener != null) {
            mImageListener.onCountChanged(capturedImagesCount, selectedImagesCount);
        }
    }

    public void setDownloadResult(MedicalExamination examination, DownloadResult result) {
        mDownloadResult = result;
        mPatientExamination = examination;
        mAdapter.resetList(examination, result);
        updateNotify();
    }

    public void refreshDownload(int startIndex, int endIndex) {

        mAdapter.refreshDownload(startIndex, endIndex);
    }

    public void notifyItemChanged(ImageDiagnoseItem item) {
        mAdapter.notifyItemChanged(item);
    }

    public void startSelectImage() {
        if (mImageListener != null) {
            mImageListener.requestSelectImage();
        }
    }

    public void startEditImage(ImageDiagnoseItem item) {
        if (mImageListener != null) {
            mImageListener.requestShowEditDialog(item);
        }
    }

    public void setImageListener(ImageListener listener) {
        mImageListener = listener;
    }

    @Override
    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
        mGestureDetector.onTouchEvent(e);
        dragTouchPoint.set(e.getX(), e.getY());
        return false;
    }

    public List<ImageDiagnoseItem> getOrderedSelectedImages() {
        return mAdapter.getOrderedSelectedImages();
    }

    @Override
    public void onTouchEvent(RecyclerView rv, MotionEvent e) {
    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {

    }

    private void onItemTouched(RecyclerView rv, MotionEvent e) {
        View itemView = rv.findChildViewUnder(e.getX(), e.getY());
        Log.d(LOG_TAG, "onItemTouched itemView: %s", itemView);
        if (itemView != null) {
            int position = rv.getChildAdapterPosition(itemView);
            mAdapter.onItemClicked(position);
        }

    }

    @Override
    public void onStartDrag(View view, ImageDiagnoseItem item) {

        if (mImageListener != null && mImageListener.allowDrag()) {
            DragState dragState = new DragState(item, item.getIndex());
            DragShadowBuilder dragShadowBuilder = new com.ankoninc.esdiagnose.report.DragShadowBuilder(view,
                    new Point(((int) (dragTouchPoint.x - view.getX())), (int) (dragTouchPoint.y - view.getY())));
            Point shadowSize = new Point();
            Point shadowTouchPoint = new Point();
            dragShadowBuilder.onProvideShadowMetrics(shadowSize, shadowTouchPoint);
            view.startDrag(null, dragShadowBuilder, dragState, 0);
        }
    }

    public interface ImageListener {
        boolean allowDrag();
        void onCountChanged(int capturedImagesCount, int selectedImagesCount);
        void requestSelectImage();
        void requestShowEditDialog(ImageDiagnoseItem item);
    }
}

3、创建adapter

package com.ankoninc.esdiagnose.report;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

import com.ankoninc.data.ADVData;
import com.ankoninc.data.MedicalExamination;
import com.ankoninc.esdiagnose.AppContext;
import com.ankoninc.esdiagnose.R;
import com.ankoninc.esdiagnose.view.ReportImageCell;
import com.ankoninc.imageview.DragImageView;
import com.ankoninc.imageview.model.DownloadResult;
import com.ankoninc.imageview.model.ImageDiagnoseItem;
import com.ankoninc.utils.Log;

import java.util.List;

/**
 * Created by zengna on 2016/6/8.
 */
public class ReportImageAdapter extends RecyclerView.Adapter<ReportImageAdapter.ImageViewHolder> implements DragListener{

    private static final String LOG_TAG = "ReportImageAdapter";

    private static final int TYPE_DEFAULT = 0;
    private static final int TYPE_ADD = 1;
    private static final int TYPE_DELETE = 2;

    private Context mContext;
    private ReportImageCell mTargetView;
    private MedicalExamination mPatientExamination;
    private boolean mEditMode;
    private List<ImageDiagnoseItem> mList;
    private Bitmap mLoadingBitmap;
    private ImageDragListener mListener;

    private int dragItemId = DragListener.NO_ID;

    public ReportImageAdapter(ReportImageCell targetView, MedicalExamination examination,
                              DownloadResult downloadResult, ImageDragListener listener) {

        mContext = targetView.getContext();
        mTargetView = targetView;
        mListener = listener;
        resetList(examination, downloadResult);
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = 2;
        mLoadingBitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.loading, options);

    }


    public void resetList(MedicalExamination examination, DownloadResult downloadResult) {

        mPatientExamination = examination;

        if (downloadResult != null) {
            mList = downloadResult.getOrderedSelectedImagesByRemarks();
        }

        notifyDataSetChanged();
    }

    /**
     * 更新是否下载的标志
     * @param startIndex
     * @param endIndex
     */
    public void refreshDownload(int startIndex, int endIndex) {

        int count = getItemCount() - 2;
        if (count <= 0) {
            return;
        }

        // 因为有前后方向,所以重新定义start,end
        int start = Math.min(startIndex, endIndex);
        int end = Math.max(startIndex, endIndex);
        int validStart = Math.max(0, start);
        int validEnd = Math.min(end, count - 1);
        for (int i=validStart; i<=validEnd; i++) {
            ImageDiagnoseItem item = getItem(i);
            if (item == null) {
                continue;
            }
            item.setDownloaded(true);
            notifyItemChanged(i);
        }
    }

    public boolean isEditMode() {
        return mEditMode;
    }

    public void switchMode(boolean editMode) {

        if (editMode == mEditMode) {
            return;
        }

        mEditMode = editMode;
        notifyDataSetChanged();
        mTargetView.setButtonVisibility(editMode);
    }

    private void startSelectImage() {
        mTargetView.startSelectImage();
    }

    private void startEditImage(int position) {
        ImageDiagnoseItem item = getItem(position);
        if (item == null || !item.isDownloaded()) {
            return;
        }
        mTargetView.startEditImage(item);
    }

    public boolean onItemClicked(int position) {

        if (position < 0 || position >= getItemCount()) {
            return false;
        }

        int viewType = getItemViewType(position);
        switch (viewType) {
            case TYPE_ADD:
                if (mEditMode) {
                    switchMode(false);
                } else {
                    startSelectImage();
                }
                break;
            case TYPE_DELETE:
                switchMode(!mEditMode);
                break;
            case TYPE_DEFAULT:
            default:
                if (mEditMode) {
                    remove(position);
                } else {
                    startEditImage(position);
                }
                break;
        }
        return true;
    }

    public void notifyItemChanged(ImageDiagnoseItem item) {

        if (mList == null || mList.isEmpty()) {
            return;
        }

        int position = mList.indexOf(item);
        if (position == -1) {
            return;
        }

        notifyItemChanged(position);
    }

    /**
     *
     * @return
     */
    public List<ImageDiagnoseItem> getOrderedSelectedImages() {
        return mList;
    }

    @Override
    public ImageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View view = LayoutInflater.from(mContext).inflate(R.layout.report_image_item, parent, false);
        return new ImageViewHolder(view, new ImageViewHolder.OnLongClickListener() {
            @Override
            public void onLongClick(View view, int position) {
                ImageDiagnoseItem item = getItem(position);
                if (getItemViewType(position) == TYPE_DEFAULT && item != null) {
                    mListener.onStartDrag(view, item);
                }
            }
        });
    }

    @Override
    public void onBindViewHolder(ImageViewHolder holder, int position) {

        int viewType = getItemViewType(position);
        ImageDiagnoseItem item = getItem(position);
        Bitmap bitmap = null;
        if (item != null && item.isDownloaded()) {
            String patientName = mPatientExamination.getPatientName();
            ADVData.ImageInfo imageInfo = ADVData.getImageAt(mPatientExamination.getRecordUid(),
                    patientName, item.getFileNo(), item.getOffset());
            if (imageInfo != null && imageInfo.image != null) {
                bitmap = DragImageView.drawMarkImage(imageInfo.image, item.getPointInfos());
            }
        }
        holder.bind(bitmap == null ? mLoadingBitmap : bitmap, mEditMode, viewType);
    }

    @Override
    public int getItemViewType(int position) {

        int count = getItemCount();
        if (position == count-1) {
            return TYPE_DELETE;
        } else if (position == count-2) {
            return TYPE_ADD;
        } else {
            return TYPE_DEFAULT;
        }
    }

    @Override
    public int getItemCount() {
        int count = mList == null ? 0 : mList.size();
        return count + 2;
    }

    public ImageDiagnoseItem getItem(int position) {

        if (position >=0 && position < mList.size()) {
            return mList.get(position);
        }
        return null;
    }

    /**
     * 删除某张图片
     * @param position
     */
    public boolean remove(int position) {

        ImageDiagnoseItem item = getItem(position);
        if (item != null) {
            item.setSelected(false);
            item.setImageOrder(0);
            mList.remove(position);
            mTargetView.updateNotify();
            notifyItemRemoved(position);
            return true;
        }
        return false;
    }

    @Override
    public boolean onMoveItem(int fromPosition, int toPosition) {

        if (getItemViewType(toPosition) != TYPE_DEFAULT
                && getItemViewType(fromPosition) != getItemViewType(toPosition)) {
            return false;
        }
        mList.add(toPosition, mList.remove(fromPosition));
        notifyItemMoved(fromPosition, toPosition);
        return true;
    }

    @Override
    public void notifyItemChange(int position, int dragItemId) {

        this.dragItemId = dragItemId;
        notifyItemChanged(position);
    }

    @Override
    public int getPosition(Object object) {
        return mList.indexOf(object);
    }

    @Override
    public void onDragEnd(int position) {

    }

    static class ImageViewHolder extends RecyclerView.ViewHolder implements View.OnLongClickListener{

        private View mImageContainer;
        private ImageView mImage;
        private ImageView mDeleteButton;
        private OnLongClickListener mListener;

        public ImageViewHolder(View view, OnLongClickListener listener) {
            super(view);

            mImageContainer = view.findViewById(R.id.container);
            mImage = (ImageView) view.findViewById(R.id.image);
            mDeleteButton = (ImageView) view.findViewById(R.id.delete);
            mListener = listener;
            this.itemView.setOnLongClickListener(this);
        }

        public void bind(final Bitmap bitmap, final boolean editMode, final int viewType) {

            switch (viewType) {
                case TYPE_ADD:
                    bindAddButton(editMode);
                    break;
                case TYPE_DELETE:
                    bindDeleteButton(editMode);
                    break;
                default:
                    bindImage(bitmap, editMode);
            }
        }

        private void bindImage(final Bitmap bitmap, final boolean editMode) {

            mImage.setImageBitmap(bitmap);
            mDeleteButton.setVisibility(editMode ? View.VISIBLE : View.INVISIBLE);
            mImageContainer.setBackground(AppContext.getInstance().getResources().getDrawable(R.drawable.report_image_background));
        }

        private void bindAddButton(final boolean editMode) {

            mDeleteButton.setVisibility(View.GONE);
            mImage.setImageResource(R.drawable.report_image_add);
            mImageContainer.setBackground(AppContext.getInstance().getResources().getDrawable(R.drawable.report_image_button_background));
            itemView.setVisibility(editMode ? View.INVISIBLE : View.VISIBLE);
        }

        private void bindDeleteButton(final boolean editMode) {

            mDeleteButton.setVisibility(View.GONE);
            mImage.setImageResource(R.drawable.report_image_delete);
            mImageContainer.setBackground(AppContext.getInstance().getResources().getDrawable(R.drawable.report_image_button_background));
            itemView.setVisibility(editMode ? View.INVISIBLE : View.VISIBLE);
        }

        @Override
        public boolean onLongClick(View v) {
            Log.d("ImageViewHolder", "onLongClick");
            mListener.onLongClick(v, getAdapterPosition());
            return true;
        }


        interface OnLongClickListener {
            void onLongClick(View view, int position);
        }
    }

    public interface ImageDragListener {
        void onStartDrag(View view, ImageDiagnoseItem item);
    }

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值