效果图
全部正确:
有对有错:
结果展示,纯黑色:
支持图片:
实现思路
仔细分析可以发现,连线题的布局可以分为两部分,一个是左右两列矩形,另一个是他们之间的连线。
每个矩形的宽高都一样,或者等比例,这样利于给他们定位,添加矩形时使用ViewGroup#ddView(View child, LayoutParams params)
方法,我们通过LayoutParams
参数来控制每个矩形的位置。
为了方便添加矩形,这里我们的自定义布局继承自RelativeLayout。
public class LinkLineView extends RelativeLayout {
...
}
接下来说连线,连线我们通过记录他们的起点和终点数据,然后调用View#invalidate
方法,在ViewGgroup#dispatchDraw()
方法里面通过canvas.drawLine()
方法进行绘制。
我们假设线都是从左向右连的,起点
就是左边矩形右边距的中点,终点
就是右边矩形左边距的中点。在添加矩形的时候我们可以知道每个矩形的具体参数,所以所有连线的起点和终点的数据我们是知道的,接着就是如何表示一根线的问题。
在所有连线完成之前,连线是可以取消掉的;在所有连线完成后,我们需要用连线结果跟正确结果进行比对的,所以我们需要针对每次连线定义一个数据结构,具体如下:
public class LinkLineBean {
/**
* 直线的横纵坐标
*/
private float startX;
private float startY;
private float endX;
private float endY;
public LinkLineBean(float startX, float startY, float endX, float endY) {
this.startX = startX;
this.startY = startY;
this.endX = endX;
this.endY = endY;
}
// 省略getter和setter方法
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof LinkLineBean)) {
return false;
}
LinkLineBean that = (LinkLineBean) o;
return (Float.compare(that.startX, startX) == 0 &&
Float.compare(that.startY, startY) == 0 &&
Float.compare(that.endX, endX) == 0 &&
Float.compare(that.endY, endY) == 0)
|| (Float.compare(that.startX, endX) == 0 &&
Float.compare(that.startY, endY) == 0 &&
Float.compare(that.endX, startX) == 0 &&
Float.compare(that.endY, startY) == 0);
}
@Override
public int hashCode() {
return Objects.hash(startX, startY, endX, endY);
}
}
这里省略了一些不必要的代码。
重写equals和hashCode方法是为了比较是否是同一条连线。如果连线A的起点等于连线B的终点,连线A的终点等于连线B的起点,我们就认为他们是同一条连线,这个也符合我们的常识,同一条线从左向右连和从右向左连是一样的。
核心思路说完了,剩下的就是一些细节处理了。
具体代码请看:LinkLineDemo
如果觉得好用请记得star。