Android 自定义卫星扇形菜单栏 可自行修改参数(1),2024年最新互联网公司面试官常问的问题

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注Android)
img

正文

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行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值