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