效果图如上,实现思路有三点。
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 {treeView访问者
//访问节点
void visit(Node node);
}
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);}在学习组合模式和访问者模式中产生想法并实现了组件的雏形,并未使用到项目,希望各位大神提供宝贵意见。