热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

又来一个库,WebView,RecyclerView多布局连贯滑动,Android小技巧

mScrollRange-getMeasuredHeight()-getPaddingTop()-getPaddingBottom();}***返回所有的非GONE子View*p

mScrollRange -= getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
}

/**
* 返回所有的非GONE子View
*/
private List getNonGoneChildren() {
List children &#61; new ArrayList<>();
int count &#61; getChildCount();
for (int i &#61; 0; i < count; i&#43;&#43;) {
View child &#61; getChildAt(i);
if (child.getVisibility() !&#61; GONE) {
children.add(child);
}
}
return children;
}

onMeasured的逻辑很简单&#xff0c;遍历测量子vew即可。

onLayout是把子view从上到下排列&#xff0c;就像一个垂直的LinearLayout一样。getNonGoneChildren()方法过滤掉隐藏的子view&#xff0c;隐藏的子view不参与布局。

上面的mScrollRange变量是布局自身可滑动的范围&#xff0c;它等于所有子view的高度减去布局自身的内容显示高度。在后面&#xff0c;它将用于计算布局的滑动偏移和边距限制。


拦截滑动事件

前面说过ConsecutiveScrollerLayout会拦截它的可滑动的子view的滑动事件&#xff0c;由自己来处理所有的滑动。下面是它拦截事件的实现。

&#64;Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() &#61;&#61; MotionEvent.ACTION_MOVE) {
// 需要拦截事件
if (isIntercept(ev)) {
return true;
}
}
return super.onInterceptTouchEvent(ev);
}

如果是滑动事件(ACTION_MOVE)&#xff0c;判断是否需要拦截事件&#xff0c;拦截则直接返回true&#xff0c;让事件交由ConsecutiveScrollerLayout的onTouchEvent方法处理。判断是否需要拦截的关键是isIntercept(ev)方法。

/**
* 判断是否需要拦截事件
*/
private boolean isIntercept(MotionEvent ev) {
// 根据触摸点获取当前触摸的子view
View target &#61; getTouchTarget((int) ev.getRawX(), (int) ev.getRawY());

if (target !&#61; null) {
// 判断子view是否允许父布局拦截事件
ViewGroup.LayoutParams lp &#61; target.getLayoutParams();
if (lp instanceof LayoutParams) {
if (!((LayoutParams) lp).isConsecutive) {
return false;
}
}

// 判断子view是否可以垂直滑动
if (ScrollUtils.canScrollVertically(target)) {
return true;
}
}

return false;
}

public class ScrollUtils {

static boolean canScrollVertically(View view) {
return canScrollVertically(view, 1) || canScrollVertically(view, -1);
}

static boolean canScrollVertically(View view, int direction) {
return view.canScrollVertically(direction);
}
}

判断是否需要拦截事件&#xff0c;主要是通过判断触摸的子view是否可以垂直滑动&#xff0c;如果可以垂直滑动&#xff0c;就拦截事件&#xff0c;让事件由ConsecutiveScrollerLayout自己处理。如果不是&#xff0c;就不拦截&#xff0c;一般不能滑动的view不会消费滑动事件&#xff0c;所以事件最终会由ConsecutiveScrollerLayout所消费。之所以不直接拦截&#xff0c;是为了能让子view尽可能的获得事件处理和分发给下面的view的机会。

这里有一个isConsecutive的LayoutParams属性&#xff0c;它是ConsecutiveScrollerLayout.LayoutParams的自定义属性&#xff0c;用于表示一个子view是否允许ConsecutiveScrollerLayout拦截它的滑动事件&#xff0c;默认为true。如果把它设置为false&#xff0c;父布局将不会拦截这个子view的事件&#xff0c;而是完全交由子view处理。这使得子view有了自己处理滑动事件的机会和分发事件的主动权。

这对于实现一些需要实现局部区域内滑动的特殊需求十分有用。我在GitHub中提供的demo和使用介绍中对isConsecutive有详细的说明&#xff0c;在这就不做过多介绍了。


滑动处理

把事件拦截后&#xff0c;就要在onTouchEvent方法中处理滑动事件。

&#64;Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
// 记录触摸点
mTouchY &#61; (int) ev.getY();
// 追踪滑动速度
initOrResetVelocityTracker();
mVelocityTracker.addMovement(ev);
break;
case MotionEvent.ACTION_MOVE:
if (mTouchY &#61;&#61; 0) {
mTouchY &#61; (int) ev.getY();
return true;
}
int y &#61; (int) ev.getY();
int dy &#61; y - mTouchY;
mTouchY &#61; y;
// 滑动布局
scrollBy(0, -dy);
// 追踪滑动速度
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(ev);
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
mTouchY &#61; 0;

if (mVelocityTracker !&#61; null) {
// 处理惯性滑动
mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
int yVelocity &#61; (int) mVelocityTracker.getYVelocity();
recycleVelocityTracker();
fling(-yVelocity);
}
break;
}
return true;
}

// 惯性滑动
private void fling(int velocityY) {
if (Math.abs(velocityY) > mMinimumVelocity) {
mScroller.fling(0, mOwnScrollY,
1, velocityY,
0, 0,
Integer.MIN_VALUE, Integer.MAX_VALUE);
invalidate();
}
}

&#64;Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
int curY &#61; mScroller.getCurrY();
// 滑动布局
dispatchScroll(curY);
invalidate();
}
}

onTouchEvent方法的逻辑非常简单&#xff0c;就是根据手指的滑动距离通过view的scrollBy方法滑动布局内容&#xff0c;同时通过VelocityTracker追踪手指的滑动速度&#xff0c;使用Scroller配合computeScroll()方法实现惯性滑动。


滑动距离的分发

在处理惯性滑动是时候&#xff0c;我们调用了dispatchScroll()方法&#xff0c;这个方法是整个ConsecutiveScrollerLayout的核心&#xff0c;它决定了应该由谁来消费这次滑动&#xff0c;应该滑动那个布局。

其实ConsecutiveScrollerLayout的scrollBy()和scrollTo()方法最终都是调用它来处理滑动的分发的。

这里有个mOwnScrollY属性&#xff0c;是用于记录ConsecutiveScrollerLayout的整体滑动距离的&#xff0c;相当于View的mScrollY属性。

dispatchScroll()方法把滑动分成向上和向下两部分处理。让我们先看向上滑动部分的处理。

private void scrollUp(int offset) {
int scrollOffset &#61; 0;  // 消费的滑动记录
int remainder &#61; offset; // 未消费的滑动距离
do {
scrollOffset &#61; 0;
// 是否滑动到底部
if (!isScrollBottom()) {
// 找到当前显示的第一个View
View firstVisibleView &#61; findFirstVisibleView();
if (firstVisibleView !&#61; null) {
awakenScrollBars();
// 获取View滑动到自身底部的偏移量
int bottomOffset &#61; ScrollUtils.getScrollBottomOffset(firstVisibleView);
if (bottomOffset > 0) {
// 如果bottomOffset大于0&#xff0c;表示这个view还没有滑动到自身的底部&#xff0c;那么就由这个view来消费这次的滑动距离。
int childOldScrollY &#61; ScrollUtils.computeVerticalScrollOffset(firstVisibleView);
// 计算需要滑动的距离
scrollOffset &#61; Math.min(remainder, bottomOffset);
// 滑动子view
scrollChild(firstVisibleView, scrollOffset);
// 计算真正的滑动距离
scrollOffset &#61; ScrollUtils.computeVerticalScrollOffset(firstVisibleView) - childOldScrollY;
} else {
// 如果子view已经滑动到自身的底部&#xff0c;就由父布局消费滑动距离&#xff0c;直到把这个子view滑出屏幕
int selfOldScrollY &#61; getScrollY();
// 计算需要滑动的距离
scrollOffset &#61; Math.min(remainder,
firstVisibleView.getBottom() - getPaddingTop() - getScrollY());
// 滑动父布局
scrollSelf(getScrollY() &#43; scrollOffset);
// 计算真正的滑动距离
scrollOffset &#61; getScrollY() - selfOldScrollY;
}
// 计算消费的滑动距离&#xff0c;如果还没有消费完&#xff0c;就继续循环消费。
mOwnScrollY &#43;&#61; scrollOffset;
remainder &#61; remainder - scrollOffset;
}
}
} while (scrollOffset > 0 && remainder > 0);


最后

简历首选内推方式&#xff0c;速度快&#xff0c;效率高啊&#xff01;然后可以在拉钩&#xff0c;boss&#xff0c;脉脉&#xff0c;大街上看看。简历上写道熟悉什么技术就一定要去熟悉它&#xff0c;不然被问到不会很尴尬&#xff01;做过什么项目&#xff0c;即使项目体量不大&#xff0c;但也一定要熟悉实现原理&#xff01;不是你负责的部分&#xff0c;也可以看看同事是怎么实现的&#xff0c;换你来做你会怎么做&#xff1f;做过什么&#xff0c;会什么是广度问题&#xff0c;取决于项目内容。但做过什么&#xff0c;达到怎样一个境界&#xff0c;这是深度问题&#xff0c;和个人学习能力和解决问题的态度有关了。大公司看深度&#xff0c;小公司看广度。大公司面试你会的&#xff0c;小公司面试他们用到的你会不会&#xff0c;也就是岗位匹配度。

面试过程一定要有礼貌&#xff01;即使你觉得面试官不尊重你&#xff0c;经常打断你的讲解&#xff0c;或者你觉得他不如你&#xff0c;问的问题缺乏专业水平&#xff0c;你也一定要尊重他&#xff0c;谁叫现在是他选择你&#xff0c;等你拿到offer后就是你选择他了。

另外&#xff0c;描述问题一定要慢&#xff01;不要一下子讲一大堆&#xff0c;慢显得你沉稳、自信&#xff0c;而且你还有时间反应思路接下来怎么讲更好。现在开发过多依赖ide&#xff0c;所以会有个弊端&#xff0c;当我们在面试讲解很容易不知道某个方法怎么读&#xff0c;这是一个硬伤…所以一定要对常见的关键性的类名、方法名、关键字读准&#xff0c;有些面试官不耐烦会说“你到底说的是哪个&#xff1f;”这时我们会容易乱了阵脚。正确的发音&#43;沉稳的描述&#43;好听的嗓音决对是一个加分项&#xff01;

最重要的是心态&#xff01;心态&#xff01;心态&#xff01;重要事情说三遍&#xff01;面试时间很短&#xff0c;在短时间内对方要摸清你的底子还是比较不现实的&#xff0c;所以&#xff0c;有时也是看眼缘&#xff0c;这还是个看脸的时代。

希望大家都能找到合适自己满意的工作&#xff01;
如果需要PDF版本可以在GitHub中自行领取&#xff01;


进阶学习视频

附上&#xff1a;我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 &#xff08;含BAT、小米、华为、美团、滴滴&#xff09;和我自己整理Android复习笔记&#xff08;包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。&#xff09;

[外链图片转存中…(img-c7siyZSt-1646484882168)]

附上&#xff1a;我们之前因为秋招收集的二十套一二线互联网公司Android面试真题 &#xff08;含BAT、小米、华为、美团、滴滴&#xff09;和我自己整理Android复习笔记&#xff08;包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。&#xff09;

[外链图片转存中…(img-YxfmTA2T-1646484882170)]


推荐阅读
  • 本文介绍了一款名为TimeSelector的Android日期时间选择器,采用了Material Design风格,可以在Android Studio中通过gradle添加依赖来使用,也可以在Eclipse中下载源码使用。文章详细介绍了TimeSelector的构造方法和参数说明,以及如何使用回调函数来处理选取时间后的操作。同时还提供了示例代码和可选的起始时间和结束时间设置。 ... [详细]
  • 本文详细介绍了Android中的坐标系以及与View相关的方法。首先介绍了Android坐标系和视图坐标系的概念,并通过图示进行了解释。接着提到了View的大小可以超过手机屏幕,并且只有在手机屏幕内才能看到。最后,作者表示将在后续文章中继续探讨与View相关的内容。 ... [详细]
  • 涉及的知识点-ViewGroup的测量与布局-View的测量与布局-滑动冲突的处理-VelocityTracker滑动速率跟踪-Scroller实现弹性滑动-屏幕宽高的获取等实现步 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 带添加按钮的GridView,item的删除事件
    先上图片效果;gridView无数据时显示添加按钮,有数据时,第一格显示添加按钮,后面显示数据:布局文件:addr_manage.xml<?xmlve ... [详细]
  • 1简介本文结合数字信号处理课程和Matlab程序设计课程的相关知识,给出了基于Matlab的音乐播放器的总体设计方案,介绍了播放器主要模块的功能,设计与实现方法.我们将该设 ... [详细]
  • SmartRefreshLayout自定义头部刷新和底部加载
    1.添加依赖implementation‘com.scwang.smartrefresh:SmartRefreshLayout:1.0.3’implementation‘com.s ... [详细]
  • python3 logging
    python3logginghttps:docs.python.org3.5librarylogging.html,先3.5是因为我当前的python版本是3.5之所 ... [详细]
  • 开发笔记:图像识别基于主成分分析算法实现人脸二维码识别
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了图像识别基于主成分分析算法实现人脸二维码识别相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 标题: ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • 深入理解CSS中的margin属性及其应用场景
    本文主要介绍了CSS中的margin属性及其应用场景,包括垂直外边距合并、padding的使用时机、行内替换元素与费替换元素的区别、margin的基线、盒子的物理大小、显示大小、逻辑大小等知识点。通过深入理解这些概念,读者可以更好地掌握margin的用法和原理。同时,文中提供了一些相关的文档和规范供读者参考。 ... [详细]
  • 工作经验谈之-让百度地图API调用数据库内容 及详解
    这段时间,所在项目中要用到的一个模块,就是让数据库中的内容在百度地图上展现出来,如经纬度。主要实现以下几点功能:1.读取数据库中的经纬度值在百度上标注出来。2.点击标注弹出对应信息。3 ... [详细]
author-avatar
呵呵哒
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有