👉即将学会
不实使用什么框架,就用基础的代码,实现层级导图。
👉背景
今天七夕快乐呀,小芝🙎和小空🙈今天一起吃了汉堡,很好吃哦!
👉实践过程
最近公司的医疗项目需要用到这个,需求是病例之间的状态跳转,医学方面比如急救的时候有一些比较成熟的操作流程和步骤,紧急情况下是可以略过的,所以软件就要模拟出来状态的跳转。而项目展示的状态就像亲属关系图类似。
先看下我们的效果吧
刚开始的时候,小空脑子也是空空的,毫无头绪,在咨询了同事其他端实现的思路后,转为Android的实现技术。
大致思路如下:
- 如何添加这些控件
- 如何位置随机
- 画线和画不封闭的箭头
- 扩展性
有了这些想法,我们就要实际动手操作了:这些仍逃不出自定义的范围:
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背景 //如果需要其他的需求再接着写 } 复制代码
下面是我们的布局文件,1个Button和2个TextView:
<?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> 复制代码
有了这些基础控件之后,就开始考虑不断创建添加进去的问题了,其实不管是位置随机还是固定位置都可以实现,具体看项目的需求了,小空做的项目应为要和其他端保持一致,所以给定了具体的画布大小和位置。
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]); } } } 复制代码
从上段代码可以看出,不管是添加状态还是连线都是靠的基本的addView,然后利用数组初始多个最开始咱们自定义的那个View,坐标的位置就是topMargin和leftMargin的值(相对于屏幕左上角,即给的坐标)。思路确实是挺另类的。
接着就是划线了,当走到这的时候,我们就已经知道了各个自定义View的坐标位置,毕竟靠的是上面的addView,那么画线的起点和终点我们稍加计算也就很明确了。
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); } } 复制代码
画线使用自定义View的canvas,drawPath这些就好了,为了让线条看起来更加的丝滑性感,小空加上了贝塞尔曲线,还有线头(其实只要在起点重点坐标点延长出两个线段就搞定了)
大致的效果出来了;恩 需求解决!若您有相近的需求或解决思路,欢迎在下方留下地址!
另外,既然是自定义的View,那加动画肯定没问题;除了这些,还能更完善:比如箭头的平滑,大控件的各种事件等等,暂时待续.....
作者:芝麻粒儿
链接:https://juejin.cn/post/6996252923030143012
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
👉其他
📢作者:小空和小芝中的小空
📢这位道友请留步☁️,我观你气度不凡,谈吐间隐隐有王者霸气💚,日后定有一番大作为📝!!!旁边有点赞👍收藏🌟今日传你,点了吧,未来你成功☀️,我分文不取,若不成功⚡️,也好回来找我。