先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip204888 (备注Android)
正文
android:tag=“Video” />
<ImageView
android:layout_width=“55dp”
android:layout_height=“55dp”
android:src=“@mipmap/icon_dynamic_camera”//子菜单2图片
android:tag=“Camera” />
<ImageView
android:layout_width=“55dp”
android:layout_height=“55dp”
android:src=“@mipmap/icon_dynamic_text”//子菜单3图片
android:tag=“Text” />
<ImageView
android:id=“@+id/btn_plus”
android:layout_width=“55dp”
android:layout_height=“55dp”
android:src=“@mipmap/icon_dynamic_edit”//主菜单图片
android:stateListAnimator=“@null” />
</com.android.infantschool.ui.view.SrcMenu>
自定义RelativiLayout
public class ForbidRelativeLayout extends RelativeLayout {
public ForbidRelativeLayout(Context context) {
super(context);
}
public ForbidRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
/**
-
添加事件拦截,以免用户在banner广告中随意切换广告
-
@param event
-
@return true:拦截,false:不拦截
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
super.onInterceptTouchEvent(event);
return true;
}
/**
-
添加事件拦截,以免用户在banner广告中随意切换广告
-
@param event
-
@return true:拦截,false:不拦截
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
return true;
}
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
super.onWindowFocusChanged(hasWindowFocus);
}
}
自定义菜单栏
public class SrcMenu extends ViewGroup implements View.OnClickListener {
private static final int POS_LEFT_TOP = 0;
private static final int POS_LEFT_BOTTOM = 1;
private static final int POS_RIGHT_TOP = 2;
private static final int POS_RIGHT_BOTTOM = 3;
private Position mPosition = Position.RIGHT_BOTTOM;//菜单位置
private int mRadius;//菜单半径
public Status mStatus = Status.CLOSE;//菜单开闭状态
public View mCButton;//菜单主按钮
private OnMenuItemClickListener mOnMenuItemClickListener;//菜单点击事件的成员变量
private OnMainClickListener mainClickListener;//主菜单事件
/**
- 菜单状态枚举类
*/
public enum Status {
OPEN, CLOSE
}
/**
- 菜单位置枚举类
*/
private enum Position {
LEFT_TOP, LEFT_BOTTOM, RIGHT_TOP, RIGHT_BOTTOM
}
/**
- 菜单按钮点击事件回调接口
*/
public interface OnMenuItemClickListener {
void onClick(View view, int position);
}
/**
- 菜单按钮点击事件回调接口
*/
public interface OnMainClickListener {
void onClick();
}
public SrcMenu(Context context) {
this(context, null);
}
public SrcMenu(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SrcMenu(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mRadius = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_FRACTION, 60,
getResources().getDisplayMetrics());//设置菜单半径默认值
//获取自定义属性值
TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.SrcMenu, defStyleAttr, 0);
//获取位置值
int pos = array.getInt(R.styleable.SrcMenu_position, POS_RIGHT_BOTTOM);
switch (pos) {
case POS_LEFT_TOP:
mPosition = Position.LEFT_TOP;
break;
case POS_LEFT_BOTTOM:
mPosition = Position.LEFT_BOTTOM;
break;
case POS_RIGHT_TOP:
mPosition = Position.RIGHT_TOP;
break;
case POS_RIGHT_BOTTOM:
mPosition = Position.RIGHT_BOTTOM;
break;
default:
break;
}
//获取菜单半径值
mRadius = (int) array.getDimension(R.styleable.SrcMenu_radius, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_FRACTION, 60, getResources().getDisplayMetrics())) / 5 * 4;
array.recycle();
}
/**
- 设置菜单点击事件
*/
public void setOnMenuItemClickListener(OnMenuItemClickListener onMenuItemClickListener) {
mOnMenuItemClickListener = onMenuItemClickListener;
}
private int type;
public void setMainOnClickLister(OnMainClickListener mainOnClickLister) {
this.mainClickListener = mainOnClickLister;
}
/**
-
测量模式+测量值
-
@param widthMeasureSpec
-
@param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int count = getChildCount();
for (int i = 0; i < count; i++) {
//测量 child
measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
if (b) {
layoutCButton();
int count = getChildCount();
for (int j = 0; j < count - 1; j++) {
View child = getChildAt(j);
//开始时设置子菜单不可见
child.setVisibility(GONE);
//默认按钮位于左上时
int cl = (int) (mRadius * Math.sin(Math.PI / 2 / (count - 2) * j));
int ct = (int) (mRadius * Math.cos(Math.PI / 2 / (count - 2) * j));
int cWidth = child.getMeasuredWidth();
int cHeight = child.getMeasuredHeight();
//按钮位于左下、右下时
if (mPosition == Position.LEFT_BOTTOM || mPosition == Position.RIGHT_BOTTOM) {
ct = getMeasuredHeight() - cHeight - ct;
}
//按钮位于右上、右下时
if (mPosition == Position.RIGHT_TOP || mPosition == Position.RIGHT_BOTTOM) {
cl = getMeasuredWidth() - cWidth - cl;
}
child.layout(cl - 30, ct - 50, cl + cWidth - 30, ct + cHeight - 50);
}
}
}
/**
- 定位主菜单按钮
*/
private void layoutCButton() {
mCButton = getChildAt(3);
/mCButton.bringToFront();/
mCButton.setOnClickListener(this);
int l = 0;
int t = 0;
int width = mCButton.getMeasuredWidth();
int height = mCButton.getMeasuredHeight();
//设置按钮显示的位置
switch (mPosition) {
case LEFT_BOTTOM:
l = 0;
t = getMeasuredHeight() - height;
break;
case LEFT_TOP:
l = 0;
t = 0;
break;
case RIGHT_TOP:
l = getMeasuredWidth() - width;
t = 0;
break;
case RIGHT_BOTTOM:
l = getMeasuredWidth() - width;
t = getMeasuredHeight() - height;
break;
default:
break;
}
mCButton.layout(l - 30, t - 50, l + width - 30, t + height - 50);
}
@Override
public void onClick(View view) {//主按钮点击事件
if (isOpen()) {//打开
rotateCButton(view, -90, 0, 200);
} else {
rotateCButton(view, 0, -90, 200);
}
toggleMenu();
if (mainClickListener != null) {
mainClickListener.onClick();
}
}
/**
- 切换菜单
*/
public void toggleMenu() {
int count = getChildCount();
for (int i = 0; i < count - 1; i++) {
final View childView = getChildAt(i);
childView.setVisibility(VISIBLE);
int cl = (int) (mRadius * Math.sin(Math.PI / 2 / (count - 2) * i));
int ct = (int) (mRadius * Math.cos(Math.PI / 2 / (count - 2) * i));
//根据菜单所处位置的不同,设置不同的参数值
int xFlag = 1;
int yFlag = 1;
if (mPosition == Position.LEFT_TOP || mPosition == Position.LEFT_BOTTOM) {
xFlag = -1;
}
if (mPosition == Position.LEFT_TOP || mPosition == Position.RIGHT_TOP) {
yFlag = -1;
}
//平移动画
AnimationSet animationSet = new AnimationSet(true);
Animation animation;
if (mStatus == Status.CLOSE) {
//打开按钮的动画
animation = new TranslateAnimation(xFlag * cl - 00, -00, yFlag * ct - 00, -00);
childView.setFocusable(true);
childView.setClickable(true);
animation.setDuration(300);
} else {
//关闭按钮的动画 xFlag * cl yFlag * ct
animation = new TranslateAnimation(-00, xFlag * cl - 00, -00, yFlag * ct - 00);
childView.setFocusable(false);
childView.setClickable(false);
animation.setDuration(300);
}
animation.setFillAfter(true);
animation.setStartOffset((i * 100) / count);
//监听动画状态
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
if (mStatus == Status.CLOSE) {
childView.setVisibility(GONE);
}
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
//旋转动画
RotateAnimation rotateAnimation = new RotateAnimation(360, 0,//控制菜单收回的时候选择角度
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setFillAfter(true);
《设计思想解读开源框架》
第一章、 热修复设计
-
第一节、 AOT/JIT & dexopt 与 dex2oat
-
第二节、 热修复设计之 CLASS_ISPREVERIFIED 问题
-
第三节、热修复设计之热修复原理
-
第四节、Tinker 的集成与使用(自动补丁包生成)
第二章、 插件化框架设计
-
第一节、 Class 文件与 Dex 文件的结构解读
-
第二节、 Android 资源加载机制详解
-
第三节、 四大组件调用原理
-
第四节、 so 文件加载机制
-
第五节、 Android 系统服务实现原理
第三章、 组件化框架设计
-
第一节、阿里巴巴开源路由框——ARouter 原理分析
-
第二节、APT 编译时期自动生成代码&动态类加载
-
第三节、 Java SPI 机制
-
第四节、 AOP&IOC
-
第五节、 手写组件化架构
第四章、图片加载框架
-
第一节、图片加载框架选型
-
第二节、Glide 原理分析
-
第三节、手写图片加载框架实战
第五章、网络访问框架设计
-
第一节、网络通信必备基础
-
第二节、OkHttp 源码解读
-
第三节、Retrofit 源码解析
第六章、 RXJava 响应式编程框架设计
-
第一节、链式调用
-
第二节、 扩展的观察者模式
-
第三节、事件变换设计
-
第四节、Scheduler 线程控制
第七章、 IOC 架构设计
-
第一节、 依赖注入与控制反转
-
第二节、ButterKnife 原理上篇、中篇、下篇
-
第三节、Dagger 架构设计核心解密
第八章、 Android 架构组件 Jetpack
-
第一节、 LiveData 原理
-
第二节、 Navigation 如何解决 tabLayout 问题
-
第三节、 ViewModel 如何感知 View 生命周期及内核原理
-
第四节、 Room 架构方式方法
-
第五节、 dataBinding 为什么能够支持 MVVM
-
第六节、 WorkManager 内核揭秘
-
第七节、 Lifecycles 生命周期
本文包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
架构设计**
-
第一节、 依赖注入与控制反转
-
第二节、ButterKnife 原理上篇、中篇、下篇
-
第三节、Dagger 架构设计核心解密
[外链图片转存中…(img-SgMDDpVz-1713685720789)]
第八章、 Android 架构组件 Jetpack
-
第一节、 LiveData 原理
-
第二节、 Navigation 如何解决 tabLayout 问题
-
第三节、 ViewModel 如何感知 View 生命周期及内核原理
-
第四节、 Room 架构方式方法
-
第五节、 dataBinding 为什么能够支持 MVVM
-
第六节、 WorkManager 内核揭秘
-
第七节、 Lifecycles 生命周期
[外链图片转存中…(img-7saa0Vfw-1713685720790)]
本文包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中…
[外链图片转存中…(img-AbpDk071-1713685720790)]
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-FMXdoj4W-1713685720790)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!