美文网首页
记物流节点的实现

记物流节点的实现

作者: 倩shrimp | 来源:发表于2017-08-01 14:30 被阅读18次

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

    需求

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

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

    相关文章

      网友评论

          本文标题:记物流节点的实现

          本文链接:https://www.haomeiwen.com/subject/cwcjlxtx.html