仿饿了么加入购物车旋转控件 - 自带闪转腾挪动画 的按钮

, mWidth - mCircleWidth, mHeight - mCircleWidth);

canvas.drawRoundRect(rectF, mHintBgRoundValue, mHintBgRoundValue, mHintPaint);

//前景文字

mHintPaint.setColor(mHintFgColor);

// 计算Baseline绘制的起点X轴坐标

int baseX = (int) (mWidth / 2 - mHintPaint.measureText(mHintText) / 2);

// 计算Baseline绘制的Y坐标

int baseY = (int) ((mHeight / 2) - ((mHintPaint.descent() + mHintPaint.ascent()) / 2));

canvas.drawText(mHintText, baseX, baseY, mHintPaint);

} else {

//左边

//背景 圆

if (mCount > 0) {

mDelPaint.setColor(mDelEnableBgColor);

} else {

mDelPaint.setColor(mDelDisableBgColor);

}

mDelPaint.setStrokeWidth(mCircleWidth);

mDelPath.reset();

mDelPath.addCircle(mLeft + mRadius, mTop + mRadius, mRadius, Path.Direction.CW);

mDelRegion.setPath(mDelPath, new Region(mLeft, mTop, mWidth - getPaddingRight(), mHeight - getPaddingBottom()));

canvas.drawPath(mDelPath, mDelPaint);

//前景 -

if (mCount > 0) {

mDelPaint.setColor(mDelEnableFgColor);

} else {

mDelPaint.setColor(mDelDisableFgColor);

}

mDelPaint.setStrokeWidth(mLineWidth);

canvas.drawLine(-mRadius / 2, 0,

+mRadius / 2, 0,

mDelPaint);

//数量

//是没有动画的普通写法,x left, y baseLine

canvas.drawText(mCount + “”, mLeft + mRadius * 2, mTop + mRadius - (mFontMetrics.top + mFontMetrics.bottom) / 2, mTextPaint);

//右边

//背景 圆

if (mCount < mMaxCount) {

mAddPaint.setColor(mAddEnableBgColor);

} else {

mAddPaint.setColor(mAddDisableBgColor);

}

mAddPaint.setStrokeWidth(mCircleWidth);

float left = mLeft + mRadius * 2 + mGapBetweenCircle;

mAddPath.reset();

mAddPath.addCircle(left + mRadius, mTop + mRadius, mRadius, Path.Direction.CW);

mAddRegion.setPath(mAddPath, new Region(mLeft, mTop, mWidth - getPaddingRight(), mHeight - getPaddingBottom()));

canvas.drawPath(mAddPath, mAddPaint);

//前景 +

if (mCount < mMaxCount) {

mAddPaint.setColor(mAddEnableFgColor);

} else {

mAddPaint.setColor(mAddDisableFgColor);

}

mAddPaint.setStrokeWidth(mLineWidth);

canvas.drawLine(left + mRadius / 2, mTop + mRadius, left + mRadius / 2 + mRadius, mTop + mRadius, mAddPaint);

canvas.drawLine(left + mRadius, mTop + mRadius / 2, left + mRadius, mTop + mRadius / 2 + mRadius, mAddPaint);

}

}

根据isHintMode 布尔值变量,区分是绘制第二层(Hint层)或者第一层(加减按钮层)。

绘制第二层时没啥好说的,就是利用canvas.drawRoundRect,绘制圆角矩形,然后canvas.drawText绘制hint。

(如果圆角的值足够大,矩形的宽度足够小,就变成了圆形。)

绘制第一层时,要根据当前的数量选择不同的颜色,注意在绘制加减按钮的圆圈时,我们是用Path绘制的,这是因为我们还需要用Path构建Region类,这个类就是我们监听点击区域的重点

点击事件的监听


在讲解动画之前,我们先说说如何监听点击的区域,因为本控件的动画是和加减数量息息相关的,而数量的加减是由点击相应”+ - 按钮”区域触发的。

所以我们的监听按钮的点击事件,其实就是监听相应的”+ - 按钮”区域

上一节中,我们在绘制”+ - 按钮”区域时,通过Path,构建了两个Region类,Region类有个contains(int x, int y)方法如下,通过传入对应触摸的x、y坐标,就可知道知否点击了相应区域

/**

  • Return true if the region contains the specified point

*/

public native boolean contains(int x, int y);

知道了这一点,再写这部分代码就相当简单了:

@Override

public boolean onTouchEvent(MotionEvent event) {

int action = event.getAction();

switch (action) {

case MotionEvent.ACTION_DOWN:

//hint模式

if (isHintMode) {

onAddClick();

return true;

} else {

if (mAddRegion.contains((int) event.getX(), (int) event.getY())) {

onAddClick();

return true;

} else if (mDelRegion.contains((int) event.getX(), (int) event.getY())) {

onDelClick();

return true;

}

}

break;

case MotionEvent.ACTION_MOVE:

break;

case MotionEvent.ACTION_UP:

case MotionEvent.ACTION_CANCEL:

break;

}

return super.onTouchEvent(event);

}

hint模式时,我们可以认为控件所有范围都是“+”的有效区域

而在非hint模式时,根据上一节构建的mAddRegionmDelRegion去判断。

判断确认点击后,具体的操作,要根据业务的不同来编写了,设计到实际的购物车可能还有写数据库操作,或者请求接口等,要操作成功后才执行动画、或者修改count,这一块代码每个人写法可能不同。

使用时,可以重写onDelClick()onAddClick()方法,并在合适的时机回调onCountAddSuccess()onCountDelSuccess()以执行动画。

本文如下编写:

protected void onDelClick() {

if (mCount > 0) {

mCount–;

onCountDelSuccess();

}

}

protected void onAddClick() {

if (mCount < mMaxCount) {

mCount++;

onCountAddSuccess();

} else {

}

}

/**

  • 数量增加成功后,使用者回调

*/

public void onCountAddSuccess() {

if (mCount == 1) {

cancelAllAnim();

mAnimReduceHint.start();

} else {

mAnimFraction = 0;

invalidate();

}

}

/**

  • 数量减少成功后,使用者回调

*/

public void onCountDelSuccess() {

if (mCount == 0) {

cancelAllAnim();

mAniDel.start();

} else {

mAnimFraction = 0;

invalidate();

}

}

动画的实现


这里会用到两个变量:

//动画的基准值 动画:减 0~1, 加 1~0

// 普通状态下是0

protected float mAnimFraction;

//提示语收缩动画 0-1 展开1-0

//普通模式时,应该是1, 只在 isHintMode true 才有效

protected float mAnimExpandHintFraction;

依次分析有哪些动画:

Hint动画

主要是圆角矩形的展开、收缩

固定right、bottom,当展开时,不断减少矩形的左起点left坐标值,则整个矩形宽度变大,呈现展开。收缩时相反。

代码:

//背景

mHintPaint.setColor(mHintBgColor);

RectF rectF = new RectF(mLeft + (mWidth - mRadius * 2) * mAnimExpandHintFraction, mTop

, mWidth - mCircleWidth, mHeight - mCircleWidth);

canvas.drawRoundRect(rectF, mHintBgRoundValue, mHintBgRoundValue, mHintPaint);

减按钮动画

看起来是旋转、位移、透明度

那么对于背景的圆圈来说,我们只需要位移、透明度。因为它本身是个圆,就不要旋转了。

代码:

//动画 mAnimFraction :减 0~1, 加 1~0 ,

//动画位移Max,

float animOffsetMax = (mRadius * 2 +mGapBetweenCircle);

//透明度动画的基准

int animAlphaMax = 255;

int animRotateMax = 360;

//左边

//背景 圆

mDelPaint.setAlpha((int) (animAlphaMax * (1 - mAnimFraction)));

mDelPath.reset();

//改变圆心的X坐标,实现位移

mDelPath.addCircle(animOffsetMax * mAnimFraction + mLe​
ft + mRadius, mTop + mRadius, mRadius, Path.Direction.CW);

canvas.drawPath(mDelPath, mDelPaint);

对于前景的“-”号来说,旋转、位移、透明度都需要做。

这里我们利用canvas.translate() canvas.rotate 做旋转和位移动画,别忘了 canvas.save()canvas.restore()恢复画布的状态。(透明度在上面已经设置过了。)

//前景 -

//旋转动画

canvas.save();

canvas.translate(animOffsetMax * mAnimFraction + mLeft + mRadius, mTop + mRadius);

canvas.rotate((int) (animRotateMax * (1 - mAnimFraction)));

canvas.drawLine(-mRadius / 2, 0,

+mRadius / 2, 0,

mDelPaint);

canvas.restore();

数量的动画

看起来也是旋转、位移、透明度。同样是利用canvas.translate() canvas.rotate 做旋转和位移动画。

//数量

canvas.save();

//平移动画

canvas.translate(mAnimFraction * (mGapBetweenCircle / 2 - mTextPaint.measureText(mCount + “”) / 2 + mRadius), 0);

//旋转动画,旋转中心点,x 是绘图中心,y 是控件中心

canvas.rotate(360 * mAnimFraction,

mGapBetweenCircle / 2 + mLeft + mRadius * 2 ,

mTop + mRadius);

//透明度动画

mTextPaint.setAlpha((int) (255 * (1 - mAnimFraction)));

//是没有动画的普通写法,x left, y baseLine

canvas.drawText(mCount + “”, mGapBetweenCircle / 2 - mTextPaint.measureText(mCount + “”) / 2 + mLeft + mRadius * 2, mTop + mRadius - (mFontMetrics.top + mFontMetrics.bottom) / 2, mTextPaint);

canvas.restore();

动画的定义:

动画是在View初始化时就定义好的,执行顺序:

  • 数量增加,0-1时,先收缩Hint(第二层)mAnimReduceHint执行,完毕后执行减按钮(第一层)进入的动画mAnimAdd

  • 数量减少,1-0时,先执行减按钮退出的动画mAniDel,再伸展Hint动画mAnimExpandHint,完毕后,显示hint文字。

代码如下:

//动画 +

mAnimAdd = ValueAnimator.ofFloat(1, 0);

mAnimAdd.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

mAnimFraction = (float) animation.getAnimatedValue();

invalidate();

}

});

mAnimAdd.setDuration(350);

//提示语收缩动画 0-1

mAnimReduceHint = ValueAnimator.ofFloat(0, 1);

mAnimReduceHint.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

mAnimExpandHintFraction = (float) animation.getAnimatedValue();

invalidate();

}

});

mAnimReduceHint.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationEnd(Animator animation) {

if (mCount == 1) {

//然后底色也不显示了

isHintMode = false;

}

if (mCount == 1) {

Log.d(TAG, “现在还是1 开始收缩动画”);

if (mAnimAdd != null && !mAnimAdd.isRunning()) {

mAnimAdd.start();

}

}

}

@Override

public void onAnimationStart(Animator animation) {

if (mCount == 1) {

//先不显示文字了

isShowHintText = false;

}

}

});

mAnimReduceHint.setDuration(350);

//动画 -

mAniDel = ValueAnimator.ofFloat(0, 1);

mAniDel.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

mAnimFraction = (float) animation.getAnimatedValue();

invalidate();

}

});

//1-0的动画

mAniDel.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationEnd(Animator animation) {

if (mCount == 0) {

Log.d(TAG, “现在还是0onAnimationEnd() called with: animation = [” + animation + “]”);

if (mAnimExpandHint != null && !mAnimExpandHint.isRunning()) {

mAnimExpandHint.start();

}

}

}

});

mAniDel.setDuration(350);

//提示语展开动画

//分析这个动画,最初是个圆。 就是left 不断减小

mAnimExpandHint = ValueAnimator.ofFloat(1, 0);

mAnimExpandHint.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

mAnimExpandHintFraction = (float) animation.getAnimatedValue();

invalidate();

}

});

mAnimExpandHint.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationEnd(Animator animation) {

if (mCount == 0) {

isShowHintText = true;

}

}

@Override

public void onAnimationStart(Animator animation) {

if (mCount == 0) {

isHintMode = true;

}

}

});

mAnimExpandHint.setDuration(350);

针对复用机制的处理


因为我们的购物车控件肯定会用在列表中,不管你用ListView还是RecyclerView,都会涉及到复用的问题。

复用给我们带来一个麻烦的地方就是,我们要处理好一些属性状态值,否则UI上会有问题。

可以从两处下手处理:

onMeasure

列表复用时,依然会回调onMeasure()方法,所以在这里初始化一些UI显示的参数。

这里顺带将适配wrap_content 的代码也一同贴上:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int wMode = MeasureSpec.getMode(widthMeasureSpec);

int wSize = MeasureSpec.getSize(widthMeasureSpec);

int hMode = MeasureSpec.getMode(heightMeasureSpec);

int hSize = MeasureSpec.getSize(heightMeasureSpec);

switch (wMode) {

case MeasureSpec.EXACTLY:

break;

case MeasureSpec.AT_MOST:

//不超过父控件给的范围内,自由发挥

int computeSize = (int) (getPaddingLeft() + mRadius * 2 +mGapBetweenCircle + mRadius * 2 + getPaddingRight() + mCircleWidth * 2);

wSize = computeSize < wSize ? computeSize : wSize;

break;

case MeasureSpec.UNSPECIFIED:

//自由发挥

computeSize = (int) (getPaddingLeft() + mRadius * 2 + mGapBetweenCircle + mRadius * 2 + getPaddingRight() + mCircleWidth * 2);

wSize = computeSize;

break;

}

switch (hMode) {

case MeasureSpec.EXACTLY:

break;

case MeasureSpec.AT_MOST:

int computeSize = (int) (getPaddingTop() + mRadius * 2 + getPaddingBottom() + mCircleWidth * 2);

hSize = computeSize < hSize ? computeSize : hSize;

break;

case MeasureSpec.UNSPECIFIED:

computeSize = (int) (getPaddingTop() + mRadius * 2 + getPaddingBottom() + mCircleWidth * 2);

hSize = computeSize;

break;

}

setMeasuredDimension(wSize, hSize);

//复用时会走这里,所以初始化一些UI显示的参数

mAnimFraction = 0;

initHintSettings();

}

/**

  • 根据当前count数量 初始化 hint提示语相关变量

*/

private void initHintSettings() {

if (mCount == 0) {

isHintMode = true;

isShowHintText = true;

mAnimExpandHintFraction = 0;

} else {

isHintMode = false;

isShowHintText = false;

mAnimExpandHintFraction = 1;

}

}

在改变count时

一般在onBindViewHolder()或者getView()时,都会对本控件重新设置count值,count改变时,当然也是需要根据count进行属性值的调整。

且此时如果View正在做动画,应该停止这些动画。

/**

  • 设置当前数量

  • @param count

  • @return

*/

public AnimShopButton setCount(int count) {

mCount = count;

//先暂停所有动画

if (mAnimAdd != null && mAnimAdd.isRunning()) {

mAnimAdd.cancel();

}

if (mAniDel != null && mAniDel.isRunning()) {

mAniDel.cancel();

}

//复用机制的处理

if (mCount == 0) {

// 0 不显示 数字和-号

mAnimFraction = 1;

} else {

mAnimFraction = 0;

}

initHintSettings();

return this;

}

总结

代码传送门:喜欢的话,随手点个star。多谢

https://github.com/mcxtzhang/AnimShopButton

经济上支持我 or 想通过视频看我是怎么实现的:

http://edu.csdn.net/course/detail/3898

我在实现这个控件时,觉得难度相对大的地方在于做动画时,“-”按钮和数量的旋转动画,如何确定正确的坐标值。因为将text绘制的居中本身就有一些注意事项在里面,再涉及到动画,难免蒙圈。需要多计算,多试验

还有就是观察饿了么的效果,将hint区域的动画利用改变RoundRect的宽度去实现。起初没有想到,也是思考了一会如何去做。这是属于分析、拆解动画遇到的问题。

除了绘制以外的重点是:

  • 利用Region监听区域点击事件

  • 复用的列表,如何正确显示UI。

  • 动画次序以及考虑到复用时,在合适的地方取消动画

最后

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

资料⬅专栏获取
imFraction = 0;

}

initHintSettings();

return this;

}

总结

代码传送门:喜欢的话,随手点个star。多谢

https://github.com/mcxtzhang/AnimShopButton

经济上支持我 or 想通过视频看我是怎么实现的:

http://edu.csdn.net/course/detail/3898

我在实现这个控件时,觉得难度相对大的地方在于做动画时,“-”按钮和数量的旋转动画,如何确定正确的坐标值。因为将text绘制的居中本身就有一些注意事项在里面,再涉及到动画,难免蒙圈。需要多计算,多试验

还有就是观察饿了么的效果,将hint区域的动画利用改变RoundRect的宽度去实现。起初没有想到,也是思考了一会如何去做。这是属于分析、拆解动画遇到的问题。

除了绘制以外的重点是:

  • 利用Region监听区域点击事件

  • 复用的列表,如何正确显示UI。

  • 动画次序以及考虑到复用时,在合适的地方取消动画

最后

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助

因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。

[外链图片转存中…(img-RbTcTwdo-1719097483595)]一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

资料⬅专栏获取

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/357330.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue3+TypeScript项目实战——打造雨雪交加的智慧城市

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 ⚡开源项目&#xff1a; rich-vue3 &#xff08;基于 Vue3 TS Pinia Element Plus Spring全家桶 MySQL&#xff09; &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1…

将WIN10的wifi上网分享给以太网接口

目录 打开网络设置设置属性点这里的设置将wlan主机的以太网接口IP设为自动获取 如果连接不成功&#xff0c;拔网线重连一次 打开网络设置 设置属性 点这里的设置 将wlan主机的以太网接口IP设为自动获取 如果连接不成功&#xff0c;拔网线重连一次

Interview preparation--elasticSearch倒排索引原理

搜索引擎应该具备哪些要求 查询速度快 优秀的索引结构设计高效率的压缩算法快速的编码和解码速度 结果准确 ElasiticSearch 中7.0 版本之后默认使用BM25 评分算法ElasticSearch 中 7.0 版本之前使用 TP-IDF算法 倒排索引原理 当我们有如下列表数据信息&#xff0c;并且系统…

网易被裁,腾讯面试被怼,幸得字节内推,5面顺利拿下offer

幸好经过师兄的内推拿到了字节跳动的面试机会&#xff0c;最终历经5面斩获了字节跳动&#xff08;抖音Android岗&#xff09;offer&#xff0c;不得不感叹一下自己的工作生涯实在是太顺了。下面简单分享一下我这次5面字节跳动的一个真题情况&#xff0c;希望能够对大家有所帮助…

Redis 学习笔记(2)

目录 1 Redis的持久化1.1 RDB持久化方案1.2 AOF持久化方案 2 Redis架构2.1 主从复制架构2.2 哨兵集群设计2.3 哨兵集群设计 3 Redis事务机制4 Redis过期策略与内存淘汰机制4.1 过期策略4.2 内存淘汰机制 5 Redis高频面试题4.1 缓存穿透4.2 缓存击穿4.3 缓存雪崩 1 Redis的持久化…

Centos 配置安装Mysql

linux安装配置mysql的方法主要有yum安装和配置安装两种&#xff0c;由于yum安装比较简单&#xff0c;但是会将文件分散到不同的目录结构下面&#xff0c;配置起来比较麻烦&#xff0c;这里主要研究一下配置安装mysql的方法 1、环境说明 centos 7.9 mysql 5.7.372、环境检查 …

Day2: 双指针977 滑动窗口209 循环不变量原则59

题目977. 有序数组的平方 - 力扣&#xff08;LeetCode&#xff09; class Solution { public:vector<int> sortedSquares(vector<int>& nums) {int left0;int rightnums.size()-1;vector<int> result(nums.size(),0);int iright;while(left<right){i…

快速生成基于vue-element的后台管理框架,实现短时间二次开发

你是否遇到过当你想要独立开发一个项目时对反复造轮子的烦扰&#xff1f; 这种流水线的操作实在让人受不了 而vue-element-template很好的帮你解决了这个烦恼 只需克隆下来&#xff0c;改改图标&#xff0c;模块名&#xff0c;甚至样式&#xff0c;就会变成一个全新的自己的项目…

Redis进阶 - Redis 淘汰策略

我们知道Redis是分布式内存数据库&#xff0c;基于内存运行&#xff0c;可是有没有想过比较好的服务器内存也不过几百G&#xff0c;能存多少数据呢&#xff0c;当内存占用满了之后该怎么办呢&#xff1f;Redis的内存是否可以设置限制&#xff1f; 过期的key是怎么从内存中删除的…

【独家发布】怎样有效发挥公司现有的资源优势

新上任的汪总发现公司存在管控力度弱、职责不清、职能执行不足等问题&#xff0c;阻碍了公司优势的发挥&#xff0c;因此决定对组织架构进行重新设计&#xff0c;但是&#xff0c;考虑到内部人力资源管理人才缺乏&#xff0c;而且组织架构的调整会涉及到复杂的人事变动和利益调…

Charles抓包工具

一、charles简介 1&#xff0c;charles是什么 Charles中文名叫青花瓷&#xff0c;它是一款基于HTTP协议的代理服务器&#xff0c;通过成为电脑或者浏览器的代理&#xff0c;然后截取请求和请求结果达到分析抓包的目的。 特点:跨平台、半免费 2&#xff0c;charles工作原理 前…

英码科技携手昇腾打造“三位一体”智慧化工解决方案,使能化工产业管理更高效、智能

我国是世界公认的化工大国。然而&#xff0c;大部分化工园区的日常管理方式较为传统&#xff0c;各园区、厂区的门禁、视频、停车场等子系统犹如一个个独立的“岛屿”&#xff0c;每个“岛屿”需要耗费大量人力及时间成本进行巡检、记录、上报&#xff0c;且不能做到全域、全时…

基于matlab的不同边缘检测算子的边缘检测

1 原理 1.1 边缘检测概述 边缘检测是图像处理和计算机视觉中的基本问题&#xff0c;其目的在于标识数字图像中亮度变化明显的点。这些变化通常反映了图像属性的重要事件和变化&#xff0c;如深度不连续、表面方向不连续、物质属性变化和场景照明变化等。边缘检测在特征提取中…

Windows环境利用 OpenCV 中 CascadeClassifier 分类器识别人眼 c++

Windows环境中配置OpenCV 关于在Windows环境中配置opencv的说明&#xff0c;具体可以参考&#xff1a;VS2022 配置OpenCV开发环境详细教程。 CascadeClassifier 分类器 CascadeClassifier 是 OpenCV 库中的一个类&#xff0c;它用于实现一种快速的物体检测算法&#xff0c;称…

AlmaLinux 更换CN镜像地址

官方镜像列表 官方列表&#xff1a;https://mirrors.almalinux.org/CN 开头的站点&#xff0c;不同区域查询即可 一键更改镜像地址脚本 以下是更改从默认更改到阿里云地址 cat <<EOF>>/AlmaLinux_Update_repo.sh #!/bin/bash # -*- coding: utf-8 -*- # Author:…

多功能投票系统(ThinkPHP+FastAdmin+Uniapp)

让决策更高效&#xff0c;更民主&#x1f31f; ​基于ThinkPHPFastAdminUniapp开发的多功能系统&#xff0c;支持图文投票、自定义选手报名内容、自定义主题色、礼物功能(高级授权)、弹幕功能(高级授权)、会员发布、支持数据库私有化部署&#xff0c;Uniapp提供全部无加密源码…

leetcode 二分查找·系统掌握 有效的完全平方数

题目&#xff1a; 题解&#xff1a; 就是一个非常普通的二分查找&#xff0c;但是需要注意的是查找的上下界&#xff0c;因为是完全平方&#xff0c;所以可以把上界设为这个数的一半&#xff0c;但是要特殊处理num等于1的时候。 bool isPerfectSquare(int num) {if(num1)retur…

四川汇聚荣科技有限公司靠谱吗?

在如今这个信息爆炸的时代&#xff0c;了解一家公司是否靠谱对于消费者和合作伙伴来说至关重要。四川汇聚荣科技有限公司作为一家位于中国西部地区的企业&#xff0c;自然也受到了人们的关注。那么&#xff0c;这家公司究竟如何呢?接下来&#xff0c;我们将从多个角度进行深入…

Repetition Improves Language Model Embeddings论文阅读笔记

文章提出了一种提高decoder-only LLM的embedding能力的方法&#xff0c;叫echo embeddingslast-token pooling&#xff08;即直接选最后一个token作为句子的embedding&#xff09;和直接mean pooling都不如文章提出的echo embedding&#xff0c;做法是把句子重复两次&#xff0…

关于微信没有接入鸿蒙NEXT的思考

6月21日,纯血鸿蒙发布,国内的质疑声终于停止,不再被人喊叫换皮 Android 了.就连编程语言都是华为自研的。 可是发布会后微信却成了热点,因为余承东在感谢了一圈互联网企业,如:淘宝、支付宝、美团、京东、抖音、今日头条、钉钉、小红书、微博、B站、高德、WPS等等. 唯独没有感…