简单时间轴布局

在进行时间历程显示的时候我们会用到基于listview显示的时间轴布局,效果如下:


现在来说下实现步骤:

首先这个布局我们可以发现其实是一个listview,在listview的左边是一个显示连接起来的时间轴,右边用来显示内容,下面我们来看看怎么实现这个时间轴:
这个自定义的View如下:
public class TimeListView extends View {
    private int mMakeSize,mLineSize;
    private Drawable mStartLine;
    private Drawable mEndLine;
    private Drawable mMaker;
    private Rect bounds;

    private void init(AttributeSet attrs){
        //获取控件的属性集合
        TypedArray array=getContext().obtainStyledAttributes(attrs, R.styleable.TimeListView);
        //中心圆大小
        mMakeSize=array.getDimensionPixelSize(R.styleable.TimeListView_circle,10);
        //线段大小
        mLineSize=array.getDimensionPixelSize(R.styleable.TimeListView_lineSize,10);
        //顶部线条
        mStartLine=array.getDrawable(R.styleable.TimeListView_startLine);
        //底部线条
        mEndLine=array.getDrawable(R.styleable.TimeListView_endLine);
        //中心圆
        mMaker=array.getDrawable(R.styleable.TimeListView_maker);
        array.recycle();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //获取中心圆以及距离左右的大小和
        int w=mMakeSize+getPaddingLeft()+getPaddingRight();
        int h=mMakeSize+getPaddingTop()+getPaddingBottom();
        //将这个值与测量的控件大小进行比较得出较小的那个值从而确定具体控件的大小
        int widthsize=resolveSizeAndState(w,widthMeasureSpec,0);
        int heightsize=resolveSizeAndState(h,heightMeasureSpec,0);
        //将这个值设置给控件大小
        setMeasuredDimension(widthsize,heightsize);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //获取左右上下的Padding值
        int pLeft=getPaddingLeft();
        int pRight=getPaddingRight();
        int pTop=getPaddingTop();
        int pBottom=getPaddingBottom();
        //获取控件宽高
        int width=getWidth();
        int height=getHeight();
        //中心圆圈的矩形定位
        int cWidth=width-pLeft-pRight;
        int cHeight=height-pTop-pBottom;
        if(mMaker!=null){
            int makesize=Math.min(mMakeSize,Math.min(cWidth,cHeight));
            mMaker.setBounds(pLeft,pTop,pLeft+makesize,pTop+makesize);
            bounds = mMaker.getBounds();
        }else {
            bounds=new Rect(pLeft,pTop,pLeft+cWidth,pTop+cHeight);
        }
        int lineleft=bounds.centerX()-mLineSize>>1;
        if(mStartLine!=null){
            mStartLine.setBounds(pLeft+lineleft,0,pLeft+lineleft+mLineSize,bounds.top);
        }
        if(mEndLine!=null){
            mEndLine.setBounds(pLeft+lineleft,bounds.bottom,pLeft+lineleft+mLineSize,height);
        }


    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (mStartLine!=null){
            mStartLine.draw(canvas);
        }
        if(mEndLine!=null){
            mEndLine.draw(canvas);
        }
        if(mMaker!=null){
            mMaker.draw(canvas);
        }
        super.onDraw(canvas);
    }

    public Drawable getmMaker() {
        return mMaker;
    }

    public void setmMaker(Drawable mMaker) {
        this.mMaker = mMaker;
    }

    public Drawable getmEndLine() {
        return mEndLine;
    }

    public void setmEndLine(Drawable mEndLine) {
        this.mEndLine = mEndLine;
    }

    public Drawable getmStartLine() {
        return mStartLine;
    }

    public void setmStartLine(Drawable mStartLine) {
        this.mStartLine = mStartLine;
    }

    public int getmLineSize() {
        return mLineSize;
    }

    public void setmLineSize(int mLineSize) {
        this.mLineSize = mLineSize;
    }

    public int getmMakeSize() {
        return mMakeSize;
    }

    public void setmMakeSize(int mMakeSize) {
        this.mMakeSize = mMakeSize;
    }
    public TimeListView(Context context) {
        super(context);

    }

    public TimeListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs);
    }

    public TimeListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs);
    }
}
属性集合attrs为:
    <declare-styleable name="TimeListView">
        <attr name="lineSize" format="dimension"/>
        <attr name="circle" format="dimension"/>
        <attr name="startLine" format="color|reference"/>
        <attr name="endLine" format="color|reference"/>
        <attr name="maker" format="color|reference"/>
    </declare-styleable>

下面我们的使用:
activity的布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycle_timelist"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>

activity如下:
public class TimeListViewActivity extends Activity {

    private RecyclerView ry;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_timelist);
        ry = (RecyclerView)findViewById(R.id.recycle_timelist);
        LinearLayoutManager layoutManager=new LinearLayoutManager(this);
        ry.setLayoutManager(layoutManager);
        List<String> list=new ArrayList<>();
        list.add("20170108");
        list.add("20170109");
        list.add("20170110");
        list.add("20170111");
        list.add("20170112");
        list.add("20170113");
        ry.setAdapter(new TimeListAdapter(this,list));
    }
}
recycleview的adapter的代码如下:
public class TimeListAdapter extends RecyclerView.Adapter<MyViewHolder> {
    private Context context;
    private List<String> datas;
    private LayoutInflater inflater;
    public TimeListAdapter(Context context, List<String> datas) {
        this.context=context;
        this.datas=datas;
        inflater=LayoutInflater.from(context);
    }

    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view=inflater.inflate(R.layout.item_recycle_timelist,parent,false);
        MyViewHolder myViewHolder=new MyViewHolder(view,inflater.getContext(),viewType);
        return myViewHolder;
    }

    @Override
    public int getItemViewType(int position) {
        //为Item设置type
        int size=datas.size()-1;
        if(size==0){
            return ItemType.NO;
        }else if(position==0){
            return ItemType.TOP;
        }else if(position==size){
            return ItemType.BOTTOM;
        }else {
            return ItemType.NORMAL;
        }
    }

    @Override
    public void onBindViewHolder(MyViewHolder holder, int position) {
        holder.tv.setText(datas.get(position));
    }

    @Override
    public int getItemCount() {
        return datas.size();
    }
}
class MyViewHolder extends RecyclerView.ViewHolder{
    TextView tv;
    public MyViewHolder(View itemView,Context context,int type) {
        super(itemView);
        tv= (TextView) itemView.findViewById(R.id.tv);
        TimeListView timeListView= (TimeListView) itemView.findViewById(R.id.tlv);
        if (type==ItemType.NO){
            timeListView.setmStartLine(null);
            timeListView.setmEndLine(null);
        }else if(type==ItemType.TOP){
            timeListView.setmStartLine(null);
        }else if(type==ItemType.BOTTOM){
            timeListView.setmEndLine(null);
        }
    }
}
值得一提的是RecycleView中的方法:
public int getItemViewType(int position) 
这个方法返回一个int类型的值可以改item的type,这个type值就是
    @Override
    public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view=inflater.inflate(R.layout.item_recycle_timelist,parent,false);
        MyViewHolder myViewHolder=new MyViewHolder(view,inflater.getContext(),viewType);
        return myViewHolder;
    }
里面的viewType这个值,然后根据这个值来设置第一条和最后一条item的属性,从而让第一条的上边部分线条和最后的条目的下边部分线条取消掉从而形成一个完整的时间轴布局.

布局Item的type如下:
public class ItemType {
    public static int NO=0;
    public static int TOP=1;
    public static int NORMAL=2;
    public static int BOTTOM=3;
}
最后再Recycleview里面的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="60dp"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <com.zxf.androidcustomlayout.CanvasAndPaint.TimeListDemo.TimeListView
        android:id="@+id/tlv"
        android:layout_width="60dp"
        android:layout_height="60dp"
        android:paddingTop="20dp"
        android:paddingLeft="10dp"
        android:paddingBottom="20dp"
        android:layout_centerVertical="true"
        app:startLine="@color/colorAccent"
        app:endLine="@color/colorPrimary"
        app:maker="@mipmap/x5"
        app:circle="20dp"
        app:lineSize="2dp"
        />
    <TextView
        android:id="@+id/tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="这个是时间轴数据"
        android:layout_marginLeft="100dp"
        android:layout_marginTop="20dp"/>
</RelativeLayout>

点击查看源码



原文地址:https://www.cnblogs.com/vegetate/p/9997262.html