ExpandableListView的拖动重新分组-DropDrag

来源:互联网 发布:赵敏 张无忌的爱情知乎 编辑:程序博客网 时间:2024/05/16 07:24

工作N年了,从来没写过什么博客,这是本人在CSDN中的处女作偷笑,从Java转到Android,的确有好多东西需要学习快哭了,而且还是自学。好,废话不多说,直接上代码奋斗

此功能是直接从项目中拷贝过来的,稍微做了一些修改,不过这个拖动有一点还没有实现:当拖动Item到最上方与到最下方没有做处理,也就是说能托出ExpandableListView不滚动。

后期做完之后,还会继续更新。如果有写的不好的地方,请大家尽管提出来。大家一起学习

因为启动虚拟机比较慢,所以就不截图了,见谅……大笑

ExpandableListView的Adapter

package com.dropdrag.adapter;import android.app.Activity;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.graphics.Matrix;import android.graphics.drawable.BitmapDrawable;import android.graphics.drawable.Drawable;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseExpandableListAdapter;import android.widget.ImageView;import android.widget.TextView;import com.dropdrag.activity.R;import java.util.List;import java.util.Map;/** * @author 权冠洲 * @author 个人博客:http://blog.csdn.net/quan356270259 * 实现ExpandableListView的Item重新分组 * Created by Quanguanzhou on 2015/9/22. */public class DragAndDropExpandableAdapter extends BaseExpandableListAdapter {    private Context mContext;    private List<Map<String, String>> groupData;// 大组成员    private List<List<Map<String, String>>> childData;// 小组成员    private Activity baseActivity;    public DragAndDropExpandableAdapter(Activity activity, Context context, List<Map<String, String>> groups, List<List<Map<String, String>>> childs) {        this.mContext = context;        this.groupData = groups;        this.childData = childs;        this.baseActivity = activity;    }    class ViewHolderChild{        public TextView title;        public TextView title2 ;        public TextView title3;        public TextView title4 ;        public ImageView sortItem;    }    class ViewHolderGroup{        public TextView title;        public TextView countTo;        public ImageView image;        public TextView tvGroupCode;    }    /**     * 获取指定组中的指定子元素数据     * @param groupPosition     * @param childPosition     * @return   返回指定子元素数据。     */    public Object getChild(int groupPosition, int childPosition) {        return childData.get(groupPosition).get(childPosition).get("MachineName").toString();    }    /**     * 获取指定组中的指定子元素ID,这个ID在组里一定是唯一的。     * 在所有条目(所有组和所有元素)中也是唯一的。     * @param arg0     * @param childPosition     * @return     */    public long getChildId(int arg0, int childPosition) {        return childPosition;    }    /**     * 获取一个视图对象,显示指定组中的指定子元素数据。     * @param groupPosition 组位置(该组内部含有子元素)     * @param childPosition 子元素位置(决定返回哪个视图)     * @param isExpanded 子元素是否处于组中的最后一个     * @param convertView 重用已有的视图(View)对象。     *                    注意:在使用前你应该检查一下这个视图对象是否非空并且这个对象的类型是否合适。     *                    由此引伸出,如果该对象不能被转换并显示正确的数据,     *                    这个方法就会调用getChildView(int, int, boolean, View, ViewGroup)来创建一个视图(View)对象。     * @param parent 返回的视图(View)对象始终依附于的视图组。     * @return 指定位置上的子元素返回的视图对象     */    public View getChildView(int groupPosition, final int childPosition, boolean isExpanded, View convertView, ViewGroup parent) {        ViewHolderChild viewHolderChild = null;        if (convertView == null) {            LayoutInflater inflater = LayoutInflater.from(mContext);            convertView = inflater.inflate(R.layout.listview_child, null);            viewHolderChild = new ViewHolderChild();            viewHolderChild.title = (TextView) convertView.findViewById(R.id.child_text);            viewHolderChild.title2 = (TextView) convertView.findViewById(R.id.child_text2);            viewHolderChild.title3 = (TextView) convertView.findViewById(R.id.child_text3);            viewHolderChild.title4 = (TextView) convertView.findViewById(R.id.child_text4);            viewHolderChild.sortItem = (ImageView) convertView.findViewById(R.id.sortItem); //排序            convertView.setTag(viewHolderChild);        }else {            viewHolderChild = (ViewHolderChild) convertView.getTag();        }        viewHolderChild.title.setText(childData.get(groupPosition).get(childPosition).get("MachineName").toString());// 设备名称        viewHolderChild.title2.setText(childData.get(groupPosition).get(childPosition).get("MachineTip").toString());// 设备ID与车牌号        viewHolderChild.title3.setText(childData.get(groupPosition).get(childPosition).get("MachineCode").toString());// 隐藏的设备ID        viewHolderChild.title4.setText(childData.get(groupPosition).get(childPosition).get("MaintainCount").toString());// 是否保养        return convertView;    }    /**     * 获取指定组中的子元素个数     * @param groupPosition  组位置(决定返回哪个组的子元素个数)     * @return 指定组的子元素个数     */    public int getChildrenCount(int groupPosition) {        return childData.get(groupPosition).size();    }    /**     * 获取指定组中的数据     * @param groupPosition     * @return 返回组中的数据,也就是该组中的子元素数据     */    public Object getGroup(int groupPosition) {        return groupData.get(groupPosition).get("groupName").toString();    }    /**     * 获取组的个数     * @return 组的个数     */    public int getGroupCount() {        return groupData.size();    }    /**     * 获取指定组的ID,这个组ID必须是唯一的 在所有条目(所有组和所有元素)中也是唯一的。     * @param groupPosition 组位置     * @return 返回组相关ID     */    public long getGroupId(int groupPosition) {        return groupPosition;    }    /**     * 获取显示指定组的视图对象。这个方法仅返回关于组的视图对象,要想获取子元素的视图对象,就需要调用getChildView(int, int, boolean, View, ViewGroup)。     * @param groupPosition 组位置(决定返回哪个视图)     * @param isExpanded 该组是展开状态还是伸缩状态     * @param convertView 重用已有的视图对象。注意:在使用前你应该检查一下这个视图对象是否非空并且这个对象的类型是否合适。     *                    由此引伸出,如果该对象不能被转换并显示正确的数据,     *                    这个方法就会调用getGroupView(int, boolean, View, ViewGroup)来创建一个视图(View)对象。     * @param parent 返回的视图对象始终依附于的视图组。     * @return 返回指定组的视图对象     */    public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {        ViewHolderGroup viewHolderGroup = null;        //View view = convertView;        if (convertView == null) {            //LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);            LayoutInflater inflater = LayoutInflater.from(mContext);            convertView = inflater.inflate(R.layout.listview_header, null);            viewHolderGroup = new ViewHolderGroup();            viewHolderGroup.title = (TextView) convertView.findViewById(R.id.groupName);            viewHolderGroup.countTo = (TextView) convertView.findViewById(R.id.countTo);            viewHolderGroup.image = (ImageView) convertView.findViewById(R.id.tubiao);// 是否展开大组的箭头图标            viewHolderGroup.tvGroupCode = (TextView) convertView.findViewById(R.id.tvGroupCode);            convertView.setTag(viewHolderGroup);        }else {            viewHolderGroup = (ViewHolderGroup) convertView.getTag();        }        viewHolderGroup.title.setText(getGroup(groupPosition).toString());// 设置大组成员名称        String maintainStatus = groupData.get(groupPosition).get("MachineMaintainStatus");        String groupCode = groupData.get(groupPosition).get("groupCode");        viewHolderGroup.countTo.setText(maintainStatus + "/" + getChildrenCount(groupPosition));        viewHolderGroup.tvGroupCode.setText(groupCode);        if (isExpanded) {// 大组展开时            Matrix matrix = new Matrix();            Bitmap bitmapOrg = BitmapFactory.decodeResource(mContext.getResources(), R.mipmap.btn_browser);            matrix.postRotate(90f);//x旋转的角度            matrix.postTranslate(bitmapOrg.getWidth(), bitmapOrg.getHeight());            Bitmap bm = Bitmap.createBitmap(bitmapOrg, 0, 0, bitmapOrg.getWidth(), bitmapOrg.getHeight(), matrix, true);            //将上面创建的Bitmap转换成Drawable对象,使得其可以使用在ImageView, ImageButton中            BitmapDrawable bmd = new BitmapDrawable(convertView.getResources(),bm);            viewHolderGroup.image.setBackground(bmd);        } else {            // 大组合并时            viewHolderGroup.image.setBackgroundResource(R.mipmap.btn_browser);        }        return convertView;    }    /**     * 组和子元素是否持有稳定的ID,也就是底层数据的改变不会影响到它们。     * @return 返回一个Boolean类型的值,如果为TRUE,意味着相同的ID永远引用相同的对象     */    public boolean hasStableIds() {        return true;    }    /**     * 是否选中指定位置上的子元素。     * @param groupPosition 组位置(该组内部含有这个子元素)     * @param childPosition 子元素位置     * @return 是否选中子元素     */    public boolean isChildSelectable(int groupPosition, int childPosition) {        return true;    }    /**     * 如果当前适配器不包含任何数据则返回True。经常用来决定一个空视图是否应该被显示。     * 一个典型的实现将返回表达式getCount() == 0的结果,     * 但是由于getCount()包含了头部和尾部,适配器可能需要不同的行为。     * @return     */    //public boolean isEmpty (){}    /**     * 当组展开状态的时候此方法被调用。     * @param groupPosition 展开状态的组位置     */    public void onGroupExpanded(int groupPosition){}    /**     * 当组收缩状态的时候此方法被调用。     * @param groupPosition 收缩状态的组索引     */    public void onGroupCollapsed (int groupPosition){}}

 

创建一个实现ExpandableListView拖动的接口,以便在主Activity中使用回调函数

 

package com.dropdrag.listener;import android.view.View;import android.widget.ListView;/** * @author 权冠洲 * @author 个人博客:http://blog.csdn.net/quan356270259 * 实现ExpandableListView的Item重新分组 * Created by Quanguanzhou on 2015/9/22. */public interface DragAndDropListener {    /**     * 开始拖动时调用     *     * @param itemView 要拖动的视图     */    void onStartDrag(View itemView);    /**     * 当拖动时调用     *     * @param x        横坐标的位移事件。     * @param y        垂直坐标的位移事件。     * @param listView     */    void onDrag(int x, int y, ListView listView);    /**     * 当拖动停止时调用     *     * @param itemView 要拖动的视图     */    void onStopDrag(View itemView);    /**     * 当停止拖动时被调用,松开拖动     *     * @param flatPosFrom     * @param flatPosTo     */    void onDrop(int flatPosFrom, int flatPosTo);}


接下来是拖动的重点了

package com.dropdrag.view;import android.content.Context;import android.graphics.Bitmap;import android.graphics.PixelFormat;import android.util.AttributeSet;import android.view.Gravity;import android.view.MotionEvent;import android.view.View;import android.view.WindowManager;import android.widget.ExpandableListView;import android.widget.ImageView;import com.dropdrag.listener.DragAndDropListener;/** * @author 权冠洲 * @author 个人博客:http://blog.csdn.net/quan356270259 * 实现ExpandableListView的Item重新分组 * Created by Quanguanzhou on 2015/9/22. */public class DragAndDropExpandableListView extends ExpandableListView {    private boolean mDragMode;    private int mStartPosition;    private int mDragPointOffset; //用于调整拖动视图位置    private ImageView mDragView;    private DragAndDropListener mDragAndDropListener;    public DragAndDropExpandableListView(Context context, AttributeSet attrs) {        super(context, attrs);    }    public void setDragNDropListener(DragAndDropListener l) {        mDragAndDropListener = l;    }    @Override    public boolean onTouchEvent(MotionEvent ev) {        if (ev.getActionIndex() != 0) {            return super.onTouchEvent(ev);        }        final int action = ev.getAction();        final int x = (int) ev.getX(0);        final int y = (int) ev.getY(0);        if (action == MotionEvent.ACTION_DOWN && x > getWidth() - 80) { // 只拖动该项的右边部分,可以调整            mDragMode = true;        }        if (!mDragMode) {            return super.onTouchEvent(ev);        }        switch (action) {            case MotionEvent.ACTION_DOWN:                mStartPosition = pointToPosition(x, y);                if (mStartPosition != INVALID_POSITION) {                    int mItemPosition = mStartPosition - getFirstVisiblePosition();                    mDragPointOffset = y - getChildAt(mItemPosition).getTop();                    mDragPointOffset -= ((int) ev.getRawY()) - y;                    startDrag(mItemPosition, y);                    drag(0, y);// 如果需要可以把0替换成:x                }                break;            case MotionEvent.ACTION_MOVE:                drag(0, y);// 如果需要可以把0替换成:x                break;            case MotionEvent.ACTION_CANCEL:            case MotionEvent.ACTION_UP:            default:                mDragMode = false;                int endPosition = pointToPosition(x, y);                stopDrag(mStartPosition - getFirstVisiblePosition());                if (mDragAndDropListener != null && mStartPosition != INVALID_POSITION && endPosition != INVALID_POSITION) {                    //调用实现接口的方法                    mDragAndDropListener.onDrop(mStartPosition, endPosition);                }                break;        }        return ev.getPointerCount() <= 1 || super.onTouchEvent(ev);    }    /**     * 移动视图getHeight();     * @param x 你的小手停放X轴的位置     * @param y 如果拖动的ItemView,Y小于50(因为上方还有标题栏高度是50),列表开始向上移动,如果Y大于getHeight()-10.列表开始向下移动     */    private void drag(int x, int y) {        if (mDragView != null) {            WindowManager.LayoutParams layoutParams = (WindowManager.LayoutParams) mDragView.getLayoutParams();            layoutParams.x = x;            layoutParams.y = y - mDragPointOffset;            WindowManager mWindowManager = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);            mWindowManager.updateViewLayout(mDragView, layoutParams);            if (mDragAndDropListener != null) {                //调用实现接口的方法                mDragAndDropListener.onDrag(x, y, this);            }        }    }    private void startDrag(int itemIndex, int y) {        stopDrag(itemIndex);        View item = getChildAt(itemIndex);        if (item == null)            return;        if (mDragAndDropListener != null) {            //调用实现接口的方法            mDragAndDropListener.onStartDrag(item);        }        WindowManager.LayoutParams mWindowParams = new WindowManager.LayoutParams();        mWindowParams.gravity = Gravity.TOP;        mWindowParams.x = 0;        mWindowParams.y = y - mDragPointOffset;        mWindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT;        mWindowParams.width = WindowManager.LayoutParams.WRAP_CONTENT;        mWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;        mWindowParams.format = PixelFormat.TRANSLUCENT;        mWindowParams.windowAnimations = 0;        Context context = getContext();        // 创建一个绘图缓存的副本,以便它不被回收        ImageView v = new ImageView(context);        item.setDrawingCacheEnabled(true);        Bitmap bitmap = Bitmap.createBitmap(item.getDrawingCache());        item.setDrawingCacheEnabled(false);        v.setBackgroundResource(android.R.color.holo_blue_dark);        v.setImageBitmap(bitmap);        WindowManager mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);        mWindowManager.addView(v, mWindowParams);        mDragView = v;    }    // 销毁拖动的视图    private void stopDrag(int itemIndex) {        if (mDragView != null) {            if (mDragAndDropListener != null) {                //调用实现接口的方法                mDragAndDropListener.onStopDrag(getChildAt(itemIndex));            }            mDragView.setVisibility(GONE);            WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);            wm.removeView(mDragView);            mDragView.setImageDrawable(null);            mDragView = null;        }    }    /**     *     * @param flatPos     * @return     */    public long getItemIdAtPosition(int flatPos) {        if(-1!=flatPos) {            long packedPos = getExpandableListPosition(flatPos);            if (ExpandableListView.getPackedPositionType(packedPos) == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {                return getExpandableListAdapter().getGroupId(ExpandableListView.getPackedPositionGroup(packedPos));            } else {                return getExpandableListAdapter().getChildId(ExpandableListView.getPackedPositionGroup(packedPos), ExpandableListView.getPackedPositionChild(packedPos));            }        }else{            return flatPos;        }    }}


 


写到这里基本上就可以实现拖动了,不过还没法更新ExpandableListView,我们继续看MainActivity的代码

package com.dropdrag.activity;import android.app.Activity;import android.content.Context;import android.os.Bundle;import android.view.View;import android.widget.ExpandableListView;import android.widget.ListView;import android.widget.TextView;import com.dropdrag.adapter.DragAndDropExpandableAdapter;import com.dropdrag.view.DragAndDropExpandableListView;import com.dropdrag.listener.DragAndDropListener;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;/** * @author 权冠洲 * @author 个人博客:http://blog.csdn.net/quan356270259 * 实现ExpandableListView的Item重新分组 * Created by Quanguanzhou on 2015/9/22. */public class MainActivity extends Activity {    private DragAndDropExpandableListView dadelvlist;    private List<Map<String, String>> groups = new ArrayList<Map<String, String>>(); //分组List    private List<List<Map<String, String>>> childs = new ArrayList<List<Map<String, String>>>(); //分组中的Item 集合    private DragAndDropExpandableAdapter adapter; //适配器    private Context mContext;    private String re_group_groupCode;    private String re_group_machineCode;    private String flag="";    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_regroup);        initView();        initData();    }    private void initView() {        dadelvlist = (DragAndDropExpandableListView) findViewById(R.id.dadelvlist);        mContext = getApplicationContext();        // 打开一个分组,关闭其它分组        dadelvlist.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() {            public void onGroupExpand(int groupPosition) {                for (int i = 0, total = adapter.getGroupCount(); i < total; i++) {                    if (groupPosition != i) {                        dadelvlist.collapseGroup(i); //关闭分组                    }                }            }        });    }    /**     * 这里应该是从WebService中获取数据     */    private void initData() {        for (int i = 0; i < 10; i++) {            Map<String, String> group = new HashMap<String, String>();            group.put("groupName", "分组" + i); // 分组的名称            group.put("groupCode", "group" + i); // 分组的Code            List<Map<String, String>> child = new ArrayList<Map<String, String>>();            for (int j = 0; j < 10; j++) {                Map<String, String> childdata = new HashMap<String, String>();                childdata.put("MachineName", "分组"+i+"中的设备名称"+j);                childdata.put("MachineTip", "设备备注"+j);                childdata.put("MachineCode", "设备编码"+j);                childdata.put("MaintainCount", ""+j);                String concern = "0";                if(i/2==1){                    concern = "1";                }else {                    concern = "0";                }                childdata.put("IsConcern", concern);                childdata.put("MachineStatus", "0");                child.add(childdata);            }            group.put("MachineMaintainStatus", "1");            groups.add(group);            childs.add(child);        }        adapter = new DragAndDropExpandableAdapter(MainActivity.this, mContext, groups, childs);        dadelvlist.setAdapter(adapter);        initListener();    }    private void initListener() {        dadelvlist.setFastScrollEnabled(true);        dadelvlist.setChoiceMode(ListView.CHOICE_MODE_SINGLE);        //ExpandableListView 的回调函数        dadelvlist.setDragNDropListener(new DragAndDropListener() {            public void onStartDrag(View itemView) {            }            public void onDrag(int x, int y, ListView listView) {            }            public void onStopDrag(View itemView) {            }            public void onDrop(int flatPosFrom, int flatPosTo) {                final boolean fromIsGroup = ExpandableListView.getPackedPositionType(dadelvlist.getExpandableListPosition(flatPosFrom)) == ExpandableListView.PACKED_POSITION_TYPE_GROUP;// 判断移动的是不是组                final boolean toIsGroup = ExpandableListView.getPackedPositionType(dadelvlist.getExpandableListPosition(flatPosTo)) == ExpandableListView.PACKED_POSITION_TYPE_GROUP;// 判断是否移动到分组上                final long packedPosTo = dadelvlist.getExpandableListPosition(flatPosTo);                final long packedPosFrom = dadelvlist.getExpandableListPosition(flatPosFrom);                final int packedGroupPosTo = ExpandableListView.getPackedPositionGroup(packedPosTo);                final int packedGroupPosForm = ExpandableListView.getPackedPositionGroup(packedPosFrom);                if ((!fromIsGroup) && toIsGroup) {// 如果移动的不是组,并且是移动到组上                    long itemId = dadelvlist.getItemIdAtPosition(flatPosFrom);                    long position = dadelvlist.getItemIdAtPosition(flatPosTo);                    HashMap<String, String> tmp = (HashMap<String, String>) childs.get(((int) packedGroupPosForm)).get((int) itemId);// 移动的Item项                    List<Map<String, String>> tmpList = (List<Map<String, String>>) childs.get((int) packedGroupPosForm);                    childs.get((int) packedGroupPosForm).remove(tmp); //  把该 条数据从当前组中进行删除                    List<Map<String, String>> tmp1 = (List<Map<String, String>>) childs.get(((int) packedGroupPosTo));  // 要移动到分组中的列表                    (childs.get(((int) packedGroupPosTo))).add(tmp); //把该 条数据添加到移动之后的组中                    adapter.notifyDataSetChanged();                    View toView = dadelvlist.getChildAt(flatPosTo - dadelvlist.getFirstVisiblePosition()); //获取移动到分组的View                    TextView groupCodeView = (TextView) toView.findViewById(R.id.tvGroupCode);                    re_group_groupCode = groupCodeView.getText().toString(); // 移动Item时,移动到组的编码                    View fromView = dadelvlist.getChildAt(flatPosFrom - dadelvlist.getFirstVisiblePosition());  // 要移动的设备View                    TextView tvMachineView = (TextView) fromView.findViewById(R.id.child_text3);                    re_group_machineCode = tvMachineView.getText().toString();  // 移动Item时,该条Item的编码                    moveItem();                }            }        });    }    /**     * 此方法开始操作数据库     * 根据:re_group_groupCode与re_group_machineCode     */    private void moveItem() {    }}


文中写的注释应该可以理解的通,相信大家根据这点代码可以实现ExpandableListView的拖动,如果需要源代码的请联系我QQ:356270259

转载请注明出处:http://blog.csdn.net/quan356270259/article/details/48663461
 

0 0
原创粉丝点击