本章节不再介绍详细的某种Chart怎么制作,RecyclerChart系列除了第一章节的概括性的介绍外,其它基本上每章节介绍一种Chart的制作逻辑,详细的完成办法也比较固定,基本上只需要完成对应的Render,将Chart的制作逻辑完成即可,不同的Chart的制作逻辑会由于chart 的办法不同而不同的制作逻辑常见的Barchart、LineChart、BezierChart等,还有一些特制的一些Chart的制作;其间一些Chart触及一些鸿沟以及制作细节问题的处理,是这些图表的难点地点。

之上的这些章节介绍的内容,笔者暂且给它们定性为静态的图表制作,便是RecyclerView滑动停下来时展现的用户眼前的数据展现,Adapter其间的一段visibleCount对应的详细的item, 借用ItemDecoration制作每个Chart在每个Item的内容展现。本章节将讲述一些RecyclerChart中笔者归结为动态特点,比如高亮选中Item时相似Top Poupwindow的窗口显现展现的值;左右滑动无限加载RecyclerChart的数据;滑动过程中松手后展现单位时间内(天、周、月)等的数据时,Chart回弹作用等。

高亮选中

选平分单击选中、长按选中,这个特点设置在Entry 中,所有Chart的数据Entry都extends Entry.

```
public class Entry extends BaseEntry implements Parcelable {
  public static final int TYPE_UNSELECTED = 0;//没有选中
  public static final int TYPE_SINGLE_TAP_UP_SELECTED = 1;//单击选中
  public static final int TYPE_LONG_PRESS_SELECTED = 2;//长按选中
  public int isSelected = TYPE_UNSELECTED;
  public boolean isSelected() {
    return isSelected == TYPE_SINGLE_TAP_UP_SELECTED || isSelected == TYPE_LONG_PRESS_SELECTED;
   }
   ......
}
```

要处理Recyclerview中每个Item的onClick, onLongClick 事情, 首要需要让RecyclerView addOnItemTouchListener OnItemTouchListener接口, 笔者这儿界说了一个类RecyclerItemGestureListener 完成了OnItemTouchListener 接口。

RecyclerChart动态属性(一)

OnItemTouchListener 中本来包含三个办法,最原始的能够自己完成它的onTouchEvent 办法完成点击、长按作用。

RecyclerChart动态属性(一)

笔者这儿经过GestureDetector来代替完成,这样就只需要将onClick 跟 onLongClick时的事务逻辑完成在GestureDetector 对应的办法里,GestureDetector怎么接收 OnItemTouchListener的事情呢?首要RecyclerItemGestureListener implements RecyclerView.OnItemTouchListener, 然后在 RecyclerItemGestureListener 的构造办法里create GestureDetector 实例, 在onInterceptTouchEvent办法里接收拦截即可,不再需要完成 其它两办法。

RecyclerChart动态属性(一)

onInterceptTouchEvent的完成,找到当时Touch到的childView, mGestureDetector.onTouchEvent(e) 为true时作为其间一个条件作为返回:

@Override
public boolean onInterceptTouchEvent(@NonNull RecyclerView view, @NonNull MotionEvent e) {
 View childView = view.findChildViewUnder(e.getX(), e.getY());
 if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
  mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
  return true;
  }
 return false;
}

接下来咱们看怎么处理GestureDetector的完成逻辑,GestureDetector本来的构造函数如下:

public GestureDetector(@UiContext Context context, OnGestureListener listener) {
   this(context, listener, null);
}

其间参数二 OnGestureListener 是一个需要完成接口的变量

public interface OnGestureListener {
 
 boolean onDown(MotionEvent e);
​
 void onShowPress(MotionEvent e);
​
 boolean onSingleTapUp(MotionEvent e);
​
 boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);
​
 void onLongPress(MotionEvent e);
​
 boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);
}

这儿只需要完成 onSingleTapUp, onLongPress 两个办法,所以笔者这儿选择传入 OnGestureListener 的一个Child class SimpleOnGestureListener的 instance作为参数, SimpleOnGestureListener 是 GestureDetector内部的一个 static class, 包含了很多的Gesture相关的办法,这儿选着完成 onSingleTapUp, onLongPress两个办法即可。

上面的衬托完毕后,进入到正题,处理onSingleTapUp, onLongPress 下选中Item Entry的逻辑。

onSingleTapUp的事务逻辑如下,看当时是否selectBarEntry为null, 不为null的时候,点击的是否正好是 selectBarEntry等状况的考虑。

RecyclerChart动态属性(一)

最终将 当时选中的BarEntry 经过 自界说的一个Listener(后续会介绍) 将其传递给上层的详细事务层。

onLongPress的事务逻辑,处理选中跟非选中的逻辑跟 onSingleTapUp大致相同,相同将选中的BarEntry 经过 自界说的一个Listener往上层传。

RecyclerChart动态属性(一)

在 onLongPress 里这儿有个小 trick, 设定了RecyclerItemGestureListener的一个filed 特点 isLongPressing 为true. 以及设定 SpeedRatioLayoutManager 下的 ratioSpeed 的值为0. 这儿跟后续处理长按状态下,RecyclerView 无法滑动,只能拖动显现高亮Item的Case(下面会介绍)。

以上是正常状况下点击、长按对选中高亮的处理,还有一些鸿沟需要处理的,鸿沟1:当Recyclerview 回到快速左右滑动时,需要对本来的selectBarEntry 进行开释。这儿需要RecyclerView 完成 OnScrollListener,OnScrollListener的增加在 RecyclerItemGestureListener 的构造办法里增加的。

RecyclerChart动态属性(一)

鸿沟处理2: 当RecyclerView的滑动在MotionEvent.ACTION_MOVE 的状况下也需要对 selectBarEntry的处理做一个弥补,笔者这儿界说了一个interface 用来处理在 RecyclerView层面的事情,BaseChartRecyclerView 作为所有ChartRecyclerView的基类。

RecyclerChart动态属性(一)

相同在RecyclerItemGestureListener 的construct 办法里增加 OnChartTouchListener 接口。在onChartGestureEnd 对 SpeedRatioLayoutManager 下的 ratioSpeed 的值做一个康复操作(详细作用,下个小节会介绍。)

@Override
public void onChartGestureEnd(MotionEvent e) {
 Log.d("OnItemTouch", " onChartGestureEnd: " + System.currentTimeMillis()/1000);
 isLongPressing = false;
 if (null != layoutManager) {//操控RecyclerView的滑动
  layoutManager.resetRatioSpeed();
  }
}

然后便是onChartGestureMovingOn 即 RecyclerView在 onTouchEvent中的MotionEvent.ACTION_MOVE状况下的一个处理:

RecyclerChart动态属性(一)

高亮选中,这儿是isLongPressing 状况下对selectBarEntry 的处理,并将选中的Entry经过 Listener传出。否则就置空 selectBarEntry, 撤销选中 mListener.onItemSelected(null, -1);

整个以上的逻辑便是对 selectBarEntry 的设定,然后便是调用 mAdapter.notifyItemChanged(position, false). 然后便是触发RecyclerView的重绘,整个逻辑就到之前的Render 的 drawHighLight 办法了。

//制作选中时 highLight 标线及浮框。
public <E extends BaseYAxis> void drawHighLight(Canvas canvas, @NonNull RecyclerView parent, E yAxis) {
 if (mBarChartAttrs.enableValueMark) {
  int childCount = parent.getChildCount();
  View child;
  for (int i = 0; i < childCount; i++) {
   child = parent.getChildAt(i);
   T entry = (T) child.getTag();
   RectF rectF = ChartComputeUtil.getBarChartRectF(child, parent, yAxis, mBarChartAttrs, entry);
   float width = child.getWidth();
   float childCenter = child.getLeft() + width / 2;
   String valueStr = mHighLightValueFormatter.getBarLabel(entry);
   if (entry.isSelected() && !TextUtils.isEmpty(valueStr)) {
    int chartColor = getChartColor(entry);
    float rectHeight = drawHighLightValue(canvas, valueStr, childCenter, parent, chartColor);
    float[] points = new float[]{childCenter, rectF.top, childCenter, rectHeight};
    drawHighLightLine(canvas, points, chartColor);
    }
   }
  }
}

以上过程中说到的将selectBarEntry 经过Listener往上层事务传出,这儿在RecyclerItemGestureListener 界说了一个 接口OnItemGestureListener:

public interface OnItemGestureListener {
 
 void onItemClick(View view, int position);
​
 void onLongItemClick(View view, int position);
​
 void onItemSelected(BarEntry barEntry, int position);
​
 void onScrollStateChanged(RecyclerView recyclerView, int newState);
​
 void onScrolled(RecyclerView recyclerView, int dx, int dy);
}

然后防止直接完成接口,中间完成一个类 SimpleItemGestureListener, 作为 RecyclerItemGestureListener的参数传入。

以上逻辑中在LongPress 设定SpeedRatioLayoutManager 下的 ratioSpeed 为0, 以及在 onChartGestureEnd (RecyclerView的MotionEvent.ACTION_UP 以及MotionEvent.ACTION_CANCEL 事情下)对 ratioSpeed的康复, default value 经过 Attribute传入

public void resetRatioSpeed(){
  this.ratioSpeed = mAttrs.ratioSpeed;
}
​
attrs.ratioSpeed = ta.getFloat(R.styleable.SleepChartRecyclerView_layoutManagerOrientation, 1f);

这儿 SpeedRatioLayoutManager 继承自 LinearLayoutManager, ratioSpeed能够用来操控 RecyclerView的滑动的Speed, 当ratioSpeed 为1f的时候默许的滑动,当为0的时候RecyclerView滑不动。

RecyclerChart动态属性(一)

这样就处理了当处于长按选中时,滑动 跟Recyclerview 滑动抵触的问题处理,跟咱们惯例的处理滑动抵触不太相同,也没有用到两层View的覆盖状况下的抵触处理手段,却又巧妙地完成了功用需求,相似股票软件的那种长按及滑动作用。

鉴于本文的篇幅过长,不再介绍其它动态特点功用了。总结一下,高亮选中功用,这儿首要触及到 四个Listener的完成,首要是 完成 RecyclerView.OnItemTouchListener 的 RecyclerItemGestureListener; 然后是 BaseChartRecyclerView 中的 OnChartTouchListener, 功用时将onTouchEvent中的MotionEvent事情向上露出;第三个是 在 RecyclerItemGestureListener 构造办法内 给 Recyclerview增加的OnScrollListener 匿名内部完成Instance,首要是处理 selectedEntry 快速滑动的开释,并将onScrollStateChanged 接口经过第四个接口向上露出;第四个便是OnItemGestureListener 自界说接口,以及它的模板完成类SimpleItemGestureListener, 首要功用给上层事务完成例如左右滑加载更多的功用。 附上一张RecyclerLineChart 点击选中、LongPress状况下高亮选中,以及滑动时选中被开释的 gif动图。

RecyclerChart动态属性(一)

下一篇介绍上面说到的左右滑无限加载数据以及Chart图表动态回弹的作用。