今年上海的七月和八月在小编看来是有特殊纪念意义的夏季。哈哈,感觉总是那么美好,虽然今年确实很热,但是好在正真炎热的夏季已经过去了。行了吧,寒暄的话,小编不说了;那现在开始,小编直奔主题吧:自定义时间轴的实现;首先,根据公司产品的设计需要写一个上有刻度和时间显示的时间轴,下有具体的日期可选与否的进度条,那首先来看看小编实现的效果吧。
以上便是小编实现后的效果。小编为了方便显示该控件的功能,特意截图了三张不同时间轴和三张不同显示可选和不可选的进度条的时间段。
实现思路:1.根据接口传来的数据来选择性的绘制需要显示的刻度时刻的刻度尺。2.根据接口传来的数据来显示绘制可选与不可选的进度条。
小编觉得一般情况下,兄弟们看到这种需求一般都是这样写的,但是还是有个我们不得不考虑的问题。那就是后台接口会传给我们什么样的数据结构呢。这个是需要考虑的问题。这个也是本次自定义控件的最难点所在,他的数据结构是什么样的呢?
也许各位兄弟们可能有更好的办法或更可行的数据结构的排布,但是在这里小编先介绍下我们的数据结构的排布。先展示下小编我们请求接口返回的数据结构吧。
首先,小编简单介绍下我们自己的数据结构的字段,其中的time字段对应的分别是整个时间轴的最小起始时刻和整个时间轴的最大结束时刻。对于每个刻度的间隔时间,我们这边是根据后台数据cutTimePoint的决定的,最后剩下的dayArray便是选中的时间段。其次,我们还要对这些数据字段进行处理展示。那么问题来了,对于刻度尺的时间点,和刻度尺的绘制怎么实现呢?
这里小编先说下我的实现过程吧
1.根据时间轴的最小时刻,最大时刻和刻度间隔时间得到可显示的时间点的集合,代码如下:
```
/**
* 刻度上显示的时间数值 单位:小时
*
*@param startTime 最小时刻点
*@param distanceTime 刻度间隔时间(分钟)
*@return
*/
privateListgetScaleTextList(intstartTime,intdistanceTime){
List mResultList =newArrayList<>();
intintegerCount = mScaleCount /2;// 把最后的一个时间点加上
for(inti =0; i < integerCount +1; i++) {
// 分钟
intresult = startTime +2* distanceTime * i;
// 取小时整数
String hourStr = String.valueOf((result /60));
mResultList.add(hourStr);
}
return mResultList;
}
```
2.根据得到可绘制刻度时间尺的实现手机像素距离,再次得到刻度间隔实际对应的手机像素距离
一般我们会重写onMeasure方法得到实际的间隔,小编得到的方法如下:
this.mScaleMargin = getFloatValue((viewWidth - leftMargin - rightMargin), mScaleCount);
3.开始绘制时间刻度吃的时间轴,废话不多说了,小编直接上代码:
```
/**
* 画刻度
*
*@paramcanvas
*/
privatevoiddrawScale(Canvas canvas){
if(mScaleCount ==0)
return;
for(inti =1; i < mScaleCount +3; i++) {
if(i >=2) {
if(i %2==0) {// 双数大刻度
canvas.drawLine(leftMargin + (i -2) * mScaleMargin, mRectHeight, leftMargin + (i -2) * mScaleMargin, mRectHeight - mScaleMaxHeight, scalePaint);
canvas.drawText(mScaleTextList.get(i /2-1), leftMargin + (i -2) * mScaleMargin, mRectHeight - mScaleMaxHeight -10, scalePaint);
}else{// 单数小刻度
canvas.drawLine(leftMargin + (i -2) * mScaleMargin, mRectHeight, leftMargin + (i -2) * mScaleMargin, mRectHeight - mScaleHeight, scalePaint);
}
}else{// 写时段字样
canvas.drawText(title, titleMargin, mRectHeight - mScaleHeight, textPaint);
}
}
canvas.drawLine(0, mRectHeight, viewWidth, mRectHeight, scalePaint);
// canvas.drawLine(leftMargin,mRectHeight,viewWidth -rightMargin,mRectHeight,progressPaint);
}
```
4.当我们绘制好了刻度尺的显示时间轴,接下来绘制时间可选与不可选择的进度条。
在这里主要有俩步非常重要,第一步,根据接口返回的时间段得到可预约的时间 所占的 实际宽度。实现方法如下:
```
/**
* 可预约的时间 所占的 实际宽度
*
*@parambookTime
*/
private float getTimePointFactViewWidth(BookTime.TimePoint bookTime){
if(bookTime ==null)
return0;
if(distanceLong ==0)
return0;
intstartTime = timeToMinter(bookTime.startTime);
intendTime = timeToMinter(bookTime.endTime);
intdistance = Math.abs(endTime - startTime);
if(distance ==0)
return0;
intfactScaleWidth = viewWidth - leftMargin - rightMargin;// 实际显示刻度的ViewWidth
floatratioToMinter = getFloatValue(factScaleWidth, distanceLong);// 每分钟所占的比例
float bookTimeWidth = distance * ratioToMinter;
return bookTimeWidth;
}
```
第二步,根据接口返回的时间段的起始时刻点得到在进度条中开始绘制的位置,实现方法如下:
```
/**
* 得到开始绘制的位置
*
*@parambookTime
*/
privatefloatgetStartDrawProgressPosition(BookTime.TimePoint bookTime){
if(distanceLong ==0)
return0;
intfactScaleWidth = viewWidth - leftMargin - rightMargin;// 实际显示刻度的ViewWidth
floatratioToMinter = getFloatValue(factScaleWidth, distanceLong);// 每分钟所占的比例
intstartTime = timeToMinter(bookTime.startTime);
if(allStartTime <0)
return0;
if(startTime < allStartTime)
return0;
intdistance = Math.abs((startTime - allStartTime));// 两个启动的时间间距
return(distance * ratioToMinter);
}
```
根据以上两步得到每次绘制时间段的在实际手机上绘制的实际位置和绘制的距离,那么接下来就是需要绘制显示的时间进度条;小编废话不多说了,直接上代码了:
```
/**
* 画预约进度条
*
*@paramcanvas
*/
privatevoiddrawBookProgress(Canvas canvas){
if(ListUtils.isEmpty(bookTimeList))
return;
linePaint.setStrokeWidth(stringHeight *2);
progressPaint.setStrokeWidth(stringHeight *2);
inti =1;
for(BookTime bookTime : bookTimeList) {
// 绘制默认进度条
canvas.drawText((i <= defaultDateSize ? bookTime.dateDesc : bookTime.shortDate), titleMargin, mRectHeight + mRectHeight /4* i + stringHeight * (i +1), textPaint);// 写字
canvas.drawLine(leftMargin, mRectHeight + mRectHeight /4* i + stringHeight * i, viewWidth - rightMargin, mRectHeight + mRectHeight /4* i + stringHeight * i, linePaint);// 画进度
// 绘制有色进度条
if(!ListUtils.isEmpty(bookTime.timeVoList)) {
List timeVoList = bookTime.timeVoList;
for(BookTime.TimePoint timePoint : timeVoList) {
floatdrawFactWidth = getTimePointFactViewWidth(timePoint);
floatstartDrawPosition = getStartDrawProgressPosition(timePoint);
floatstartX = leftMargin + startDrawPosition;
canvas.drawLine(startX, mRectHeight + mRectHeight /4* i + stringHeight * i, drawFactWidth + startX, mRectHeight + mRectHeight /4* i + stringHeight * i, progressPaint);// 绘制可预约进度
}
}
i++;
}
}
```
以上是小编实现此控件的实现过程。
感觉以上的实现过程相当还是比较简单的,就是有些思路实现起来比较绕还有就是有些细节处理起来比较挠。其他的处理起来还是相当挺简单的。在本次代码的处理中最难的部分就是对时间段和实际手机像素距离的转化处理。