每做完一個(gè)需求我們是不是該留下點(diǎn)什么碎赢。??
需求
這次主要是做訂單這塊局义,然后物流的一個(gè)頁(yè)面平時(shí)買(mǎi)東西也會(huì)經(jīng)常見(jiàn)到,這次居然做到了,看著似乎挺簡(jiǎn)單的就斤,做的時(shí)候也花了我有些時(shí)間充边。實(shí)現(xiàn)
-
方案一:最開(kāi)始的時(shí)候想著ListView+item布局應(yīng)該就能實(shí)現(xiàn)庸推,結(jié)果做出來(lái)的效果有點(diǎn)不如人意,因?yàn)槭褂靡韵伦鳛閕tem布局的話(huà)浇冰,要注意贬媒,點(diǎn)大概在一行文字的中間位置,點(diǎn)和線(xiàn)之間有間隙肘习,如果點(diǎn)距離上面的距離很大际乘,那么下一個(gè)item顯示的時(shí)候,同樣會(huì)和上一個(gè)點(diǎn)有很大的間隙漂佩;
item.png 方案二:參考github上的一個(gè)實(shí)現(xiàn):將item添加到LinearLayout里面脖含,在onDraw方法中獲取到第一個(gè)和最后一個(gè)item的位置,從第一個(gè)到最后一個(gè)畫(huà)一條直線(xiàn)仅仆,最后中間分別畫(huà)點(diǎn)器赞,這樣的話(huà)點(diǎn)和線(xiàn)之間沒(méi)有間距。
我參考了該種實(shí)現(xiàn)方案墓拜,記錄了每個(gè)item的起始位置港柜,并且每個(gè)畫(huà)線(xiàn)的開(kāi)始和結(jié)束點(diǎn)的位置(距離點(diǎn)有一定的距離),依次畫(huà)點(diǎn)咳榜,然后畫(huà)線(xiàn)夏醉。
效果實(shí)現(xiàn),問(wèn)題:onDraw方法每次都會(huì)調(diào)用兩次涌韩,而且上下滑動(dòng)的時(shí)候都會(huì)去一直調(diào)用onDraw方法畔柔,沒(méi)找到原因,所以還是先放棄該種方案臣樱。
參考github的鏈接地址:https://github.com/razerdp/UnderLineLinearLayout
參考實(shí)現(xiàn):
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.drawable.BitmapDrawable;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.widget.LinearLayout;
import java.util.ArrayList;
import java.util.List;
public class LogisticsLinearLayout extends LinearLayout {
private Context context;
private int lineDynamicDimen;
private Paint linePaint;
private Paint pointPaint;
// 存儲(chǔ)畫(huà)現(xiàn)的點(diǎn)
private List<Point> points = new ArrayList<>();
private Bitmap mIcon;
private int halfIconWidth;
private int iconHeight;
// 圓的半徑
private int circleRadius;
private int lineMarginLeft;
// 線(xiàn)距離上下點(diǎn)之間的距離
private int lineMarginUPDown;
// 設(shè)置完成的節(jié)點(diǎn)
private int finishCodeCount;
public LogisticsLinearLayout(Context context) {
this(context, null);
}
public LogisticsLinearLayout(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public LogisticsLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
setWillNotDraw(false);
init();
}
private void init() {
setOrientation(VERTICAL);
// 這里是工具類(lèi)靶擦,dp->px
circleRadius = DisplayUtil.dip2px(context, 3);
lineMarginLeft = DisplayUtil.dip2px(context, 20);
lineMarginUPDown = DisplayUtil.dip2px(context, 3);
lineDynamicDimen = DisplayUtil.dip2px(context, 8);
linePaint = new Paint();
linePaint.setAntiAlias(true);
linePaint.setDither(true);
linePaint.setColor(context.getResources().getColor(R.color.gh_cm_line_bg));
linePaint.setStrokeWidth(DisplayUtil.dip2px(context, 1));
linePaint.setStyle(Paint.Style.FILL_AND_STROKE);
pointPaint = new Paint();
pointPaint.setAntiAlias(true);
pointPaint.setDither(true);
pointPaint.setColor(context.getResources().getColor(R.color.m_consult_custom_service_text_gray_deep));
pointPaint.setStyle(Paint.Style.FILL);
BitmapDrawable temp = (BitmapDrawable) context.getResources().getDrawable(R.drawable.m_consult_icon_strict_logistics_point);
if (temp != null) mIcon = temp.getBitmap();
halfIconWidth = mIcon.getWidth() >> 1;
iconHeight = mIcon.getHeight();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int childCount = getChildCount();
points.clear();
drawAllView(canvas);
}
// 肯定只有最后一個(gè)是未完成的腮考,前面應(yīng)該都是已經(jīng)完成的節(jié)點(diǎn)
private void drawAllView(Canvas canvas) {
for (int i = 0; i < getChildCount(); i++) {
// 0, 1, 2 finishCodeCount=2
if (i < finishCodeCount) { // 0,1
drawImageChildViewVertical(i, canvas);
} else {
drawCircleChildViewVertical(i, canvas);
}
}
float[] pts = new float[points.size()*2];
for (int j = 0; j < points.size()*2; j=j+2) {
Point p = points.get(j/2);
pts[j] = p.x;
pts[j+1] = p.y;
}
canvas.drawLines(pts, linePaint);
}
/**
* 畫(huà)圓點(diǎn)view
* @param i
* @param canvas
*/
private void drawCircleChildViewVertical(int i, Canvas canvas) {
if (getChildAt(i) != null) {
//記錄值: getLeft() + lineMarginLeft
int posX = getLeft() + lineMarginLeft;
// y = top + getChildAt(0).getPaddingTop() + lineDynamicDimen(可以理解為距離頂部的動(dòng)態(tài)值);
int posY = getChildAt(i).getTop() + getChildAt(i).getPaddingTop() + lineDynamicDimen;
//畫(huà)一個(gè)圓
canvas.drawCircle(posX, posY, circleRadius, pointPaint);
if (i == 0) {
points.add(new Point(posX, posY+circleRadius+lineMarginUPDown));
} else if (i == getChildCount()-1) {
points.add(new Point(posX, posY-circleRadius-lineMarginUPDown));
} else {
points.add(new Point(posX, posY-circleRadius-lineMarginUPDown));
points.add(new Point(posX, posY + circleRadius + lineMarginUPDown));
}
}
}
/**
* 畫(huà)圖片view
* @param i
* @param canvas
*/
private void drawImageChildViewVertical(int i, Canvas canvas) {
if (getChildAt(i) != null) {
// int halfIconWidth = mIcon.getWidth() >> 1;
// int iconHeight = mIcon.getHeight();
//記錄值: getLeft() + lineMarginLeft
int posX = (getLeft() + lineMarginLeft) - halfIconWidth;
// y = top + getChildAt(0).getPaddingTop() + lineDynamicDimen(可以理解為距離頂部的動(dòng)態(tài)值);
int posY = getChildAt(i).getTop() + getChildAt(i).getPaddingTop() + lineDynamicDimen;
canvas.drawBitmap(mIcon, posX, posY, null);
if (i == 0) {
points.add(new Point(posX+halfIconWidth, posY + iconHeight + lineMarginUPDown));
} else if (i == getChildCount() - 1) {
// i進(jìn)入這個(gè)判斷,說(shuō)明節(jié)點(diǎn)全部都已經(jīng)完成
points.add(new Point(posX+halfIconWidth, posY - lineMarginUPDown));
} else {
points.add(new Point(posX+halfIconWidth, posY - lineMarginUPDown));
points.add(new Point(posX+halfIconWidth, posY + iconHeight + lineMarginUPDown));
}
}
}
public void setNodeFinish(int count) {
finishCodeCount = count;
}
}
- 方案三:就是完全自定義嘍玄捕,但是我不想做的這么麻煩踩蔚,這種方案放棄。
思考最初
回到最初的開(kāi)始枚粘,覺(jué)著應(yīng)該可以做出這種效果馅闽,重新嘗試ListView+item布局,這次換種布局方式馍迄,做出來(lái)的效果還是過(guò)的去福也。??
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:paddingLeft="12dp"
android:paddingRight="12dp">
<!-- 每個(gè)點(diǎn)距離頂部3dp,即可以看起來(lái)在右邊文字的中間攀圈,又可以和線(xiàn)之間有一定距離 -->
<ImageView
android:id="@+id/logistics_point_iv"
android:layout_width="12dip"
android:layout_height="12dip"
android:layout_marginTop="3dip"
android:scaleType="center"
android:src="@drawable/icon_logistics_point" />
<!-- 為了能讓線(xiàn)在點(diǎn)的中間下方位置暴凑,只能固定圖片點(diǎn)的大小量承,算好距離左邊的位置是圖片寬度的一半搬设;
必須要和右邊文字的最底部對(duì)齊撕捍,不然線(xiàn)顯示不出來(lái) -->
<View
android:id="@+id/logistics_line"
android:layout_width="1dp"
android:layout_marginTop="3dip"
android:layout_height="match_parent"
android:layout_marginLeft="6dip"
android:layout_alignBottom="@+id/logistics_info_ll"
android:layout_below="@id/logistics_point_iv"
android:background="#EBECF1" />
<LinearLayout
android:id="@+id/logistics_info_ll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toRightOf="@+id/logistics_point_iv"
android:paddingLeft="10dp"
android:orientation="vertical" >
<TextView
android:id="@+id/logistics_content_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="需求提交成功需求提交成功需求提交成功需求提交成功需求提交成功需求提交成功需求提交"
android:textSize="16sp"
android:textColor="#28354c"/>
<TextView
android:id="@+id/m_consult_item_strict_order_logistics_time_tv"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="8dp"
android:paddingBottom="40dip"
android:text="2015-9-28"
android:textSize="12sp"
android:textColor="#c4c6cf"/>
</LinearLayout>
</RelativeLayout>
效果圖:
看著還行吧泣洞,點(diǎn)到右邊第一行文字的距離稍微有點(diǎn)偏差忧风,但還算過(guò)得去掺冠,實(shí)現(xiàn)起來(lái)也方便。??