记物流节点的实现

每做完一个需求我们是不是该留下点什么。😊

需求

这次主要是做订单这块,然后物流的一个页面平时买东西也会经常见到,这次居然做到了,看着似乎挺简单的,做的时候也花了我有些时间。
物流查询.png

实现

  • 方案一:最开始的时候想着ListView+item布局应该就能实现,结果做出来的效果有点不如人意,因为使用以下作为item布局的话,要注意,点大概在一行文字的中间位置点和线之间有间隙,如果点距离上面的距离很大,那么下一个item显示的时候,同样会和上一个点有很大的间隙;

    item.png

  • 方案二:参考github上的一个实现:将item添加到LinearLayout里面,在onDraw方法中获取到第一个和最后一个item的位置,从第一个到最后一个画一条直线,最后中间分别画点,这样的话点和线之间没有间距。
    我参考了该种实现方案,记录了每个item的起始位置,并且每个画线的开始和结束点的位置(距离点有一定的距离),依次画点,然后画线。
    效果实现,问题:onDraw方法每次都会调用两次,而且上下滑动的时候都会去一直调用onDraw方法,没找到原因,所以还是先放弃该种方案。

参考github的链接地址:https://github.com/razerdp/UnderLineLinearLayout

参考实现:

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;

    // 存储画现的点
    private List<Point> points = new ArrayList<>();
    private Bitmap mIcon;
    private int halfIconWidth;
    private int iconHeight;
    // 圆的半径
    private int circleRadius;
    private int lineMarginLeft;
    // 线距离上下点之间的距离
    private int lineMarginUPDown;

    // 设置完成的节点
    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);
        
        // 这里是工具类,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);
    }

    // 肯定只有最后一个是未完成的,前面应该都是已经完成的节点
    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);
    }

    /**
     * 画圆点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(可以理解为距离顶部的动态值);
            int posY = getChildAt(i).getTop() + getChildAt(i).getPaddingTop() + lineDynamicDimen;

            //画一个圆
            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));
            }
        }
    }

    /**
     * 画图片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(可以理解为距离顶部的动态值);
            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进入这个判断,说明节点全部都已经完成
                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;
    }
}
  • 方案三:就是完全自定义喽,但是我不想做的这么麻烦,这种方案放弃。
思考最初

回到最初的开始,觉着应该可以做出这种效果,重新尝试ListView+item布局,这次换种布局方式,做出来的效果还是过的去。😂

布局文件:

<?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">

    <!-- 每个点距离顶部3dp,即可以看起来在右边文字的中间,又可以和线之间有一定距离 -->
    <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" />

    <!-- 为了能让线在点的中间下方位置,只能固定图片点的大小,算好距离左边的位置是图片宽度的一半;
         必须要和右边文字的最底部对齐,不然线显示不出来 -->
    <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>

效果图:

效果图.png

看着还行吧,点到右边第一行文字的距离稍微有点偏差,但还算过得去,实现起来也方便。😊

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,563评论 25 707
  • afinalAfinal是一个android的ioc,orm框架 https://github.com/yangf...
    passiontim阅读 15,078评论 2 44
  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,629评论 1 92
  • 每个人都是由于过往的不完美也可以说是过往的业,才来到这个世间修行的,西方的理论是我们都是带着原罪来到世界上的,东西...
    闾阎良善阅读 322评论 0 0
  • 年少离家多飘零,乡愁此时又更浓。 慈母可知游子意,万千思念付归鸿。
    林夕敬阅读 352评论 5 1