效果圖
全部正確:
有對有錯:
結果展示,純黑色:
支持圖片:
實現思路
仔細分析可以發現,連線題的佈局可以分爲兩部分,一個是左右兩列矩形,另一個是他們之間的連線。
每個矩形的寬高都一樣,或者等比例,這樣利於給他們定位,添加矩形時使用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。