1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
package com.application.zhangshi_app_android.widget;
 
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
 
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.utils.widget.ImageFilterView;
 
import com.android.app_base.utils.GlideUtil;
import com.android.app_base.utils.ScreenSizeUtils;
import com.application.zhangshi_app_android.R;
import com.application.zhangshi_app_android.bean.HomeRootBean;
 
import java.util.HashMap;
import java.util.Map;
 
/**
 * @author Ljj
 * @date 2023.08.12. 1:19
 * @desc 家族导图 自定义布局
 */
public class HomeMindMapLayout extends FrameLayout {
    boolean isAutoLayout = true;// 是否自动布局
    private Paint linePaint;
    private HomeRootBean rootMember;// 根节点成员
    private Node rootNode;// 根节点
    private int width, height;// 当前布局的宽高
    private int minHeight, minWidth;// 当前布局的最小宽高
    private int padding = 100;//内容矩形 与 FrameLayout矩形 的padding
    private OnItemClickListener onItemClickListener;// 点击事件
    public HomeMindMapLayout(@NonNull Context context) {
        this(context, null);
    }
 
    public HomeMindMapLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }
 
    private void init() {
        linePaint = new Paint();
        linePaint.setColor(Color.parseColor("#FFEBA4AA"));
        linePaint.setStrokeWidth(ScreenSizeUtils.dip2px(2f));
        linePaint.setStyle(Paint.Style.STROKE);
        linePaint.setStrokeJoin(Paint.Join.ROUND);
        linePaint.setStrokeMiter(10);
        linePaint.setAntiAlias(true);
 
        // 设置ViewGroup默认调用onDraw方法
        setWillNotDraw(false);
    }
 
    public void setRootMember(HomeRootBean root) {
        //等待布局加载完成后再设置数据
        post(new Runnable() {
            @Override
            public void run() {
                setRootMemberReal(root);
            }
        });
    }
 
    private void setRootMemberReal(HomeRootBean root) {
        this.rootMember = root;
        if (rootMember != null) { // 绘制根节点,在竖直方向上居中
            if (rootMember.getSpouse() == null){
                rootNode = new SimpleNode(getContext(),rootMember);
            }else {
                rootNode = new DoubleNode(getContext(),rootMember);
            }
            rootNode.setPosition(padding,padding);
            //把所有节点的view添加到viewGroup中
            addNodeView(rootNode);
            requestLayout();
            if (onItemClickListener != null){
                rootNode.setOnItemClickListener(onItemClickListener);
            }
        }
    }
    public void setOnItemClickListener(OnItemClickListener listener){
        this.onItemClickListener = listener;
        if (rootNode != null){
            rootNode.setOnItemClickListener(onItemClickListener);
        }
    }
 
    private void addNodeView(Node rootNode) {
        for (View view : rootNode.viewList) {
            addView(view);
        }
        if (rootNode.getChildren() != null && rootNode.getChildren().size() > 0) {
            for (Node child : rootNode.getChildren()) {
                addNodeView(child);
            }
        }
    }
 
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
    }
 
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if(rootNode != null){
            // 是否自适应布局
            if (isAutoLayout) {
                //需要随着内容的显示内容动态显示view
                rootNode.setPosition(padding, padding);
                width = rootNode.getAllVisibleWidth() + padding * 2;
                height = rootNode.getAllVisibleHeight() + padding * 2;
            } else {
                //不需要随着内容的显示内容动态显示view
                width = rootNode.getAllWidth() + padding * 2;
                height = rootNode.getAllHeight() + padding * 2;
            }
        }
        setMeasuredDimension(Math.max(minWidth,width),Math.max(minHeight,height));
    }
 
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (rootNode != null) {
            drawNodeLine(canvas, rootNode);
        }
    }
 
    private void drawNodeLine(Canvas canvas, Node rootNode) {
        //根据根节点的可见性判断是否绘制线条
        if (rootNode.isVisible()){
            if (rootNode.nextPathList != null) {
                for (Path path : rootNode.nextPathList) {
                    canvas.drawPath(path, linePaint);
                }
            }
            if (rootNode.prePathList != null) {
                for (Path path : rootNode.prePathList) {
                    canvas.drawPath(path, linePaint);
                }
            }
            if (rootNode.isExpand){
                if (rootNode.forkPathList != null) {
                    for (Path path : rootNode.forkPathList) {
                        canvas.drawPath(path, linePaint);
                    }
                }
            }
        }
 
        if (rootNode.getChildren() != null && rootNode.getChildren().size() > 0) {
            for (Node child : rootNode.getChildren()) {
                drawNodeLine(canvas, child);
            }
        }
 
    }
 
    public void setMinSize(int minWidth, int minHeight) {
        this.minWidth = minWidth;
        this.minHeight = minHeight;
    }
 
    public interface OnItemClickListener{
        void onItemClick(View view,HomeRootBean member);
    }
 
}