最后
答应大伙的备战金三银四,大厂面试真题来啦!
这份资料我从春招开始,就会将各博客、论坛。网站上等优质的Android开发中高级面试题收集起来,然后全网寻找最优的解答方案。每一道面试题都是百分百的大厂面经真题+最优解答。包知识脉络 + 诸多细节。
节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。
《960全网最全Android开发笔记》
《379页Android开发面试宝典》
包含了腾讯、百度、小米、阿里、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。
如何使用它?
1.可以通过目录索引直接翻看需要的知识点,查漏补缺。
2.五角星数表示面试问到的频率,代表重要推荐指数
《507页Android开发相关源码解析》
只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。
真正最能锻炼能力的便是直接去阅读源码,不仅限于阅读各大系统源码,还包括各种优秀的开源库。
腾讯、字节跳动、阿里、百度等BAT大厂 2020-2021面试真题解析
资料收集不易,如果大家喜欢这篇文章,或者对你有帮助不妨多多点赞转发关注哦。文章会持续更新的。绝对干货!!!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
android:textSize="20sp" />
</com.kongqw.view.ScrollViewPager>
写完布局我们要重写`onMeasure`和`onLayout`方法,开始对布局测量、排布。
我们这里是纵向排布。
/**
- 测量
*/
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
for (index in 0 until childCount) {
measureChild(getChildAt(index), widthMeasureSpec, heightMeasureSpec)
}
}
/**
- 布局 纵向布局
*/
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
var top = 0
var bottom = 0
for (index in 0 until childCount) {
val childView = getChildAt(index)
bottom = top + childView.measuredHeight
childView.layout(0, top, childView.measuredWidth, bottom)
top = bottom
}
mBottomBorder = bottom
}
写到这里运行程序,应该是可以看得到第一个页面了,但是滑动没有任何反应,我们需要重写`onTouchEvent`方法,让View可以根据手指的滑动而滚动,这里需要监听event的`ACTION_DOWN`、`ACTION_MOVE`、`ACTION_UP`、`ACTION_CANCEL`状态,通过`ACTION_MOVE`记录手指每次纵向移动的距离,在监听到`ACTION_UP`、`ACTION_CANCEL`的时候,判断滑动位置,然后滚动到哪个页面。这样,一个简单的页面滑动就实现了。
### scrollBy、scrollTo
提到滚动,就不得不提到两个方法,`scrollBy`和`scrollTo`,值得注意的是,通常我们一种面向对象的思想,想让谁滚动,谁就调用自己的scroll就行了,但是,这里的`scrollBy`和`scrollTo`针对的是自己子View的运动,说白话了,就是老爸要管理儿子运动的。
`scrollBy`是控制一次滚动多少,`scrollTo`是控制滚动到哪里。
我们这里自定义了ScrollViewPager,页面内容都写在ScrollViewPager内部,所以,我们控制滚动,就是在控制ScrollViewPager内部的子View滚动,所以,直接调用`scrollBy`和`scrollTo`即可。
### Scroller
现在滑动没有问题了,但是手指一松开,View 会瞬间移动到指定位置,体验不太好,我们想要View的滚动有一个顺滑的过程,这就又不得不再提到一个`Scroller`类,他可以帮助我们完成动画的平缓过度。
通过`Scroller`的`startScroll`来初始化运动的起始位置、结束位置和运动时间,然后调用`invalidate()`开始处理,这里会一直回调`View`的`computeScroll`方法,是一个空方法,需要我们自己在这里自己依据`Scroller`的`computeScrollOffset()`判断移动是否完成,然后调用`scrollTo`来完成平滑移动处理。
到这里,View就可以实现上下滑动,并平滑过渡了,接下来来处理事件的分发问题。
我们想要实现的目标是,当我们上下滑动的时候,可以滚动页面,要将事件拦截。
当我们在子控件上左右滑动的时候,可以将事件先交给子控件处理。那么我们就可以重写`ScrollViewPager`的`onInterceptTouchEvent`方法,在`ACTION_MOVE`的时候判断滑动方向,如果是上下滑动,则返回true,将事件拦截即可。
下面是自定义`ScrollViewPager`源码(Kotlin代码):
package com.kongqw.view.ScrollViewPager
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import android.view.ViewConfiguration
import android.view.ViewGroup
import android.widget.Scroller
/**
-
Created by Kongqw on 2018/3/29.
-
ScrollViewPager
*/
class ScrollViewPager(context: Context?, attrs: AttributeSet?) : ViewGroup(context, attrs) {
/**
* 手指按下位置
*/
private var mDownX = 0.0F
private var mDownY = 0.0F
/**
* 手指移动后的位置
*/
private var mMoveX = 0.0F
private var mMoveY = 0.0F
/**
* 手指最后移动位置
*/
private var mLastX = 0.0F
private var mLastY = 0.0F
/**
* View 上边界
*/
private val mTopBorder = 0
/**
* View 下边界
*/
private var mBottomBorder = 0
/**
* 滑动处理
*/
private val mScroller: Scroller = Scroller(context)
/**
* 事件是否拦截
*/
private var isIntercept = false
/**
* 最小移动单位
*/
private val mScaledtouchslop = ViewConfiguration.get(context).scaledTouchSlop
companion object {
private val TAG: String = ScrollViewPager::class.java.simpleName
}
/**
* 测量
*/
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
for (index in 0 until childCount) {
Log.i(TAG, "测量第 $index 个控件大小")
measureChild(getChildAt(index), widthMeasureSpec, heightMeasureSpec)
}
}
/**
* 布局 纵向布局
*/
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
var top = 0
var bottom = 0
for (index in 0 until childCount) {
val childView = getChildAt(index)
bottom = top + childView.measuredHeight
Log.i(TAG, "布局第几个View [0, ${top}, ${childView.measuredWidth}, ${bottom}]")
childView.layout(0, top, childView.measuredWidth, bottom)
top = bottom
}
mBottomBorder = bottom
Log.i(TAG, "View 高度 $height")
}
override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
val touchX = ev?.rawX
val touchY = ev?.rawY
when (ev?.action) {
MotionEvent.ACTION_DOWN -> {
mDownX = touchX!!
mDownY = touchY!!
isIntercept = false
}
MotionEvent.ACTION_MOVE -> {
mMoveX = touchX!!
mMoveY = touchY!!
val dx = Math.abs(mMoveX - mDownX)
val dy = Math.abs(mMoveY - mDownY)
// if(dy > dx){
// isIntercept = true
// }
isIntercept = (dy > dx)
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
isIntercept = false
}
}
mLastX = touchX!!
mLastY = touchY!!
return isIntercept
// return super.onInterceptTouchEvent(ev)
}
@SuppressLint("ClickableViewAccessibility")
override fun onTouchEvent(event: MotionEvent?): Boolean {
val touchY = event?.rawY
when (event?.action) {
MotionEvent.ACTION_DOWN -> {
Log.i(TAG, "ACTION_DOWN")
// 获取手指按下的位置
mDownY = touchY!!
return true
}
MotionEvent.ACTION_MOVE -> {
Log.i(TAG, "ACTION_MOVE")
// 获取手指移动后的位置
mMoveY = touchY!!
// 计算手指在Y轴移动距离
// val dY = Math.abs(mLastY - mDownY)
val dY = mLastY - mMoveY
when {
scrollY < mTopBorder -> {
// 向下已经划出上边界
Log.i(TAG, "向下已经划出上边界")
scrollBy(0, dY.toInt() / 5)
}
scrollY + height > mBottomBorder -> {
// 向上已经划出下边界
Log.i(TAG, "向上已经划出下边界")
scrollBy(0, dY.toInt() / 5)
}
else -> {
// 移动
scrollBy(0, dY.toInt())
}
}
// 刷新页面
invalidate()
mLastY = mMoveY
}
MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
Log.i(TAG, "ACTION_UP View 纵向滑动了 $scrollY")
when {
scrollY <= mTopBorder -> {
// 向下已经划出上边界
Log.i(TAG, "向下已经划出上边界")
mScroller.startScroll(0, scrollY, 0, -scrollY)
invalidate()
}
scrollY + height >= mBottomBorder -> {
// 向上已经划出下边界
Log.i(TAG, "向上已经划出下边界")
val dy = mBottomBorder - scrollY - height
mScroller.startScroll(0, scrollY, 0, dy)
invalidate()
}
else -> {
// 移动
val page = computePageByScrollY(scrollY)
Log.i(TAG, "滑动到第 $page 页")
mScroller.startScroll(0, scrollY, 0, height * page - scrollY)
invalidate()
}
}
}
}
mLastY = touchY!!
return super.onTouchEvent(event)
最后
其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。
下面分享的腾讯、头条、阿里、美团、字节跳动等公司2019-2021年的高频面试题全套解析,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,下面只是以图片的形式给大家展示一部分。
知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
其实Android开发的知识点就那么多,面试问来问去还是那么点东西。所以面试没有其他的诀窍,只看你对这些知识点准备的充分程度。so,出去面试时先看看自己复习到了哪个阶段就好。
下面分享的腾讯、头条、阿里、美团、字节跳动等公司2019-2021年的高频面试题全套解析,博主还把这些技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,下面只是以图片的形式给大家展示一部分。
[外链图片转存中…(img-TkcVkGbt-1715751893132)]
知识不体系?这里还有整理出来的Android进阶学习的思维脑图,给大家参考一个方向。
[外链图片转存中…(img-7D34727D-1715751893132)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!