Android自定义时间线控件

效果图

时间线控件

初步思路

自定义控件是必须的,看效果首先想到的就是继承LinearLayout
View的排布,LinearLayout已经帮我们搞定了,我们需要做的就是把左边的时间线和状态圆点给画出来。
至于绘画的状态又有两种,一种是普通状态,一种是高亮状态。这时候我们可以提供当前View的位置信息,抽象出接口,把状态的选择权让给用户。
时间点:通过对应的View的getY() + getHeight()/2就可以获取对应的时间点位置。
时间线:我们只需要记录第一个View和最后一个View对应的时间点位置就可以画出来了

小细节

绘图的过程中有许多细节需要去注意

  • 自定义ViewGroup控件必须提供背景色,否则不会调用onDraw()方法
  • 画点跟画线的顺序必须是先画线,再画点,否则点上面就会被线给遮盖部分。

代码实现

TimeLineView.java

package demo.august1996.top.timelineviewdemo.widget;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
import android.widget.LinearLayout;

/**
 * Created by August on 16/8/20.
 */
public class TimeLineView extends LinearLayout {

    //高亮图片
    private Bitmap mIcon;

    //时间线左右边距
    private int leftAndRightMargin = dp2px(30);

    //第一个点的坐标
    private int firstX;
    private int firstY;


    //最后一个点的坐标
    private int lastX;
    private int lastY;

    //时间线画笔、颜色、粗细
    private Paint linePaint;
    private int lineColor = Color.parseColor("#ff4ed6b4");
    private int lineStoke = dp2px(2);

    //时间点画笔
    private Paint pointPaint;
    private int pointColor = Color.parseColor("#ff4ed6b4");
    private int pointRadius = dp2px(5);


    //提供当前位置是否为高亮状态
    private HeightLineProvider mHeightLineProvider;

    public interface HeightLineProvider {
        boolean isHeightLine(int position);
    }

    public TimeLineView(Context context) {
        this(context, null);

    }

    public TimeLineView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public TimeLineView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        prePare();
    }

    /**
     * 初始化
     */
    private void prePare() {
        linePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        linePaint.setColor(lineColor);
        linePaint.setStrokeWidth(lineStoke);
        linePaint.setStyle(Paint.Style.FILL);


        pointPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        pointPaint.setColor(pointColor);
        pointPaint.setDither(true);
        pointPaint.setStyle(Paint.Style.FILL);
        setOrientation(VERTICAL);
    }


    /**
     * 设置供用户选择是否高亮的接口
     *
     * @param provider
     */
    public void setHeightLineProvider(HeightLineProvider provider) {
        this.mHeightLineProvider = provider;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawTimeLine(canvas);
    }

    /**
     * 绘画时间线
     *
     * @param canvas
     */
    private void drawTimeLine(Canvas canvas) {
        //没有子View,不用绘画
        if (getChildCount() == 0)
            return;

        //计算起点和终点位置,并且画出所有点
        countFirstPoint();
        countLastPoint();
        drawJoinLine(canvas);
        drawPoint(canvas);
    }

    /**
     * 计算起点位置
     */
    private void countFirstPoint() {
        firstX = leftAndRightMargin;
        View view = getChildAt(0);
        firstY = (int) (view.getY() + view.getHeight() / 2);
    }

    /**
     * 计算终点位置
     */
    private void countLastPoint() {
        lastX = leftAndRightMargin;
        View lastView = getChildAt(getChildCount() - 1);
        lastY = (int) (lastView.getY() + lastView.getHeight() / 2);
    }

    /**
     * 画线
     * @param canvas
     */
    private void drawJoinLine(Canvas canvas) {
        countLastPoint();
        canvas.drawLine(firstX, firstY, lastX, lastY, linePaint);
    }

    /**
     * 画出点
     * @param canvas
     */
    private void drawPoint(Canvas canvas) {

        for (int i = 0; i < getChildCount(); i++) {
            int x = leftAndRightMargin;
            View view = getChildAt(i);
            int y = (int) (view.getY() + view.getHeight() / 2);
            /**
             * 如果用户设置了选择状态的权利并且返回真并且设置了高亮图片,则画出高亮状态,否则画出正常状态
             */
            if (mHeightLineProvider != null && mHeightLineProvider.isHeightLine(i) && mIcon != null) {
                drawHeightLine(canvas, x, y);
            } else {
                drawNorPoint(canvas, x, y);
            }
        }
    }


    /**
     * 画正常点
     * @param canvas
     * @param x
     * @param y
     */
    private void drawNorPoint(Canvas canvas, int x, int y) {
        canvas.drawCircle(x, y, pointRadius, pointPaint);
    }

    /**
     * 画出高亮点
     * @param canvas
     * @param x
     * @param y
     */
    private void drawHeightLine(Canvas canvas, int x, int y) {
        canvas.drawBitmap(mIcon, x - mIcon.getWidth() / 2, y - mIcon.getHeight() / 2, null);
    }

    /**
     * dp转px
     * @param dp
     * @return
     */
    private int dp2px(int dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getContext().getResources().getDisplayMetrics());
    }

    /**
     * 设置高亮点的图片
     * @param bitmap
     */
    public void setHeightBitmap(Bitmap bitmap) {
        this.mIcon = bitmap;
    }
}

item_test.xml




    

    

    


activity_main.xml




    

        

MainActivity.java

package demo.august1996.top.timelineviewdemo;

import android.graphics.drawable.BitmapDrawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;

import java.text.SimpleDateFormat;
import java.util.Date;

import demo.august1996.top.timelineviewdemo.widget.TimeLineView;

public class MainActivity extends AppCompatActivity implements TimeLineView.HeightLineProvider {

    @Override
    public boolean isHeightLine(int position) {
        if (position % 4 == 0) {
            return true;
        }
        return false;
    }

    private TimeLineView tlv;
    private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tlv = (TimeLineView) findViewById(R.id.tlv);
        tlv.setHeightLineProvider(this);
        BitmapDrawable bitmapDrawable = (BitmapDrawable) getResources().getDrawable(R.drawable.ic_ok);
        tlv.setHeightBitmap(bitmapDrawable.getBitmap());

    }

    private void addItem() {
        View v = LayoutInflater.from(this).inflate(R.layout.item_test, tlv, false);
        ((TextView) v.findViewById(R.id.tx_action)).setText(tlv.getChildCount() + "探访了你");
        ((TextView) v.findViewById(R.id.tx_action_time)).setText(sdf.format(new Date()));
        ((TextView) v.findViewById(R.id.tx_action_status)).setText("查看");
        tlv.addView(v);
    }

    public void addView(View v) {
        addItem();
    }

    public void removeView(View v) {
        if (tlv.getChildCount() != 0) {
            tlv.removeViewAt(tlv.getChildCount() - 1);
        }
    }
}

源码

Github源码

你可能感兴趣的:(Android自定义时间线控件)