- 视图属性更改(alpha、translationXY等)的快速失效。
- 我们不想设置任何标志或处理默认失效方法处理的所有情况>
- 相反,我们只想在ViewRootImpl中用适当的dirty rect安排一次遍历。
- 此方法调用ViewGroup中的快速失效方法,这些方法在层次结构中遍历,并根据需要转换dirty rect。
- 如果此视图中未使用显示列表属性,则该方法还处理正常的无效逻辑。
- 该备份方法使用invalidateParent和forceRedraw标志来处理各种属性设置方法中使用的这些情
- @param invalidateParent 如果此视图中未使用显示列表属性,
- 则强制调用invalidateParentCaches()
- @param forceRedraw 如果此视图中未使用显示列表属性,请将视图标记为“已绘制”以强制传播无效
*/
@UnsupportedAppUsage
void invalidateViewProperty(boolean invalidateParent, boolean forceRedraw) {
if (!isHardwareAccelerated()//是否支持硬件加速
|| !mRenderNode.hasDisplayList()//是否有需要绘制的缓冲数据
|| (mPrivateFlags & PFLAG_DRAW_ANIMATION) != 0) {//view是否正在绘制
if (invalidateParent) {//是否刷新父控件
invalidateParentCaches();清楚parent view的缓存,不调用父控件的invalidate方法
}
if (forceRedraw) {
mPrivateFlags |= PFLAG_DRAWN; // force another invalidation with the new orientation
}
invalidate(false);//invalidate(boolean invalidateCache) 重绘(是否清除绘图缓存)
} else {
damageInParent();//告诉父视图破坏此View的边界。
}
}
-
Display List 是一个缓存绘制命令的 Buffer,Display List 的本质是一个缓冲区,它里面记录了即将要执行的绘制命令序列。
-
Display List 是视图的基本绘制元素,包含元素原始属性(位置、尺寸、角度、透明度等),对应 Canvas 的 drawXxx()方法。
-
视图信息传递流程:Canvas(Java API) —> OpenGL(C/C++ Lib) —> 驱动程序 —> GPU
c. getY()和getRawY()
- getRawX()、getRawY()返回的是触摸点相对于屏幕的位置,
- getX()、getY()返回的则是触摸点相对于View的位置。
3. 思路
- 弯路1: 想着设置layoutparams.marginTop来改变位置,但是视图刷新效果不行
- 弯路2: 使用ValueAnimation来修改translateY,但发现有deraution。
- 瞎猫碰到死耗子: 直接使用setTranslateY方法,改变view的位置,在down的时候记录按下的点位,move的时候判断是否移除位置超过上限和下限,up的时候判断手势方向,并自动setTranslateY到指定的下一个位置。
4. 源码
/**
- @authoer create by markfrain
- @github https://github.com/furuiCQ
- 高怀见物理 和气得天真
- 时间: 5/8/21
- 描述: BaiduRecyclView
*/
public class BaiduRecycleView extends RecyclerView {
float lastY;
float translateY;
float lastDiff = 0f;
float minVerticalY = 20;
int topTranslateY = 10, centerTranslateY = 300, bottomTranslateY = 540;
public BaiduRecycleView(@NonNull Context context) {
super(context);
init();
}
public BaiduRecycleView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public BaiduRecycleView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
translateY = DpUtils.dp2px(getContext(), centerTranslateY);
}
@Override
public boolean onTouchEvent(MotionEvent e) {
switch (e.getAction()) {
case MotionEvent.ACTION_DOWN:
lastY = e.getRawY();
return true;
case MotionEvent.ACTION_UP:
float rawY = lastY - e.getRawY();
if (translateY < DpUtils.dp2px(getContext(), centerTranslateY)) {
translateY = DpUtils.dp2px(getContext(), rawY > 0 ? topTranslateY : centerTranslateY);
setTranslationY(translateY);
} else if (translateY < DpUtils.dp2px(getContext(), bottomTranslateY)) {
translat
eY = DpUtils.dp2px(getContext(), rawY > 0 ? centerTranslateY : bottomTranslateY);
setTranslationY(translateY);
}
return true;
case MotionEvent.ACTION_MOVE:
rawY = lastY - e.getRawY();
float distance = lastDiff == 0f ? lastDiff : rawY - lastDiff;
lastDiff = rawY;
if (rawY > minVerticalY || rawY < -minVerticalY) {
if (translateY - distance < DpUtils.dp2px(getContext(), topTranslateY)) {
translateY = DpUtils.dp2px(getContext(), topTranslateY);
setTranslationY(DpUtils.dp2px(getContext(), topTranslateY));
} else if (translateY - distance > DpUtils.dp2px(getContext(), bottomTranslateY)) {
translateY = DpUtils.dp2px(getContext(), bottomTranslateY);
setTranslationY(DpUtils.dp2px(getContext(), bottomTranslateY));
} else {
translateY -= distance;
setTranslationY(translateY);
}
}
return false;
}
return super.onTouchEvent(e);
}
} else {
translateY -= distance;
setTranslationY(translateY);
}
}
return false;
}
return super.onTouchEvent(e);
}