【Android】毫无耦合性,一个Item根布局搞定 item侧滑删除菜单,像IOS那样简单的使用侧滑删除。(1)

自定义ViewGroup实现侧滑删除简单,难得是还要同时 处理多指滑动的屏蔽,防止两个侧滑菜单同时出现,等等,

有办法将这些东西都用一个ViewGroup搞定么?

看本文如何巧用static类变量来解决这些矛盾冲突。

==================================================================================

【2 预览】

那么我们先看一下最终的效果:

非阻塞式Android特色版本(我司自用版本 ) 平滑滚动动画用属性动画实现 ,即使有一个侧滑菜单处于打开状态,在打开其他item侧滑菜单时,依然无阻塞,会自动关闭上次开启的菜单:~

为了满足个别产品的,高仿IOS版本 平滑滚动用Scroller实现 阻塞式交互(自己的说法) 打开了某个侧滑菜单后 点击其他地方会自动关闭这个侧滑菜单 并且不能做其他操作 :

包含且不仅包含以下功能:

1 侧滑拉出菜单。

2 点击除了这个item的其他位置,菜单关闭。

3 侧滑过程中,不许父控件上下滑动。

4 多指同时滑动,屏蔽后触摸的几根手指。

5 不会同时展开两个侧滑菜单。

6 侧滑菜单时 拦截了长按事件。

7 侧滑时,拦截了点击事件(20160905更新)

8 通过开关 isLeftSwipe支持左滑右滑(2016 09 30 更新):

**

**

==================================================================================

【3 使用预览】

看起来还不错吧,忽略颜值,可以再细调,主要的是解决了那几个难题,那么,使用起来麻烦么。

<mcxtzhang.listswipemenudemo.view.CstSwipeDelMenuViewGroup xmlns:android=“http://schemas.android.com/apk/res/android”

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:clickable=“true”>

<TextView android:id=“@+id/content”

android:layout_width=“wrap_content”

android:layout_height=“match_parent”

android:gravity=“center”

android:text=“试试看” />

<Button android:id=“@+id/btnDelete”

android:layout_width=“60dp”

android:layout_height=“match_parent”

android:background=“@color/red_ff4a57”

android:text=“删除” />

</mcxtzhang.listswipemenudemo.view.CstSwipeDelMenuViewGroup>

就这么简单,

只需要在 侧滑删除的item的layout的xml里,将根布局父控件换成我们的自定义ViewGroup即可。

第一个子View放置item的内容即可(正式项目里一般是一个ViewGroup),

从2+子View开始,是我们的侧滑菜单区域,如我们的demo图,是三个Button。

//注意事项,设置item点击,不能对整个holder.itemView设置咯,只能对第一个子View,即原来的content设置,这算是局限性吧。

(holder.content).setOnClickListener(new View.OnClickListener() {

@Override

public void onClick(View v) {

Toast.makeText(mContext, “”+mDatas.get(position).name, Toast.LENGTH_SHORT).show();

}

});

==================================================================================

【4 实现方法】

使用起来这么简单,让我们一步一步实现它吧。

首先说的是,颜值非本文的重点,UI动画仍有调整空间,重要的是在一个自定义ViewGroup里处理那些冲突。

首先,本类继承自ViewGroup,那么onMeasure()和onLayout()方法,就需要我们自己动手写了,而且在上文我们也提到,使用时,第一个子View放置item内容,2+子View为侧滑菜单区域,那么这需要我们在onMeasure()和onLayout()方法里进行一些特殊处理,设置第一个childView宽度为全屏。

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

//Log.d(TAG, "onMeasure() called with: " + “widthMeasureSpec = [” + widthMeasureSpec + “], heightMeasureSpec = [” + heightMeasureSpec + “]”);

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

mRightMenuWidths = 0;//由于ViewHolder的复用机制,每次这里要手动恢复初始值

int childCount = getChildCount();

//add by 2016 08 11 为了子View的高,可以matchParent(参考的FrameLayout 和LinearLayout的Horizontal)

final boolean measureMatchParentChildren = MeasureSpec.getMode(heightMeasureSpec) != MeasureSpec.EXACTLY;

boolean isNeedMeasureChildHeight = false;

for (int i = 0; i < childCount; i++) {

View childView = getChildAt(i);

if (childView.getVisibility() != GONE) {

//measureChild(childView, widthMeasureSpec, heightMeasureSpec);

measureChildWithMargins(childView, widthMeasureSpec, 0, heightMeasureSpec, 0);

final MarginLayoutParams lp = (MarginLayoutParams) childView.getLayoutParams();

mHeight = Math.max(mHeight, childView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);

if (measureMatchParentChildren && lp.height == LayoutParams.MATCH_PARENT) {

isNeedMeasureChildHeight = true;

}

if (i > 0) {//第一个布局是Left item,从第二个开始才是RightMenu

mRightMenuWidths += childView.getMeasuredWidth();

}

}

}

setMeasuredDimension(mScreenW, mHeight);//宽度取屏幕宽度

mLimit = mRightMenuWidths * 4 / 10;//滑动判断的临界值

//Log.d(TAG, "onMeasure() called with: " + “mRightMenuWidths = [” + mRightMenuWidths); if (isNeedMeasureChildHeight) {//如果子View的height有MatchParent属性的,设置子View高度

forceUniformHeight(childCount, widthMeasureSpec);

}

}

/**

* 给MatchParent的子View设置高度 * * @param count

* @param widthMeasureSpec

* @see android.widget.LinearLayout# 同名方法

*/

private void forceUniformHeight(int count, int widthMeasureSpec) {

// Pretend that the linear layout has an exact size. This is the measured height of

// ourselves. The measured height should be the max height of the children, changed // to accommodate the heightMeasureSpec from the parent int uniformMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredHeight(),

MeasureSpec.EXACTLY);//以父布局高度构建一个Exactly的测量参数

for (int i = 0; i < count; ++i) {

final View child = getChildAt(i);

if (child.getVisibility() != GONE) {

MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

if (lp.height == LayoutParams.MATCH_PARENT) {

// Temporarily force children to reuse their old measured width

// FIXME: this may not be right for something like wrapping text?

int oldWidth = lp.width;//measureChildWithMargins 这个函数会用到宽,所以要保存一下

lp.width = child.getMeasuredWidth();

// Remeasure with new dimensions

measureChildWithMargins(child, widthMeasureSpec, 0, uniformMeasureSpec, 0);

lp.width = oldWidth;

}

}

}

}

@Override

protected void onLayout(boolean changed, int l, int t, int r, int b) {

//LogUtils.d(TAG, "onLayout() called with: " + “changed = [” + changed + “], l = [” + l + “], t = [” + t + “], r = [” + r + “], b = [” + b + “]”);

int childCount = getChildCount();

int left = l;

for (int i = 0; i < childCount; i++) {

View childView = getChildAt(i);

if (childView.getVisibility() != GONE) {

if (i == 0) {//第一个子View是内容 宽度设置为全屏

childView.layout(left, getPaddingTop(), left + mScreenW, getPaddingTop() + childView.getMeasuredHeight());

left = left + mScreenW;

} else {

childView.layout(left, getPaddingTop(), left + childView.getMeasuredWidth(), getPaddingTop() + childView.getMeasuredHeight());

left = left + childView.getMeasuredWidth();

}

}

}

//Log.d(TAG, "onLayout() called with: " + “maxScrollGap = [” + maxScrollGap + “], l = [” + l + “], t = [” + t + “], r = [” + r + “], b = [” + b + “]”);

}

onMeasure()的时候,保存右侧菜单区域的宽度(这个值同时也是滑动的最大距离),然后调用setMeasuredDimension(),分别传入屏幕的宽度,和计算出的高度。这里还加了一些额外的代码了是为了让自定义的ViewGroup,在子View的height设置为match_parent的情况下,height正确,否则子View设置match_parent的效果是wrap_content,这些代码参考了源码FrameLayout和LinearLayout的Horizontal模式。

由于我们希望子View的LayoutParams是MarginLayoutParams,需要如下重写generateLayoutParams()这个方法。

@Override

public LayoutParams generateLayoutParams(AttributeSet attrs) {

return new MarginLayoutParams(getContext(), attrs);

}

以上是准备工作,下面是让我们的item可以侧滑起来并且在其中解决多指同时触摸 以及 多个侧滑menu同时显示的问题。

我这里重写的是dispatchTouchEvent()方法,目的就是为了好处理多指滑动等冲突。

@Override

public boolean dispatchTouchEvent(MotionEvent ev) {

//LogUtils.d(TAG, "dispatchTouchEvent() called with: " + “ev = [” + ev + “]”);

if (isSwipeEnable) {

acquireVelocityTracker(ev);

final VelocityTracker verTracker = mVelocityTracker;

switch (ev.getAction()) {

case MotionEvent.ACTION_DOWN:

if (isTouching) {//如果有别的指头摸过了,那么就return false。这样后续的move…等事件也不会再来找这个View了。

return false;

} else {

isTouching = true;//第一个摸的指头,赶紧改变标志,宣誓主权。

}

mLastP.set(ev.getRawX(), ev.getRawY());

//如果down,view和cacheview不一样,则立马让它还原。且把它置为null

if (mViewCache != null) {

if (mViewCache != this) {

mViewCache.smoothClose();

mViewCache = null;

}

//只要有一个侧滑菜单处于打开状态, 就不给外层布局上下滑动了

getParent().requestDisallowInterceptTouchEvent(true);

}

//求第一个触点的id, 此时可能有多个触点,但至少一个,计算滑动速率用

mPointerId = ev.getPointerId(0);

break; case MotionEvent.ACTION_MOVE:

float gap = mLastP.x - ev.getRawX();

//为了在水平滑动中禁止父类ListView等再竖直滑动

if (gap > ViewConfiguration.get(getContext()).getScaledTouchSlop()) {

getParent().requestDisallowInterceptTouchEvent(true);

}

//如果scroller还没有滑动结束 停止滑动动画

/* if (!mScroller.isFinished()) {

mScroller.abortAnimation(); }*/ scrollBy((int) (gap), 0);//滑动使用scrollBy

//修正 if (getScrollX() < 0) {

scrollTo(0, 0);

}

if (getScrollX() > mRightMenuWidths) {

scrollTo(mRightMenuWidths, 0);

}

mLastP.set(ev.getRawX(), ev.getRawY());

break; case MotionEvent.ACTION_UP:

case MotionEvent.ACTION_CANCEL:

//求伪瞬时速度

verTracker.computeCurrentVelocity(1000, mMaxVelocity);

final float velocityX = verTracker.getXVelocity(mPointerId);

if (Math.abs(velocityX) > 1000) {//滑动速度超过阈值

if (velocityX < -1000) {

//平滑展开Menu

smoothExpand();

//展开就加入ViewCache:

mViewCache = this;

} else {

//平滑关闭Menu

smoothClose();

}

} else {

if (getScrollX() > mLimit) {//否则就判断滑动距离

//平滑展开Menu smoothExpand();

//展开就加入ViewCache:

mViewCache = this;

} else {

//平滑关闭Menu

smoothClose();

}

}

//释放

releaseVelocityTracker();

//LogUtils.i(TAG, “onTouch A ACTION_UP ACTION_CANCEL:velocityY:” + velocityX);

isTouching = false;//没有手指在摸我了

break;

default:

break;

}

}

return super.dispatchTouchEvent(ev);

}

VelocityTracker相关代码是为了计算手指滑动的速度,帮助我们在手指抬起时判断,确定当前item是展开还是收缩,令UI更友好。

首先看case MotionEvent.ACTION_DOWN:

在手指按下时,我们用一个 布尔值 static类变量存储当前是否有手指在触摸该ViewGroup,

//防止多只手指一起滑我的flag 在每次down里判断, touch事件结束清空

private static boolean isTouching;

之所以用类变量,是因为一个类里它是唯一的,所以在RecyclerView,ListView里,即使一个屏幕上有多个item,但是他们的isTouching的变量是同一个,这样便能达到控制单指触摸的目的。所以控制单侧滑菜单出现也是同理。后面会提到。

boolean变量,默认值是false,所以当出现两指同时触摸时(同时触摸其实还是有先后的),第一个触摸的指头在down事件里,就将isTouching改变为true,这样后续赶到的那个指头所在的ViewGroup 的down事件里 isTouching就是true了,在dispatchTouchEven()t里就会被return false,这样后续的事件它统统接收不到了。就这么简单就解决了多指触摸的问题。(ACTION_DOWN也没有往子View分发,后续所有事件自己和子View都接收不到了)。

然后正常流程往下,我们先存储一下当前触摸点的x y 坐标,然后判断viewCache变量是否为空。

viewCache变量也是一个类变量,全局就这一份,存储的是全局处于展开状态的那个View对象。

如果它不为空,说明已经有一个侧滑菜单在展开了,那么我们判断一下,是否是this,即自己这个View,那么忽略,如果不是自己,那么就将那个处于展开状态的View的侧滑菜单关闭。并将viewCache置空,同时只要有一个侧滑菜单在展开了,我们都剥夺父控件处理TouchEvent的权利。

//存储的是当前正在展开的View

private static CstSwipeDelMenuViewGroup mViewCache;

然后看case MotionEvent.ACTION_MOVE:

我们先通过当前的x值和我们保存的上次的x左边值,计算这次滑动的距离gap。

如果gap大于系统认定的滑动阈值(通过 ViewConfiguration.get(getContext()).getScaledTouchSlop() 得到),则说明是水平方向的侧滑动作,那么也剥夺父控件处理TouchEvent的权利。

然后调用View的scrollBy()方法,滑动我们自定义的ViewGroup的所有子View

滑动后需要判断是否越界,需要修正一下,这里用到了我们在onMeasure时保存的侧滑菜单的宽度。

最后我们将此时的x,y坐标保存一下。

scrollBy方法,很多人容易懵逼,可以简单的记一下结论,不是本文重点暂不深究,像让子View 向左 向上滑,传入正值,向 右 向下滑,传负值。

最后看 case MotionEvent.ACTION_UP:和case MotionEvent.ACTION_CANCEL:

注意的是,一定要加上ACTION_CANCEL,不要仅仅判断ACTION_UP。

因为在一些情况下,例如当你的手指一直触摸 从屏幕边缘,离开了屏幕,只会出发CANCEL不会出发UP事件,即当用户保持按下操作,并从你的控件转移到外层控件时,会触发ACTION_CANCEL。

这里的操作就是,根据手指滑动速率,判断手指离开、取消时的动作,是关上侧滑菜单,还是展开侧滑菜单。如果是展开侧滑菜单的操作,要将viewCache设置为this,

同时在最后要将isTouching设置为false,因为此时已经没有人在摸你啦。别忘记释放VelocityTracker~

关于平滑展开smoothExpand() 和平滑关闭smoothClose()方法如下:

/**

* 平滑展开 */ public void smoothExpand() {

/*mScroller.startScroll(getScrollX(), 0, mRightMenuWidths - getScrollX(), 0);

invalidate();*/ ValueAnimator valueAnimator = ValueAnimator.ofInt(getScrollX(), mRightMenuWidths);

valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

scrollTo((Integer) animation.getAnimatedValue(), 0);

}

});

valueAnimator.setInterpolator(new OvershootInterpolator());

valueAnimator.setDuration(300).start();

}

/**

* 平滑关闭 */ public void smoothClose() {

/* mScroller.startScroll(getScrollX(), 0, -getScrollX(), 0);

invalidate();*/ ValueAnimator valueAnimator = ValueAnimator.ofInt(getScrollX(), 0);

valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

scrollTo((Integer) animation.getAnimatedValue(), 0);

}

});

valueAnimator.setInterpolator(new AnticipateInterpolator());

valueAnimator.setDuration(300).start();

//LogUtils.d(TAG, "smoothClose() called with:getScrollX() " + getScrollX());

}

一开始我用的是scroller做的,后来发现属性动画的 OvershootInterpolator   AnticipateInterpolator 貌似更酷炫一些,就改了一下,这都不重要~

获取加速度 和释放的函数:

/**

* @param event 向VelocityTracker添加MotionEvent

* @see VelocityTracker#obtain()

* @see VelocityTracker#addMovement(MotionEvent)

*/

private void acquireVelocityTracker(final MotionEvent event) {

if (null == mVelocityTracker) {

mVelocityTracker = VelocityTracker.obtain();

}

mVelocityTracker.addMovement(event);

}

/**

* * 释放VelocityTracker * * @see android.view.VelocityTracker#clear()

* @see android.view.VelocityTracker#recycle()

*/

private void releaseVelocityTracker() {

if (null != mVelocityTracker) {

mVelocityTracker.clear();

mVelocityTracker.recycle();

mVelocityTracker = null;

}

}

==================================================================================

【5 一些不能忘的事】

由于我们使用的是类静态变量存储的处于展开状态的View,所以我们需要在恰当的时机释放它,否则恭喜你就会内存泄漏啦

释放时机呢,我选在onDetachedFromWindow()这里函数里,每次当View从屏幕上移除会回调这个函数,在其中我们判断,ViewCache是不是等于自己,如果是,那么关闭侧滑菜单,同时将viewCache赋值null。注释也蛮详细的~

//每次ViewDetach的时候,判断一下 ViewCache是不是自己,如果是自己,关闭侧滑菜单,且ViewCache设置为null,

// 理由:1 防止内存泄漏(ViewCache是一个静态变量)

// 2 侧滑删除后自己后,这个View被Recycler回收,复用,下一个进入屏幕的View的状态应该是普通状态,而不是展开状态。

@Override

protected void onDetachedFromWindow() {

if (this == mViewCache) {

mViewCache.smoothClose();

mViewCache = null;

}

super.onDetachedFromWindow();

}

前面不是提到一个展开时,还禁止了长按么,在如下方法里判断,如果getScrollX大于0,说明已经侧滑了一点点,那么就return,屏蔽长按就好啦,如果这个方法你没见过,那么我告诉你其实我也是才看见的,因为下午在做侧滑删除的时候,产品还让我加上长按删除,结果出现了一个小冲突,侧滑的时候同时长按,就会触发长按事件,我觉得要处理一下,就看了一下setOnLongClickListener的源码,顺藤摸瓜,几分钟就可以找到,就不细说啦。

//展开时,禁止长按

@Override

public boolean performLongClick() {

if (getScrollX() > 0) {

return false;

}

return super.performLongClick();

}

20160905 新增

另外附上侧滑时,单击事件的屏蔽,之前忘了补充(代码可以在github上下载)

侧滑时,拦截了点击事件

增加一个变量存储scaleTouchSlop,这个值是系统定义的,超过这个值即判断此次动作是在滑动。我们利用这个值判断是否处于侧滑。

private int mScaleTouchSlop;//为了处理单击事件的冲突

mScaleTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();

要拦截点击事件,就是在ACTION_UP里判断,当前处于侧滑状态,并且落点是在内容区域,才返回true,事件不再分发给子View:

如果落点在侧滑菜单区域,是可以点击的。

@Override

public boolean onInterceptTouchEvent(MotionEvent ev) {

switch (ev.getAction()) {

case MotionEvent.ACTION_UP:

//为了在侧滑时,屏蔽子View的点击事件

if (getScrollX() > mScaleTouchSlop) {

//add by 2016 09 10 解决一个智障问题~ 居然不给点击侧滑菜单 我跪着谢罪

//这里判断落点在内容区域屏蔽点击,内容区域外,允许传递事件继续向下的的。。。 if (ev.getX() < getWidth() - getScrollX()) {

return true;//true表示拦截

}

}

break;

}

return super.onInterceptTouchEvent(ev);

}

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

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

img

img

img

img

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

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

在这里我和身边一些朋友特意整理了一份快速进阶为Android高级工程师的系统且全面的学习资料。涵盖了Android初级——Android高级架构师进阶必备的一些学习技能。

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!

天花板技术停滞不前!**

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

[外链图片转存中…(img-XlGE5ANL-1712309839642)]

[外链图片转存中…(img-2B7BiL8R-1712309839642)]

[外链图片转存中…(img-gA0p4DuX-1712309839643)]

[外链图片转存中…(img-3dV2eq67-1712309839643)]

[外链图片转存中…(img-q6hEWT3S-1712309839643)]

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

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

最后

在这里我和身边一些朋友特意整理了一份快速进阶为Android高级工程师的系统且全面的学习资料。涵盖了Android初级——Android高级架构师进阶必备的一些学习技能。

附上:我们之前因为秋招收集的二十套一二线互联网公司Android面试真题(含BAT、小米、华为、美团、滴滴)和我自己整理Android复习笔记(包含Android基础知识点、Android扩展知识点、Android源码解析、设计模式汇总、Gradle知识点、常见算法题汇总。)

[外链图片转存中…(img-manY2kiA-1712309839644)]

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!

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

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

相关文章

真快乐APP抢购源码实现

支持多个平台的自动 滑动验证码、选字验证码。缺点就是需要自己找一个验证码识别服务器,可以自己用python写一个,或者使用超级鹰(本篇教程就是使用它) 下面是实现源码 "ui"; Date.prototype.Format = function (fmt) {var o = {"M+": this.getMonth() …

2024年做抖音小店商家,最不该忽视的三个运营要点,一定要避开!

大家好&#xff0c;我是电商花花。 每一次平台规则的改变都深深的影响着我们无货源商家&#xff0c;我们只有在规则内行使&#xff0c;遵守规则&#xff0c;才能在安然无恙。 所以我们做抖音小店一定要及时关注平台的规则变化&#xff0c;以及整体的做店趋势。 只有这样才不…

App.vue触发axios报错及解决方案

App.vue触发axios报错及解决方案 修改根目录下vue.config.js文件 module.exports {publicPath: ./,assetsDir: assets,configureWebpack: {devServer: {client: {overlay: false}}} }重新npm run dev 搞定

十个排序算法

目录 冒泡排序(Bubble Sort) 选择排序(Select Sort) 插入排序&#xff08;InsertSort&#xff09; 希尔排序&#xff08;ShellSort&#xff09; 计数排序&#xff08;CountSort&#xff09; 快速排序&#xff08;QuickSort&#xff09; 归并排序&#xff08;Merge Sort&a…

Jenkins 安装部署

1、安装下载 官网地址&#xff1a;Jenkins 下载 war 包 1、前置环境 JDK 环境&#xff08;根据 Jenkins 版本不同&#xff0c;需要的 JDK 版本不同&#xff0c;目前需要 JDK11 的版本来支持&#xff09;Maven maven 官网下载压缩包 &#xff0c;并将其传输到服务器&#xf…

【热门话题】计算机视觉入门:探索数字世界中的“视觉智能”

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 计算机视觉入门&#xff1a;探索数字世界中的“视觉智能”摘要正文一、计算机视…

scoped原理及使用

一、什么是scoped&#xff0c;为什么要用 在vue文件中的style标签上&#xff0c;有一个特殊的属性&#xff1a;scoped。 当一个style标签拥有scoped属性时&#xff0c;它的CSS样式就只能作用于当前的组件&#xff0c;通过该属性&#xff0c;可以使得组件之间的样式不互相污染。…

重构智能防丢产品,苹果Find My技术引领市场发展

目前市场上最主要的防丢技术是蓝牙防丢和GPS防丢&#xff0c;蓝牙防丢是通过感应防丢器与绑定手机的距离来实现防丢的。一般防丢会默认设置一个最远安全距离&#xff0c;超过这个安全距离后&#xff0c;与手机蓝牙信号断开&#xff0c;触发防丢报警&#xff0c;用户根据防丢报警…

Shell GPT:直接安装使用的chatgpt应用软件

ShellGPT是一款基于预训练生成式Transformer模型&#xff08;如GPT系列&#xff09;构建的智能Shell工具。它将先进的自然语言处理能力集成到Shell环境中&#xff0c;使用户能够使用接近日常对话的语言来操作和控制操作系统。 官网&#xff1a;GitHub - akl7777777/ShellGPT: *…

深度学习理论基础(三)封装数据集及手写数字识别

目录 前期准备一、制作数据集1. excel表格数据2. 代码 二、手写数字识别1. 下载数据集2. 搭建模型3. 训练网络4. 测试网络5. 保存训练模型6. 导入已经训练好的模型文件7. 完整代码 前期准备 必须使用 3 个 PyTorch 内置的实用工具&#xff08;utils&#xff09;&#xff1a; ⚫…

TXT文本高效编辑神器,教你进行隔行删除不需要的内容,轻松整理文本内容。

在信息爆炸的时代&#xff0c;我们每天都会接触到大量的文本信息&#xff0c;无论是工作中的报告、邮件&#xff0c;还是生活中的读书笔记、备忘录&#xff0c;都需要我们对文本进行高效的管理和编辑。然而&#xff0c;传统的文本编辑方式往往繁琐低效&#xff0c;无法满足我们…

PTA L2-048 寻宝图

给定一幅地图&#xff0c;其中有水域&#xff0c;有陆地。被水域完全环绕的陆地是岛屿。有些岛屿上埋藏有宝藏&#xff0c;这些有宝藏的点也被标记出来了。本题就请你统计一下&#xff0c;给定的地图上一共有多少岛屿&#xff0c;其中有多少是有宝藏的岛屿。 输入格式&#xf…

LeetCode练习题--567.字符串的排列

今天讲一个非常经典的滑动窗口的问题 这道题的意思很明显: 给你两个字符串s1与s2,判断s2中是否存在一个子串:它包含s1中所有字符且不包含其他字符 让我们先来写一下滑动窗口的模板: /*** 滑动窗口模板 * param s1 * param s2 */public static void model (String s1, String s2…

51单片机入门:认识开发板

认识开发板 板载资源&#xff1a; 数码管模块 说明&#xff1a; 2个四位一体共阴数码管 详细&#xff1a; 2个四位一体&#xff1a;两个独立的四位数码管&#xff0c;每个四位数码管都是“一体”的设计&#xff0c;也就是说&#xff0c;每个数码管内部集成了四个独立的七段LE…

HTTPS跟HTTP有区别吗?

HTTPS和HTTP的区别&#xff0c;白话一点说就是&#xff1a; 1. 安全程度&#xff1a; - HTTP&#xff1a;就像是你和朋友面对面聊天&#xff0c;说的话大家都能听见&#xff08;信息明文传输&#xff0c;容易被偷听&#xff09;。 - HTTPS&#xff1a;就像是你们俩戴着加密耳机…

论大数据服务化发展史

引言 一直想写一篇服务化相关的文章&#xff0c;那就别犹豫了现在就开始吧 正文 作为大数据基础架构工程师&#xff0c;业界也笑称“运维Boy”&#xff0c;日常工作就是在各个机器上部署以及维护服务&#xff0c;例如部署Hadoop、Kafka、Pulsar这些等等&#xff0c;用于给公…

InternLM2-lesson2笔记

书生浦语大模型趣味 Demo 视频连接&#xff1a;https://www.bilibili.com/video/BV1AH4y1H78d/?vd_source902e3124d4683c41b103f1d1322401fa 目录 书生浦语大模型趣味 Demo课程总览SIG项目Demo部署的一般流程存在的问题总结 课程总览 InternLM2-chat-1.8B部署八戒-chat-1.8B…

【css】文本过长溢出一行不换行普通css以及antd实现

.text-box { white-space: nowrap; /* 防止文字换行 */ overflow: hidden; /* 隐藏超出div的内容 */ text-overflow: ellipsis; /* 当内容超出时&#xff0c;显示省略号 */ max-width: calc(100% - 80px); /* 假设按钮宽度为80px&#xff0c;则设置div的最大宽度为容器宽度…

Mysql索引总结(1)

文章目录 InnoDB索引与MyISAM索引实现的区别是什么&#xff1f;一个表中如果没有创建索引&#xff0c;那么还会创建B树吗&#xff1f;B树索引实现原理&#xff08;数据结构&#xff09; InnoDB索引与MyISAM索引实现的区别是什么&#xff1f; MyISAM的索引方式都是非聚簇的&…

07-app端文章搜索

app端文章搜索 1) 今日内容介绍 1.1)App端搜索-效果图 1.2)今日内容 文章搜索 ElasticSearch环境搭建 索引库创建 文章搜索多条件复合查询 索引数据同步 搜索历史记录 Mongodb环境搭建 异步保存搜索历史 查看搜索历史列表 删除搜索历史 联想词查询 联想词的来源 联…