Android原生实现控件outline方案(API28及以上)
Android控件的Outline效果的实现方式有很多种,这里介绍一下另一种使用Canvas.drawPath()方法来绘制控件轮廓Path路径的实现方案(API28及以上)。
实现效果:
属性
添加Outline相关属性,主要包括颜色和Stroke宽度:
<declare-styleable name="shape_button">...<attr name="carbon_stroke" /><attr name="carbon_strokeWidth" />
</declare-styleable>
StrokeView接口
创建一个StrokeView通用接口:
/*** 外部轮廓相关*/
public interface StrokeView {ColorStateList getStroke();void setStroke(ColorStateList color);void setStroke(int color);float getStrokeWidth();void setStrokeWidth(float strokeWidth);
}
ShapeButton 实现这个StrokeView接口:
public class ShapeButton extends AppCompatButtonimplements ShadowView,ShapeModelView,RippleView,StrokeView {public ShapeButton(@NonNull Context context) {super(context);initButton(null, android.R.attr.buttonStyle, R.style.carbon_Button);}public ShapeButton(@NonNull Context context, @Nullable AttributeSet attrs) {super(context, attrs);initButton(attrs, android.R.attr.buttonStyle, R.style.carbon_Button);}public ShapeButton(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initButton(attrs, defStyleAttr, R.style.carbon_Button);}public ShapeButton(Context context, String text, OnClickListener listener) {super(context);initButton(null, android.R.attr.buttonStyle, R.style.carbon_Button);setText(text);setOnClickListener(listener);}private static int[] elevationIds = new int[]{R.styleable.shape_button_carbon_elevation,R.styleable.shape_button_carbon_elevationShadowColor,R.styleable.shape_button_carbon_elevationAmbientShadowColor,R.styleable.shape_button_carbon_elevationSpotShadowColor};private static int[] cornerCutRadiusIds = new int[]{R.styleable.shape_button_carbon_cornerRadiusTopStart,R.styleable.shape_button_carbon_cornerRadiusTopEnd,R.styleable.shape_button_carbon_cornerRadiusBottomStart,R.styleable.shape_button_carbon_cornerRadiusBottomEnd,R.styleable.shape_button_carbon_cornerRadius,R.styleable.shape_button_carbon_cornerCutTopStart,R.styleable.shape_button_carbon_cornerCutTopEnd,R.styleable.shape_button_carbon_cornerCutBottomStart,R.styleable.shape_button_carbon_cornerCutBottomEnd,R.styleable.shape_button_carbon_cornerCut};private static int[] rippleIds = new int[]{R.styleable.shape_button_carbon_rippleColor,R.styleable.shape_button_carbon_rippleStyle,R.styleable.shape_button_carbon_rippleHotspot,R.styleable.shape_button_carbon_rippleRadius};private static int[] strokeIds = new int[]{R.styleable.shape_button_carbon_stroke,R.styleable.shape_button_carbon_strokeWidth};protected TextPaint paint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);private void initButton(AttributeSet attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.shape_button, defStyleAttr, defStyleRes);Carbon.initElevation(this, a, elevationIds);Carbon.initCornerCutRadius(this,a,cornerCutRadiusIds);Carbon.initRippleDrawable(this,a,rippleIds);// 初始化Stroke相关属性Carbon.initStroke(this,a,strokeIds);a.recycle();}// -------------------------------// shadow// -------------------------------// -------------------------------// shape// -------------------------------// -------------------------------// ripple// -------------------------------// -------------------------------// stroke// -------------------------------private ColorStateList stroke;private float strokeWidth;private Paint strokePaint;// 绘制轮廓private void drawStroke(Canvas canvas) {strokePaint.setStrokeWidth(strokeWidth * 2);strokePaint.setColor(stroke.getColorForState(getDrawableState(), stroke.getDefaultColor()));// cornersMask这是之前装载控件轮廓的path对象cornersMask.setFillType(Path.FillType.WINDING);canvas.drawPath(cornersMask, strokePaint);}// 设置轮廓颜色@Overridepublic void setStroke(ColorStateList colorStateList) {stroke = colorStateList;if (stroke == null)return;if (strokePaint == null) {strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);strokePaint.setStyle(Paint.Style.STROKE);}}// 设置轮廓颜色@Overridepublic void setStroke(int color) {setStroke(ColorStateList.valueOf(color));}@Overridepublic ColorStateList getStroke() {return stroke;}// 设置轮廓线条宽度@Overridepublic void setStrokeWidth(float strokeWidth) {this.strokeWidth = strokeWidth;}@Overridepublic float getStrokeWidth() {return strokeWidth;}}
初始化Stroke属性
public static void initStroke(StrokeView strokeView, TypedArray a, int[] ids) {int carbon_stroke = ids[0];int carbon_strokeWidth = ids[1];View view = (View) strokeView;ColorStateList color = a.getColorStateList(carbon_stroke);if (color != null)strokeView.setStroke(color);strokeView.setStrokeWidth(a.getDimension(carbon_strokeWidth, 0));}
绘制轮廓
在onDraw()
方法的super.draw(canvas);
后面执行drawStroke()
方法:
public void drawInternal(@NonNull Canvas canvas) {super.draw(canvas);if(stroke!=null){drawStroke(canvas);}}
如何使用
<com.chinatsp.demo1.shadow.ShapeButtonandroid:id="@+id/show_dialog_btn"android:layout_width="wrap_content"android:layout_height="36dp"android:layout_margin="@dimen/carbon_padding"android:background="#ffffff"android:stateListAnimator="@null"android:text="TOM"app:carbon_cornerCut="4dp"app:carbon_elevation="30dp"app:carbon_elevationShadowColor="#40ff0000"app:carbon_rippleColor="#40ff0000"app:carbon_rippleStyle="borderless"app:carbon_rippleRadius="30dp"app:carbon_stroke="@color/carbon_green_400"app:carbon_strokeWidth="1dp"/>
完整代码:
public class ShapeButton extends AppCompatButtonimplements ShadowView,ShapeModelView,RippleView,StrokeView {public ShapeButton(@NonNull Context context) {super(context);initButton(null, android.R.attr.buttonStyle, R.style.carbon_Button);}public ShapeButton(@NonNull Context context, @Nullable AttributeSet attrs) {super(context, attrs);initButton(attrs, android.R.attr.buttonStyle, R.style.carbon_Button);}public ShapeButton(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initButton(attrs, defStyleAttr, R.style.carbon_Button);}public ShapeButton(Context context, String text, OnClickListener listener) {super(context);initButton(null, android.R.attr.buttonStyle, R.style.carbon_Button);setText(text);setOnClickListener(listener);}private static int[] elevationIds = new int[]{R.styleable.shape_button_carbon_elevation,R.styleable.shape_button_carbon_elevationShadowColor,R.styleable.shape_button_carbon_elevationAmbientShadowColor,R.styleable.shape_button_carbon_elevationSpotShadowColor};private static int[] cornerCutRadiusIds = new int[]{R.styleable.shape_button_carbon_cornerRadiusTopStart,R.styleable.shape_button_carbon_cornerRadiusTopEnd,R.styleable.shape_button_carbon_cornerRadiusBottomStart,R.styleable.shape_button_carbon_cornerRadiusBottomEnd,R.styleable.shape_button_carbon_cornerRadius,R.styleable.shape_button_carbon_cornerCutTopStart,R.styleable.shape_button_carbon_cornerCutTopEnd,R.styleable.shape_button_carbon_cornerCutBottomStart,R.styleable.shape_button_carbon_cornerCutBottomEnd,R.styleable.shape_button_carbon_cornerCut};private static int[] rippleIds = new int[]{R.styleable.shape_button_carbon_rippleColor,R.styleable.shape_button_carbon_rippleStyle,R.styleable.shape_button_carbon_rippleHotspot,R.styleable.shape_button_carbon_rippleRadius};private static int[] strokeIds = new int[]{R.styleable.shape_button_carbon_stroke,R.styleable.shape_button_carbon_strokeWidth};protected TextPaint paint = new TextPaint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);private void initButton(AttributeSet attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.shape_button, defStyleAttr, defStyleRes);Carbon.initElevation(this, a, elevationIds);Carbon.initCornerCutRadius(this,a,cornerCutRadiusIds);Carbon.initRippleDrawable(this,a,rippleIds);Carbon.initStroke(this,a,strokeIds);a.recycle();}// -------------------------------// shadow// -------------------------------private float elevation = 0;private float translationZ = 0;private ColorStateList ambientShadowColor, spotShadowColor;@Overridepublic float getElevation() {return elevation;}@Overridepublic void setElevation(float elevation) {if (Carbon.IS_PIE_OR_HIGHER) {super.setElevation(elevation);super.setTranslationZ(translationZ);} else if (Carbon.IS_LOLLIPOP_OR_HIGHER) {if (ambientShadowColor == null || spotShadowColor == null) {super.setElevation(elevation);super.setTranslationZ(translationZ);} else {super.setElevation(0);super.setTranslationZ(0);}} else if (elevation != this.elevation && getParent() != null) {((View) getParent()).postInvalidate();}this.elevation = elevation;}@Overridepublic float getTranslationZ() {return translationZ;}public void setTranslationZ(float translationZ) {if (translationZ == this.translationZ)return;if (Carbon.IS_PIE_OR_HIGHER) {super.setTranslationZ(translationZ);} else if (Carbon.IS_LOLLIPOP_OR_HIGHER) {if (ambientShadowColor == null || spotShadowColor == null) {super.setTranslationZ(translationZ);} else {super.setTranslationZ(0);}} else if (translationZ != this.translationZ && getParent() != null) {((View) getParent()).postInvalidate();}this.translationZ = translationZ;}@Overridepublic ColorStateList getElevationShadowColor() {return ambientShadowColor;}@Overridepublic void setElevationShadowColor(ColorStateList shadowColor) {ambientShadowColor = spotShadowColor = shadowColor;setElevation(elevation);setTranslationZ(translationZ);}@Overridepublic void setElevationShadowColor(int color) {ambientShadowColor = spotShadowColor = ColorStateList.valueOf(color);setElevation(elevation);setTranslationZ(translationZ);}@Overridepublic void setOutlineAmbientShadowColor(ColorStateList color) {ambientShadowColor = color;if (Carbon.IS_PIE_OR_HIGHER) {super.setOutlineAmbientShadowColor(color.getColorForState(getDrawableState(), color.getDefaultColor()));} else {setElevation(elevation);setTranslationZ(translationZ);}}@Overridepublic void setOutlineAmbientShadowColor(int color) {setOutlineAmbientShadowColor(ColorStateList.valueOf(color));}@Overridepublic int getOutlineAmbientShadowColor() {return ambientShadowColor.getDefaultColor();}@Overridepublic void setOutlineSpotShadowColor(int color) {setOutlineSpotShadowColor(ColorStateList.valueOf(color));}@Overridepublic void setOutlineSpotShadowColor(ColorStateList color) {spotShadowColor = color;if (Carbon.IS_PIE_OR_HIGHER) {super.setOutlineSpotShadowColor(color.getColorForState(getDrawableState(), color.getDefaultColor()));} else {setElevation(elevation);setTranslationZ(translationZ);}}@Overridepublic int getOutlineSpotShadowColor() {return ambientShadowColor.getDefaultColor();}@Overridepublic boolean hasShadow() {return false;}@Overridepublic void drawShadow(Canvas canvas) {}@Overridepublic void draw(Canvas canvas) {boolean c = !Carbon.isShapeRect(shapeModel, boundsRect);if (Carbon.IS_PIE_OR_HIGHER) {if (spotShadowColor != null)super.setOutlineSpotShadowColor(spotShadowColor.getColorForState(getDrawableState(), spotShadowColor.getDefaultColor()));if (ambientShadowColor != null)super.setOutlineAmbientShadowColor(ambientShadowColor.getColorForState(getDrawableState(), ambientShadowColor.getDefaultColor()));}// 判断如果不是圆角矩形,需要使用轮廓Path,绘制一下Path,不然显示会很奇怪if (getWidth() > 0 && getHeight() > 0 && ((c && !Carbon.IS_LOLLIPOP_OR_HIGHER) || !shapeModel.isRoundRect(boundsRect))) {int saveCount = canvas.saveLayer(0, 0, getWidth(), getHeight(), null, Canvas.ALL_SAVE_FLAG);drawInternal(canvas);paint.setXfermode(Carbon.CLEAR_MODE);if (c) {cornersMask.setFillType(Path.FillType.INVERSE_WINDING);canvas.drawPath(cornersMask, paint);}canvas.restoreToCount(saveCount);paint.setXfermode(null);}else{drawInternal(canvas);}}public void drawInternal(@NonNull Canvas canvas) {super.draw(canvas);if(stroke!=null){drawStroke(canvas);}if (rippleDrawable != null && rippleDrawable.getStyle() == RippleDrawable.Style.Over)rippleDrawable.draw(canvas);}// -------------------------------// shape// -------------------------------private ShapeAppearanceModel shapeModel = new ShapeAppearanceModel();private MaterialShapeDrawable shadowDrawable = new MaterialShapeDrawable(shapeModel);@Overridepublic void setShapeModel(ShapeAppearanceModel shapeModel) {this.shapeModel = shapeModel;shadowDrawable = new MaterialShapeDrawable(shapeModel);if (getWidth() > 0 && getHeight() > 0)updateCorners();if (!Carbon.IS_LOLLIPOP_OR_HIGHER)postInvalidate();}// View的轮廓形状private RectF boundsRect = new RectF();// View的轮廓形状形成的Path路径private Path cornersMask = new Path();/*** 更新圆角*/private void updateCorners() {if (Carbon.IS_LOLLIPOP_OR_HIGHER) {// 如果不是矩形,裁剪View的轮廓if (!Carbon.isShapeRect(shapeModel, boundsRect)){setClipToOutline(true);}//该方法返回一个Outline对象,它描述了该视图的形状。setOutlineProvider(new ViewOutlineProvider() {@Overridepublic void getOutline(View view, Outline outline) {if (Carbon.isShapeRect(shapeModel, boundsRect)) {outline.setRect(0, 0, getWidth(), getHeight());} else {shadowDrawable.setBounds(0, 0, getWidth(), getHeight());shadowDrawable.setShadowCompatibilityMode(MaterialShapeDrawable.SHADOW_COMPAT_MODE_NEVER);shadowDrawable.getOutline(outline);}}});}// 拿到圆角矩形的形状boundsRect.set(shadowDrawable.getBounds());// 拿到圆角矩形的PathshadowDrawable.getPathForSize(getWidth(), getHeight(), cornersMask);}@Overridepublic ShapeAppearanceModel getShapeModel() {return this.shapeModel;}@Overridepublic void setCornerCut(float cornerCut) {shapeModel = ShapeAppearanceModel.builder().setAllCorners(new CutCornerTreatment(cornerCut)).build();setShapeModel(shapeModel);}@Overridepublic void setCornerRadius(float cornerRadius) {shapeModel = ShapeAppearanceModel.builder().setAllCorners(new RoundedCornerTreatment(cornerRadius)).build();setShapeModel(shapeModel);}@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);if (!changed)return;if (getWidth() == 0 || getHeight() == 0)return;updateCorners();if (rippleDrawable != null)rippleDrawable.setBounds(0, 0, getWidth(), getHeight());}// -------------------------------// ripple// -------------------------------private RippleDrawable rippleDrawable;@Overridepublic boolean dispatchTouchEvent(@NonNull MotionEvent event) {if (rippleDrawable != null && event.getAction() == MotionEvent.ACTION_DOWN)rippleDrawable.setHotspot(event.getX(),event.getY());return super.dispatchTouchEvent(event);}@Overridepublic RippleDrawable getRippleDrawable() {return rippleDrawable;}@Overridepublic void setRippleDrawable(RippleDrawable newRipple) {if (rippleDrawable != null) {rippleDrawable.setCallback(null);if (rippleDrawable.getStyle() == RippleDrawable.Style.Background)super.setBackgroundDrawable(rippleDrawable.getBackground());}if (newRipple != null) {newRipple.setCallback(this);newRipple.setBounds(0, 0, getWidth(), getHeight());newRipple.setState(getDrawableState());((Drawable) newRipple).setVisible(getVisibility() == VISIBLE, false);if (newRipple.getStyle() == RippleDrawable.Style.Background)super.setBackgroundDrawable((Drawable) newRipple);}rippleDrawable = newRipple;}@Overrideprotected void drawableStateChanged() {super.drawableStateChanged();if (rippleDrawable != null && rippleDrawable.getStyle() != RippleDrawable.Style.Background)rippleDrawable.setState(getDrawableState());}@Overrideprotected boolean verifyDrawable(@NonNull Drawable who) {return super.verifyDrawable(who) || rippleDrawable == who;}@Overridepublic void invalidateDrawable(@NonNull Drawable drawable) {super.invalidateDrawable(drawable);invalidateParentIfNeeded();}@Overridepublic void invalidate(@NonNull Rect dirty) {super.invalidate(dirty);invalidateParentIfNeeded();}@Overridepublic void invalidate(int l, int t, int r, int b) {super.invalidate(l, t, r, b);invalidateParentIfNeeded();}@Overridepublic void invalidate() {super.invalidate();invalidateParentIfNeeded();}private void invalidateParentIfNeeded() {if (getParent() == null || !(getParent() instanceof View))return;if (rippleDrawable != null && rippleDrawable.getStyle() == RippleDrawable.Style.Borderless)((View) getParent()).invalidate();}@Overridepublic void setBackground(Drawable background) {setBackgroundDrawable(background);}@Overridepublic void setBackgroundDrawable(Drawable background) {if (background instanceof RippleDrawable) {setRippleDrawable((RippleDrawable) background);return;}if (rippleDrawable != null && rippleDrawable.getStyle() == RippleDrawable.Style.Background) {rippleDrawable.setCallback(null);rippleDrawable = null;}super.setBackgroundDrawable(background);}// -------------------------------// stroke// -------------------------------private ColorStateList stroke;private float strokeWidth;private Paint strokePaint;private void drawStroke(Canvas canvas) {strokePaint.setStrokeWidth(strokeWidth * 2);strokePaint.setColor(stroke.getColorForState(getDrawableState(), stroke.getDefaultColor()));cornersMask.setFillType(Path.FillType.WINDING);canvas.drawPath(cornersMask, strokePaint);}@Overridepublic void setStroke(ColorStateList colorStateList) {stroke = colorStateList;if (stroke == null)return;if (strokePaint == null) {strokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);strokePaint.setStyle(Paint.Style.STROKE);}}@Overridepublic void setStroke(int color) {setStroke(ColorStateList.valueOf(color));}@Overridepublic ColorStateList getStroke() {return stroke;}@Overridepublic void setStrokeWidth(float strokeWidth) {this.strokeWidth = strokeWidth;}@Overridepublic float getStrokeWidth() {return strokeWidth;}}
相关文章:

Android原生实现控件outline方案(API28及以上)
Android控件的Outline效果的实现方式有很多种,这里介绍一下另一种使用Canvas.drawPath()方法来绘制控件轮廓Path路径的实现方案(API28及以上)。 实现效果: 属性 添加Outline相关属性,主要包括颜色和Stroke宽度&…...

ROS学习笔记(六)---服务通信机制
1. 服务通信是什么 在ROS中,服务通信机制是一种点对点的通信方式,用于节点之间的请求和响应。它允许一个节点(服务请求方)向另一个节点(服务提供方)发送请求,并等待响应。 服务通信机制在ROS中…...
常见的C/C++开源QP问题求解器
1. qpSWIFT qpSWIFT 是面向嵌入式和机器人应用的轻量级稀疏二次规划求解器。它采用带有 Mehrotra Predictor 校正步骤和 Nesterov Todd 缩放的 Primal-Dual Interioir Point 方法。 开发语言:C文档:传送门项目:传送门 2. OSQP OSQP&#…...

前端axios发送请求,在请求头添加参数
1.在封装接口传参时,定义形参,params是正常传参,name则是我想要在请求头传参 export function getCurlList (params, name) {return request({url: ********,method: get,params,name}) } 2.接口调用 const res await getCurlList(params,…...

CTF Misc(3)流量分析基础以及原理
前言 流量分析在ctf比赛中也是常见的题目,参赛者通常会收到一个网络数据包的数据集,这些数据包记录了网络通信的内容和细节。参赛者的任务是通过分析这些数据包,识别出有用的信息,例如登录凭据、加密算法、漏洞利用等等 工具安装…...

Telink泰凌微TLSR8258蓝牙开发笔记(二)
在开发过程中遇到了以下问题,记录一下 1.在与ios手机连接后,手机app使能notify,设备与手机通过write和notify进行数据交换,但是在连接传输数据一端时间后,设备收到write命令后不能发出notify命令,打印错误…...
vue3+elementPlus:el-tree复制粘贴数据功能,并且有弹窗组件
在tree控件里添加contextmenu属性表示右键点击事件。 因右键自定义菜单事件需要获取当前点击的位置,所以此处绑定动态样式来控制菜单实时跟踪鼠标右键点击位置。 //html <div class"box-list"><el-tree ref"treeRef" node-key"id…...

JTS:10 Crosses
这里写目录标题 版本点与线点与面线与面线与线 版本 org.locationtech.jts:jts-core:1.19.0 链接: github public class GeometryCrosses {private final GeometryFactory geometryFactory new GeometryFactory();private static final Logger LOGGER LoggerFactory.getLog…...

MySQL中的SHOW FULL PROCESSLIST命令
在MySQL数据库管理中,理解和监控当前正在执行的进程是至关重要的一环。MySQL提供了一系列强大的工具和命令,使得这项任务变得相对容易。其中,SHOW FULL PROCESSLIST命令就是一个非常有用的工具,它可以帮助我们查看MySQL服务器中的…...

VsCode 常见的配置、常用好用插件
1、自动保存:不用装插件,在VsCode中设置一下就行 2、设置ctr滚轮改变字体大小 3、设置选项卡多行展示 这样打开了很多个文件,就不会导致有的打开的文件被隐藏 4、实时刷新网页的插件:LiveServer 5、open in browser 支持快捷键…...

深度学习问答题(更新中)
1. 各个激活函数的优缺点? 2. 为什么ReLU常用于神经网络的激活函数? 在前向传播和反向传播过程中,ReLU相比于Sigmoid等激活函数计算量小;避免梯度消失问题。对于深层网络,Sigmoid函数反向传播时,很容易就…...

JavaScript 笔记: 函数
1 函数声明 2 函数表达式 2.1 函数表达式作为property的value 3 箭头函数 4 构造函数创建函数(不推荐) 5 function 与object 5.1 typeof 5.2 object的操作也适用于function 5.3 区别于⼀般object的⼀个核⼼特征 6 回调函数 callback 7 利用function的pr…...
2023NOIP A层联测9-天竺葵
天竺葵/无法阻挡的子序列/很有味道的题目 我们称一个长度为 k k k 的序列 c c c 是好的,当且仅当对任意正整数 i i i 在 [ 1 , k − 1 ] [1,k-1] [1,k−1] 中,满足 c i 1 > b i c i c_{i1}>b_i \times c_i ci1>bici, …...

react antd table表格点击一行选中数据的方法
一、前言 antd的table,默认是点击左边的单选/复选按钮,才能选中一行数据; 现在想实现点击右边的部分,也可以触发操作选中这行数据。 可以使用onRow实现,样例如下。 二、代码 1.表格样式部分 //表格table样式部分{…...

【VUEX】最好用的传参方式--Vuex的详解
🥳🥳Welcome Huihuis Code World ! !🥳🥳 接下来看看由辉辉所写的关于VuexElementUI的相关操作吧 目录 🥳🥳Welcome Huihuis Code World ! !🥳🥳 一.Vuex是什么 1.定义 2…...
【.net core】yisha框架 SQL SERVER数据库 反向递归查询部门(子查父)
业务service.cs中ListFilter方法中内容 //反向递归查询部门列表List<DepartmentEntity> departmentList await departmentService.GetReverseRecurrenceList(new DepartmentListParam() { Ids operatorInfo.DepartmentId.ToString() });if (departmentList ! null &am…...

java处理时间-去除节假日以及双休日
文章目录 一、建表:activity_holiday_info二、java代码1、ActivitityHolidayController.java2、ActivityHolidayInfoService.java3、ActivityHolidayInfoServiceImpl.java 三、测试效果 有些场景需要计算数据非工作日的情况,eg:统计每个人每月工作日签到…...

快讯|Tubi 有 Rabbit AI 啦
在每月一期的 Tubi 快讯中,你将全面及时地获取 Tubi 最新发展动态,欢迎星标关注【比图科技】微信公众号,一起成长变强! Tubi 推出 Rabbit AI 帮助用户找到喜欢的视频内容 Tubi 于今年九月底推出了 Rabbit AI,这是一项…...
Zookeeper从入门到精通
Zookeeper 是一个开源的分布式协调服务,目前由 Apache 进行维护。Zookeeper 可以用于实现分布式系统中常见的发布/订阅、负载均衡、命令服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。 目录 01-Zookeeper特性与节点数据类型详解02-Z…...

10.11作业
多继承代码实现沙发床 #include <iostream>using namespace std;class Sofa {private:int h;public:Sofa() {cout << "Sofa无参构造" << endl;}Sofa(int h): h(h) {cout << "Sofa有参构造" << endl;}Sofa(const Sofa& …...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...

如何在Windows本机安装Python并确保与Python.NET兼容
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...

麒麟系统使用-进行.NET开发
文章目录 前言一、搭建dotnet环境1.获取相关资源2.配置dotnet 二、使用dotnet三、其他说明总结 前言 麒麟系统的内核是基于linux的,如果需要进行.NET开发,则需要安装特定的应用。由于NET Framework 是仅适用于 Windows 版本的 .NET,所以要进…...
FOPLP vs CoWoS
以下是 FOPLP(Fan-out panel-level packaging 扇出型面板级封装)与 CoWoS(Chip on Wafer on Substrate)两种先进封装技术的详细对比分析,涵盖技术原理、性能、成本、应用场景及市场趋势等维度: 一、技术原…...