[置顶] 利用组合模式与访问者模式实现Android树形控件(多层级,可拖拽)

时间:2022-02-17 16:03:08

[置顶]        利用组合模式与访问者模式实现Android树形控件(多层级,可拖拽)

效果图如上,实现思路有三点。

1.使用组合模式组织部门员工数据结构。

2.使用访问者模式定义并解耦对部门、员工元素的操作。

3.使用Android的拖放框架,能够允许用户使用图形化的拖放手势,把数据从当前布局中的一个View对象中移到另一个View对象中。

代码:叶节点

public class Node implements NodeAccept, Serializable {

//节点层级
private int layer;

//节点名称
private String nodeName;

//父节点
private NodeGroup parentNode;

public Node(String name) {
this.nodeName = name;
}

@Override
public void accept(NodeVisitor visitor) {
visitor.visit(this);
}

//获得父节点
public NodeGroup getParent() {
return parentNode;
}

//从父节点移除自己
public void destory() {
getParent().removeChild(this);
}

public String getNodeName() {
return nodeName;
}

public void setNodeName(String nodeName) {
this.nodeName = nodeName;
}

public void setParentNode(NodeGroup parentNode) {
this.parentNode = parentNode;
}

public int getLayer() {
return layer;
}

public void setLayer(int layer) {
this.layer = layer;
}

}
枝节点
public class NodeGroup extends Node implements NodeManager, NodeAccept {    //是否是根节点    private boolean root;    //子节点存储    private List<Node> components;    public NodeGroup(String name) {        super(name);        components = new ArrayList<>();    }    public NodeGroup(String name, boolean root) {        super(name);        this.root = root;        components = new ArrayList<>();    }    @Override    public void setLayer(int layer) {        super.setLayer(layer);        for (Node node:components){            node.setLayer(getLayer() + 1);        }    }    @Override    public void addChild(Node node) {        node.setParentNode(this);        node.setLayer(getLayer() + 1);        components.add(node);    }    @Override    public void removeChild(Node node) {        node.setParentNode(null);        components.remove(node);    }    @Override    public List<Node> getAllChild() {        return components;    }    @Override    public Node getChildAt(int index) {        return components.get(index);    }    @Override    public int getChildCount() {        return components.size();    }    @Override    public void accept(NodeVisitor visitor) {        visitor.visit(this);    }    @Override    public NodeGroup getParent() {        if (isRoot()) {            throw new RuntimeException("node is root");        }        return super.getParent();    }    @Override    public void destory() {        if (isRoot()) {            return;        }        super.destory();    }    public boolean isRoot() {        return root;    }    public void setRoot(boolean root) {        this.root = root;    }}
访问接口
public interface NodeAccept {    //接受访问者    void accept(NodeVisitor visitor);}
枝节点接口
public interface NodeManager {    //添加子节点    void addChild(Node node);    //删除子节点    void removeChild(Node node);    //获得所有子节点    List<Node> getAllChild();    //根据下标获得子节点    Node getChildAt(int index);    //获取子节点个数    int getChildCount();}
访问者
public interface NodeVisitor {
//访问节点
void visit(Node node);
}
treeView访问者
public class TreeViewVisitor implements NodeVisitor {    private Context mContext;    private Node dropNode;    private ViewGroup rootView;    private OnDragChange onDragChange;    private HashMap<String, LinearLayout> list;    public TreeViewVisitor(Context context) {        this.mContext = context;        this.list = new HashMap<>();    }    @Override    public void visit(Node node) {        LinearLayout parent = list.get(node.getParent().getNodeName());        parent.addView(getTextView(node));    }    @Override    public void visit(NodeGroup nodeGroup) {        if (nodeGroup.isRoot()) {            createNodeGroupView(nodeGroup);        } else {            if (list.containsKey(nodeGroup.getParent().getNodeName())) {                LinearLayout parentLayout = list.get(nodeGroup.getParent().getNodeName());                parentLayout.addView(createNodeGroupView(nodeGroup));            } else {                createNodeGroupView(nodeGroup);            }        }        List<Node> nodes = nodeGroup.getAllChild();        for (Node e : nodes) {            e.accept(this);        }    }    //获取任意节点下的view    public ViewGroup getShowView(Node node) {        rootView = list.get(node.getNodeName());        return rootView;    }    //创建NodeGrop组视图    private LinearLayout createNodeGroupView(final NodeGroup nodeGroup) {        TextView textView = getTextView(nodeGroup);        LinearLayout parentLayout = getParentLayout();        parentLayout.addView(textView);        parentLayout.setOnDragListener(new View.OnDragListener() {  //拖拽            @Override            public boolean onDrag(View v, DragEvent event) {                switch (event.getAction()) {                    case DragEvent.ACTION_DRAG_STARTED:                        break;                    case DragEvent.ACTION_DRAG_ENTERED:                        break;                    case DragEvent.ACTION_DRAG_EXITED:                        break;                    case DragEvent.ACTION_DRAG_LOCATION:                        break;                    case DragEvent.ACTION_DRAG_ENDED:                        break;                    case DragEvent.ACTION_DROP:                        if (!nodeGroup.getNodeName().equals(dropNode.getNodeName()) &&                                !dropNode.getParent().getNodeName().equals(nodeGroup.getNodeName())) {                            Toast.makeText(mContext,dropNode.getNodeName() + "移动至" + nodeGroup.getNodeName(),Toast.LENGTH_SHORT).show();                            dropNode.destory();                            nodeGroup.addChild(dropNode);                            if (onDragChange != null) {                                onDragChange.dragChange();                            }                        }                        break;                    default:                        break;                }                return true;            }        });        textView.setOnClickListener(new MyOnClickListener(parentLayout));        list.put(nodeGroup.getNodeName(), parentLayout);        return parentLayout;    }    //创建布局    private LinearLayout getParentLayout() {        LinearLayout linearLayout = new LinearLayout(mContext);        linearLayout.setOrientation(LinearLayout.VERTICAL);        return linearLayout;    }    //创建文本视图    private TextView getTextView(final Node node) {        TextView textView = new TextView(mContext);        if (node instanceof NodeGroup) {            bindDrawable(textView, R.mipmap.down);        }        textView.setBackgroundResource(R.drawable.shape_circle);        textView.setPadding(50 * node.getLayer() + 15, 30, 30, 30);        textView.setTextSize(17);        textView.setText(node.getNodeName() + " (层级" + node.getLayer() + ")");        //长按拖拽        textView.setOnLongClickListener(new View.OnLongClickListener() {            @Override            public boolean onLongClick(View view) {                dropNode = node;                view.setTag(node.getNodeName());                ClipData.Item item = new ClipData.Item(node.getNodeName());                String[] mimeTypes = {ClipDescription.MIMETYPE_TEXT_PLAIN};                ClipData dragData = new ClipData(view.getTag().toString(), mimeTypes, item);                View.DragShadowBuilder myShadow = new View.DragShadowBuilder(view);                view.startDrag(dragData, myShadow, null, 0);                return true;            }        });        return textView;    }    //数据拖动后回调    public interface OnDragChange {        void dragChange();    }        public void setOnDragChange(OnDragChange onDragChange) {        this.onDragChange = onDragChange;    }        //点击隐藏显示    private class MyOnClickListener implements View.OnClickListener {        private LinearLayout layout;        public MyOnClickListener(LinearLayout linearLayout) {            this.layout = linearLayout;        }        @Override        public void onClick(View view) {            int childCount = layout.getChildCount();            for (int i = 0; i < childCount; i++) {                if (i != 0) {                    int visibility = layout.getChildAt(i).getVisibility();                    TextView textView = (TextView) view;                    if (visibility == View.GONE) {                        bindDrawable(textView, R.mipmap.down);                        layout.getChildAt(i).setVisibility(View.VISIBLE);                    } else {                        bindDrawable(textView, R.mipmap.up);                        layout.getChildAt(i).setVisibility(View.GONE);                    }                }            }        }    }        //绑定展开,伸展图片    private void bindDrawable(TextView textView, int id) {        Drawable drawable = textView.getContext().getResources().getDrawable(id);        drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight());        textView.setCompoundDrawables(drawable, null, null, null);        textView.setCompoundDrawablePadding(15);    }}
执行代码
    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        final LinearLayout contentView = new LinearLayout(this);        setContentView(contentView);        Node A1 = new Node("安卓1");        Node A2 = new Node("安卓2");        Node P1 = new Node("php1");        Node P2 = new Node("php2");        Node C1 = new Node("产品1");        final NodeGroup aiju = new NodeGroup("爱聚公司", true);        NodeGroup development = new NodeGroup("研发部");        NodeGroup product = new NodeGroup("产品部");        NodeGroup android = new NodeGroup("安卓小组");        NodeGroup php = new NodeGroup("PHP小组");        aiju.addChild(development);        aiju.addChild(product);        development.addChild(android);        development.addChild(php);        product.addChild(C1);        php.addChild(P1);        php.addChild(P2);        android.addChild(A1);        android.addChild(A2);        final TreeViewVisitor treeViewVisitor = new TreeViewVisitor(this);        aiju.accept(treeViewVisitor);        treeViewVisitor.setOnDragChange(new TreeViewVisitor.OnDragChange() {            @Override            public void dragChange() {                aiju.accept(show);                contentView.removeAllViews();                ViewGroup viewGroup = show.getShowView(aiju);                contentView.addView(viewGroup);            }        });        ViewGroup viewGroup = show.getShowView(treeViewVisitor);        contentView.addView(viewGroup);}
在学习组合模式和访问者模式中产生想法并实现了组件的雏形,并未使用到项目,希望各位大神提供宝贵意见。