2024年最全ViewPager翻页特效(1_向源码学习),常用java框架面试题目

写在最后

学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯。所以:贵在坚持!

最后再分享的一些BATJ等大厂20、21年的面试题,把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,上面只是以图片的形式给大家展示一部分。

蚂蚁金服三面直击面试官的Redis三连,Redis面试复习大纲在手,不慌

Mybatis面试专题

蚂蚁金服三面直击面试官的Redis三连,Redis面试复习大纲在手,不慌

MySQL面试专题

蚂蚁金服三面直击面试官的Redis三连,Redis面试复习大纲在手,不慌

并发编程面试专题

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

但是上方的TabLayout字体大小变化,指示器indicator的长度和位置变化,谷歌给的TabLayout貌似没法弄,所以只能自己DIY了.

要完成这个特效,两个技能必须就位:

  • android 视图动画
    android体系中比较原始的一种动画类型。原理,是将view的绘制过程指定区域,按照指定规则再进行一遍,但是原本view所携带的事件交互,则不受影响。由于无法真正地继承事件交互,所以被属性动画所取代。但是它仍然有自己的价值。在不涉及到交互,只考虑视觉效果的情况下,它的效率反而比属性动画更高。

  • 数学建模思想

不要误会,这里说的数学建模是一种思维方式,把我们肉眼看到的现象,用数学公式的形式表达出来而已,并不是什么高深的操作。学过自定义控件并且 深入实践过的童鞋应该能够体会到,要想真正从0开始完成一个DIY控件,会有大量的数学计算,而拥有好的数学思维能力,能够在自定义的时候如鱼得水。

实现思路

一 ,源码研究

要对ViewPager进行特效改造,那么首先我们要知道ViewPager是一个容器ViewGroup,它内部的子View是如何摆放的,虽然从视觉上我们能够感觉到 子view是横向摆放的,但是作为技术人,就要敢于追根究底,用源码说话。

进入源码,找到 onLayout 方法(以下是我提炼的关键代码):

protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int count = getChildCount();

for (int i = 0; i < count; i++) {
if (child.getVisibility() != GONE) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
int childLeft = 0;
int childTop = 0;
if (lp.isDecor) {

}
}
}

for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
ItemInfo ii;
if (!lp.isDecor && (ii = infoForChild(child)) != null) {
int loff = (int) (childWidth * ii.offset);
int childLeft = paddingLeft + loff;
int childTop = paddingTop;
if (lp.needsMeasure) {
// This was added during layout and needs measurement.
// Do it now that we know what we’re working with.
lp.needsMeasure = false;
final int widthSpec = MeasureSpec.makeMeasureSpec(
(int) (childWidth * lp.widthFactor),
MeasureSpec.EXACTLY);
final int heightSpec = MeasureSpec.makeMeasureSpec(
(int) (height - paddingTop - paddingBottom),
MeasureSpec.EXACTLY);
child.measure(widthSpec, heightSpec);
}
if (DEBUG) {
Log.v(TAG, “Positioning #” + i + " " + child + " f=" + ii.object

  • “:” + childLeft + “,” + childTop + " " + child.getMeasuredWidth()
  • “x” + child.getMeasuredHeight());
    }
    child.layout(childLeft, childTop,
    childLeft + child.getMeasuredWidth(),
    childTop + child.getMeasuredHeight());
    }
    }
    }
    }

上面代码中,对 count 进行了两轮循环,其中第一轮是针对 lp.isDecortrue的,

意为:如果当前view是一个 decoration 装饰,并不是adapter提供的view 则返回 true

显然,我们要探讨的是 adapter提供的View 是如何摆放的,所以忽略这一块。

而在下面的循环中,可以看到

child.layout(childLeft, childTop,
childLeft + child.getMeasuredWidth(),
childTop + child.getMeasuredHeight());

这个便是child的排布的核心代码,追溯这4个参数,可以得知:第 1,3 参数 表示 left ,right , 他们都和一个 int loff = (int) (childWidth * ii.offset); 挂钩,而 第2,4 参数表示 top,bottom , 则 并没有与 任何动态参数相挂钩。

因此可以断定,ViewPager的子View排布,只会存在X轴方向上的位置偏差,在Y方向上会保持上下平齐。

其实还可以继续追溯 int loff = (int) (childWidth * ii.offset); 看看 x轴方向上的位置偏差是如何造成的,但是目的已经达到,到有必要的时候再去追查。

确定是横向排布,那么左右滑动逻辑又是怎么样的呢?

找到 onTouchEvent() 方法, 并且在其中找到 ACTION_MOVE 逻辑分支:

case MotionEvent.ACTION_MOVE:
if (!mIsBeingDragged) {
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex == -1) {
// A child has consumed some touch events and put us into an inconsistent
// state.
needsInvalidate = resetTouch();
break;
}
final float x = ev.getX(pointerIndex);
final float xDiff = Math.abs(x - mLastMotionX);
final float y = ev.getY(pointerIndex);
final float yDiff = Math.abs(y - mLastMotionY);
if (DEBUG) {
Log.v(TAG, “Moved x to " + x + “,” + y + " diff=” + xDiff + “,” + yDiff);
}
if (xDiff > mTouchSlop && xDiff > yDiff) {
if (DEBUG) Log.v(TAG, “Starting drag!”);
mIsBeingDragged = true;
requestParentDisallowInterceptTouchEvent(true);
mLastMotionX = x - mInitialMotionX > 0 ? mInitialMotionX + mTouchSlop :
mInitialMotionX - mTouchSlop;
mLastMotionY = y;
setScrollState(SCROLL_STATE_DRAGGING);
setScrollingCacheEnabled(true);

// Disallow Parent Intercept, just in case
ViewParent parent = getParent();
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
}
}
// Not else! Note that mIsBeingDragged can be set above.
if (mIsBeingDragged) {
// Scroll to follow the motion event
final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
final float x = ev.getX(activePointerIndex);
needsInvalidate |= performDrag(x);
}
break;

我们需要关注的只是 X方向上的拖拽有什么规律. 所以,顺着final float x = ev.getX(pointerIndex); 这个变量去找关键方法, 最终锁定:performDrag(x); 它是处理X方向上位移的关键入口。

private boolean performDrag(float x) {
boolean needsInvalidate = false;

final float deltaX = mLastMotionX - x;
mLastMotionX = x;


// Don’t lose the rounded component
mLastMotionX += scrollX - (int) scrollX;
scrollTo((int) scrollX, getScrollY()); // 关键代码1, 控件在画布上的横像滚动
pageScrolled((int) scrollX);// 关键代码2,将 scrollX进一步往下传递

return needsInvalidate;
}

发现两句关键代码,一个是处理滑动的 scrolllTo,一个是把scrollX往下传递的 pageScrolled(scrollX). 前面一句都明白,但是这个第二句就有点不懂了,继续深入。

private boolean pageScrolled(int xpos) {

final float pageOffset = (((float) xpos / width) - ii.offset)
/ (ii.widthFactor + marginOffset);
final int offsetPixels = (int) (pageOffset * widthWithMargin);

mCalledSuper = false;
onPageScrolled(currentPage, pageOffset, offsetPixels);
if (!mCalledSuper) {
throw new IllegalStateException(
“onPageScrolled did not call superclass implementation”);
}
return true;
}

追踪 参数xpos得知,x方向上的偏移量信息,最后进入了 onPageScrolled(...) 方法.

protected void onPageScrolled(int position, float offset, int offsetPixels) {
// Offset any decor views if needed - keep them on-screen at all times.
if (mDecorChildCount > 0) {
… // 这里还是在处理 装饰,所以不用看,而且参数也没进入到这里
}

dispatchOnPageScrolled(position, offset, offsetPixels);

if (mPageTransformer != null) {
final int scrollX = getScrollX();
final int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();

if (lp.isDecor) continue;
final float transformPos = (float) (child.getLeft() - scrollX) / getClientWidth();

最后

学习视频:

大厂面试真题:

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

3476588)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值