Android实现无序树形结构图,类似思维导图和级联分层图(无序,随机位置)

参考文章:

利用递归算法、堆栈打造一个android可擦除思维导图

用SurfaceView实现级联分层图(粗略篇)

效果图打头阵:

这些和亲戚关系图谱,或者思维导图类似,最近公司的医疗项目也用到了这个,记录学习下;

刚开始的时候,也是脑子抽抽,毫无头绪,看完上面2篇文章后,有了大致模仿思路;

大致思路:

1.如何出现这种控件;

2.如何位置随机;

3.画线和画不封闭箭头;

4.扩展性

有了这些想法,就开始动手了

这种控件逃不了自定义的范围:

public class BLzgView extends RelativeLayout {
	private Button blzg_btn;
	private TextView blzg_title_tv, blzg_describe_tv;

	public BLzgView(Context context) {
		this(context,null);
	}

	public BLzgView(Context context, AttributeSet attrs) {
		super(context, attrs);
		LayoutInflater.from(context).inflate(R.layout.view_blzg, this, true);
		blzg_describe_tv=(TextView) findViewById(R.id.blzg_describe_tv);
		blzg_title_tv=(TextView) findViewById(R.id.blzg_title_tv);
		blzg_btn=(Button) findViewById(R.id.blzg_btn);
	}
     public void setTitleText(String tString){
    	 blzg_title_tv.setText(tString);
     } 
     public void setDecribeText(String string){
    	 blzg_describe_tv.setText(string);
     }
     public void setBtnClickListener(OnClickListener onClickListener){
    	 if (onClickListener!=null) {
			blzg_btn.setOnClickListener(onClickListener);
		}
     }
     //更改btn背景
     
     //如果需要其他的需求再接着写
}

对了,在这用Android Studio开发的时候遇到一个意想不到的问题:很意外的问题    这个问题致使布局是下面的写法;

布局文件

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="120dp"
    android:layout_height="70dp"
    android:layout_gravity="center_horizontal">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="70dp"
        android:layout_gravity="center_horizontal"
        android:orientation="vertical">
        <Button
            android:id="@+id/blzg_btn"
            android:layout_width="120dp"
            android:layout_height="70dp"
            android:layout_gravity="center_horizontal"
            android:background="@mipmap/xxk_n" />
    </LinearLayout>

    <TextView
        android:id="@+id/blzg_title_tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="4dp"
        android:gravity="center_horizontal"
        android:maxLines="1"
        android:text="@string/blzg_title"
        android:textColor="#ffffff" />

    <TextView
        android:id="@+id/blzg_describe_tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="24dp"
        android:gravity="center_horizontal"
        android:maxLines="2"
        android:text="内容描述"
        android:textColor="@color/black" />

</merge>

有了这些控件之后,开始考虑位置随机的问题;公司的项目因为给了具体的坐标,所以直接传递坐标即可,在这为实现效果,使用的随机位置

主Activity如下:

public class UnOrderTree extends Activity {
    private DrawGeometryView line_view[] = new DrawGeometryView[30];
    private RelativeLayout.LayoutParams[] layoutParams = new RelativeLayout.LayoutParams[15];
    private RelativeLayout.LayoutParams[] layoutParams1 = new RelativeLayout.LayoutParams[15];
    private BLzgView[] bLzgViews = new BLzgView[15];
    private RelativeLayout insertLayout;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_unordertree);
        insertLayout = (RelativeLayout) findViewById(R.id.layout_zone);
        initData();//初始化数据
    }

    private int start_line_x = 0, start_line_y = 0;
    private int topMargin = 0, leftMargin = 0;

    private void initData() {
        for (int i = 0; i < 6; i++) { // 开始绘制
            topMargin = new Random().nextInt(20) * 30;
            leftMargin = new Random().nextInt(10) * 40;
            initUnOrder(start_line_x, start_line_y, topMargin, leftMargin, i, 0, 0, 2, 1, "");
            start_line_x = leftMargin;
            start_line_y = topMargin;
        }
    }

    private void initUnOrder(int start_x, int start_y, int topMargin, int leftMargin, int i,
                             int line_start_x, int line_start_y, int tree_tier, int isleft, String data) {
        bLzgViews[i] = new BLzgView(this);
        bLzgViews[i].setBtnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                Toast.makeText(UnOrderTree.this, "功能快速开发中,敬请期待", Toast.LENGTH_SHORT).show();
            }

        });

        bLzgViews[i].setTitleText("标题" + i);
        bLzgViews[i].setDecribeText("内容" + i);

        ScaleAnimation animation = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f, Animation.RELATIVE_TO_SELF, 0.5f,
                Animation.RELATIVE_TO_SELF, 0.5f);
        animation.setInterpolator(new BounceInterpolator());
        animation.setStartOffset(100);// 动画秒数。
        animation.setFillAfter(true);
        animation.setDuration(700);
        bLzgViews[i].startAnimation(animation);
        layoutParams[i] = new RelativeLayout.LayoutParams(120, 70); // 大小
        layoutParams[i].topMargin = topMargin;
        layoutParams[i].leftMargin = leftMargin; // 设置的按钮位置
        insertLayout.addView(bLzgViews[i], layoutParams[i]);
        if (i != 0) {   //第一个不用画线(画线方式为:当前的坐标去找上一个坐标,之后连线)
            line_view[i] = new DrawGeometryView(this, start_x + 60, start_y + 70,
                    leftMargin + 40, topMargin, "线条", isleft);
            layoutParams1[i] = new RelativeLayout.LayoutParams(800, 800);
            line_view[i].invalidate();
            layoutParams1[i].topMargin = 0;// line_y-600;//Math.min(line_y+100,button_y+100
            layoutParams1[i].leftMargin = 0;// line_x+300;
            insertLayout.addView(line_view[i], layoutParams1[i]);
        }
    }
}


其实,思路也是另类的,利用数组初始多个自定义的View,坐标位置就是topMargin和leftMargin(相对于屏幕左上角,即给的坐标)

剩下的就是画线了,走到这,其实已经知道了各个大控件的坐标位置,那么画线的起点和终点就很明确了

public class DrawGeometryView extends View {
    private int beginx = 0;
    private int beginy = 0;
    private int stopx = 100;
    private int stopy = 100;

    /**
     * @param context
     * @param attrs
     */
    public DrawGeometryView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * @param context
     */
    public DrawGeometryView(Context context, int beginx, int beginy, int stopx, int stopy, String word, int isleft) {
        super(context);
        this.beginx = beginx;
        this.beginy = beginy;
        this.stopx = stopx;
        this.stopy = stopy;
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint redPaint = new Paint(); // 红色画笔
        redPaint.setAntiAlias(true); // 抗锯齿效果,显得绘图平滑
        redPaint.setColor(Color.BLACK); // 设置画笔颜色
        redPaint.setStrokeWidth(2.0f);// 设置笔触宽度
        redPaint.setStyle(Style.STROKE);// 设置画笔的填充类型(完全填充)
        redPaint.setTextSize(50);// 字体
        Path mPath = new Path();
        mPath.reset();
        // 起点
        mPath.moveTo(beginx, beginy);
        // 贝塞尔曲线
        // mPath.cubicTo(beginx+80, beginy, beginx+80, stopy,stopx-100, stopy);
        mPath.cubicTo(beginx, beginy + 30, stopx, stopy - 50, stopx, stopy);
        // // 画直线
        // mPath.lineTo(stopx, stopy);
        // 画path
        canvas.drawPath(mPath, redPaint);
        //下面是画箭头线的
        Paint left_paint = new Paint();
        Paint right_paint = new Paint();
        Path left_path = new Path();
        Path right_path = new Path();
        left_path.reset();
        right_path.reset();
        left_paint.setAntiAlias(true);
        left_paint.setColor(Color.BLACK);
        right_paint.setAntiAlias(true);
        right_paint.setColor(Color.BLACK);
        left_paint.setStrokeWidth(2.0f);
        right_paint.setStrokeWidth(2.0f);
        left_paint.setStyle(Style.STROKE);
        right_paint.setStyle(Style.STROKE);
        left_path.moveTo(stopx, stopy);
        right_path.moveTo(stopx, stopy);
        left_path.quadTo(stopx - 3, stopy - 3, stopx - 6, stopy - 6);
        right_path.quadTo(stopx + 3, stopy - 3, stopx + 6, stopy - 6);
        canvas.drawPath(left_path, left_paint);
        canvas.drawPath(right_path, right_paint);
    }
}

贝塞尔曲线绘制,略微平滑的引导线,再画2个箭头的边(其实就是花的线段);

既然是自定义的View,那加动画肯定没问题;除了这些,还能更完善:比如箭头的平滑,大控件的各种事件等等,暂时待续.....

大致的效果出来了;恩 需求解决!

若您有相近的需求或解决思路,欢迎在下方留下地址!

附下载链接:CSDN下载链接

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芝麻粒儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值