Material Design系列探究之LinearLayoutCompat

在这里插入图片描述

谷歌Material Design推出了许多非常好用的控件,所以我决定写一个专题来讲述MaterialDesign,今天带来Material Design系列的第一弹 LinearLayoutCompat。

以前要在LinearLayout布局之间的子View之间添加分割线,还需要自己去自定义控件进行添加或者就是在子View之间写很多个TextView,但是谷歌已经给我们提供了这样一个组件,可以很轻松的解决分割线的问题,妈妈再也不用担心分割线问题啦,这个组件就是Material Design中的 LinearLayoutCompat。本篇博客将会从以下两个方面来对LinearLayoutCompat进行介绍:

\1. LinearLayoutCompat的使用

\2. LinearLayoutCompat的源码分析

LinearLayoutCompat的使用

LinearLayoutCompat位于support-v7包中,LinearLayoutCompat其实就是LinerLayout组件,只是为了兼容低版本,所以你必须的引用 V7包下面的LinearLayoutCompat。 LinearLayoutCompat除了拥有LinerLayout原本的属性之外,主要有如下几种属性来实现间隔线效果。

当然使用LinearLayoutCompat需要自定义命名空间xmlns:app=”http://schemas.android.com/apk/res-auto”

app:divider=”@drawable/line”给分隔线设置自定义的drawable,这里你需要在drawable在定义shape资源,否则将没有效果。

app:dividerPadding 给分隔线设置距离左右边距的距离。

app:showDividers="beginning|middle|end"属性。 beginning,middle,end属性值分别指明将在何处添加分割线。 beginning表示从该LinearLayoutCompat布局的最顶一个子view的顶部开始。 middle表示在此LinearLayoutCompat布局内的子view之间添加。 end表示在此LinearLayoutCompat最后一个子view的底部添加分割线。

none表示不设置间隔线。

使用LinearLayoutCompat可以很方便的就做出微信的发现界面:

img

布局的代码如下:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@color/gray"android:gravity="top"tools:context="com.example.linearlayoutcompatdemo.MainActivity" ><!-- <android.support.v7.widget.LinearLayoutCompat --><android.support.v7.widget.LinearLayoutCompatandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginTop="30dp"android:background="@color/white"android:gravity="center"android:orientation="vertical"app:divider="@drawable/line"app:dividerPadding="1dp"app:showDividers="middle|beginning|end" ><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingBottom="10dip"android:paddingLeft="5dip"android:paddingTop="10dip" ><ImageViewandroid:layout_width="35dp"android:layout_height="35dp"android:scaleType="fitCenter"android:src="@drawable/find_more_friend_photograph_icon" /><TextViewandroid:layout_width="wrap_content"android:layout_height="fill_parent"android:layout_marginLeft="10dp"android:gravity="center"android:text="朋友圈"android:textColor="@color/black"android:textSize="15dip" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingBottom="10dip"android:paddingLeft="5dip"android:paddingTop="10dip" ><ImageViewandroid:layout_width="35dp"android:layout_height="35dp"android:scaleType="fitCenter"android:src="@drawable/find_more_friend_scan" /><TextViewandroid:layout_width="wrap_content"android:layout_height="fill_parent"android:layout_marginLeft="10dp"android:gravity="center"android:text="扫一扫"android:textColor="@color/black"android:textSize="15dip" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingBottom="10dip"android:paddingLeft="5dip"android:paddingTop="10dip" ><ImageViewandroid:layout_width="35dp"android:layout_height="35dp"android:scaleType="fitCenter"android:src="@drawable/find_more_friend_shake" /><TextViewandroid:layout_width="wrap_content"android:layout_height="fill_parent"android:layout_marginLeft="10dp"android:gravity="center"android:text="摇一摇"android:textColor="@color/black"android:textSize="15dip" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingBottom="10dip"android:paddingLeft="5dip"android:paddingTop="10dip" ><ImageViewandroid:layout_width="35dp"android:layout_height="35dp"android:scaleType="fitCenter"android:src="@drawable/find_more_friend_near_icon" /><TextViewandroid:layout_width="wrap_content"android:layout_height="fill_parent"android:layout_marginLeft="10dp"android:gravity="center"android:text="附近的人"android:textColor="@color/black"android:textSize="15dip" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingBottom="10dip"android:paddingLeft="5dip"android:paddingTop="10dip" ><ImageViewandroid:layout_width="35dp"android:layout_height="35dp"android:scaleType="fitCenter"android:src="@drawable/find_more_friend_bottle" /><TextViewandroid:layout_width="wrap_content"android:layout_height="fill_parent"android:layout_marginLeft="10dp"android:gravity="center"android:text="漂流瓶"android:textColor="@color/black"android:textSize="15dip" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingBottom="10dip"android:paddingLeft="5dip"android:paddingTop="10dip" ><ImageViewandroid:layout_width="35dp"android:layout_height="35dp"android:scaleType="fitCenter"android:src="@drawable/more_game" /><TextViewandroid:layout_width="wrap_content"android:layout_height="fill_parent"android:layout_marginLeft="10dp"android:gravity="center"android:text="游戏"android:textColor="@color/black"android:textSize="15dip" /></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingBottom="10dip"android:paddingLeft="5dip"android:paddingTop="10dip" ><ImageViewandroid:layout_width="35dp"android:layout_height="35dp"android:scaleType="fitCenter"android:src="@drawable/more_emoji_store" /><TextViewandroid:layout_width="wrap_content"android:layout_height="fill_parent"android:layout_marginLeft="10dp"android:gravity="center"android:text="表情商店"android:textColor="@color/black"android:textSize="15dip" /></LinearLayout></android.support.v7.widget.LinearLayoutCompat></RelativeLayout>

当然和真正微信里的界面还是不一样的,还需要处理很多细节,这里就不过分纠结于细节了,主要还是了解LinearLayoutCompat的用法。

LinearLayoutCompat的源码分析

在使用完LinearLayoutCompat之后,我们会很好奇它内部是如何实现添加分割线的,那我们就看一下LinearLayoutCompat的源码进行分析。

\1. 观看源码,首先可以知道 LinearLayoutCompat继承了ViewGroup,然后我们查看它的构造函数

public LinearLayoutCompat(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);final TintTypedArray a = TintTypedArray.obtainStyledAttributes(context, attrs,R.styleable.LinearLayoutCompat, defStyleAttr, 0);int index = a.getInt(R.styleable.LinearLayoutCompat_android_orientation, -1);if (index >= 0) {setOrientation(index);}index = a.getInt(R.styleable.LinearLayoutCompat_android_gravity, -1);if (index >= 0) {setGravity(index);}boolean baselineAligned = a.getBoolean(R.styleable.LinearLayoutCompat_android_baselineAligned, true);if (!baselineAligned) {setBaselineAligned(baselineAligned);}mWeightSum = a.getFloat(R.styleable.LinearLayoutCompat_android_weightSum, -1.0f);mBaselineAlignedChildIndex =a.getInt(R.styleable.LinearLayoutCompat_android_baselineAlignedChildIndex, -1);mUseLargestChild = a.getBoolean(R.styleable.LinearLayoutCompat_measureWithLargestChild, false);setDividerDrawable(a.getDrawable(R.styleable.LinearLayoutCompat_divider));mShowDividers = a.getInt(R.styleable.LinearLayoutCompat_showDividers, SHOW_DIVIDER_NONE);mDividerPadding = a.getDimensionPixelSize(R.styleable.LinearLayoutCompat_dividerPadding, 0);a.recycle();}

从构造函数中,首先会把LinearLayoutCompat的所有风格属性的值保存到一个TintTypedArray数组中,然后从中取出用户给LinearLayoutCompat设置的orientation, gravity,baselineAligned的值,如果这些值存在,就给LinearLayoutCompat设置这些值。当然还会从TintTypedArray中取出weightSum,baselineAlignedChildIndex,measureWithLargestChild等属性,然后在构造函数的最低部,会发现这一段代码:

 <span style="white-space:pre">	</span>setDividerDrawable(a.getDrawable(R.styleable.LinearLayoutCompat_divider));mShowDividers = a.getInt(R.styleable.LinearLayoutCompat_showDividers, SHOW_DIVIDER_NONE);mDividerPadding = a.getDimensionPixelSize(R.styleable.LinearLayoutCompat_dividerPadding, 0);

可以发现setDividerDrawable方法,看名字意思是设置分割线的Drawable,非常明显和分割线有关系,接着是从TintTypedArray中继续获取mShowDividers和mDividerPadding的值,分别用于判断显示分割线的模式和分割线的Padding值为多少。我们查看setDividerDrawable方法的内部实现:

 public void setDividerDrawable(Drawable divider) {if (divider == mDivider) {return;}mDivider = divider;if (divider != null) {mDividerWidth = divider.getIntrinsicWidth();mDividerHeight = divider.getIntrinsicHeight();} else {mDividerWidth = 0;mDividerHeight = 0;}setWillNotDraw(divider == null);requestLayout();}

可以看到,该方法中传进来一个Drawable,然后会进行if判断,是否和原有的Drawable相等,如果为true则return,不执行下面的语句,如果不是,则将该Drawable设置给全局的mDivider,又是if判断,如果传进来的divider!= null,则获取它的固有宽高并设置给mDivider,否则mDivider的宽高设为0,然后会执行setWillNotDraw和requestLayout方法。

我们都知道每一个ViewGroup都会拥有onDraw,onLayout和onMeasure方法,下面我们就查看一下这几个方法的源码进行分析,看看分割线是如何进行绘制的。从源码往下看,首先会看到onDraw方法。

 protected void onDraw(Canvas canvas) {if (mDivider == null) {return;}if (mOrientation == VERTICAL) {drawDividersVertical(canvas);} else {drawDividersHorizontal(canvas);}}

onDraw方法内部逻辑很简单,判断mDivider是否为空,然后是根据mOrientation的属性,来调用不同的方法进行横或者竖的分割线绘制。查看drawDividersVertical方法内部:

void drawDividersVertical(Canvas canvas) {final int count = getVirtualChildCount();for (int i = 0; i < count; i++) {final View child = getVirtualChildAt(i);if (child != null && child.getVisibility() != GONE) {if (hasDividerBeforeChildAt(i)) {final LayoutParams lp = (LayoutParams) child.getLayoutParams();final int top = child.getTop() - lp.topMargin - mDividerHeight;drawHorizontalDivider(canvas, top);}}}

循环遍历所有子孩子,进行是否为空和是否为不可见的判断,然后调用hasDividerBeforeChildAt(i),如果为true,则通过获取child的LayoutParams进行计算,然后就可以计算出分割线的top距离,然后调用drawHorizontalDivider(canvas,top)方法,查看一下hasDividerBeforeChildAt方法的内部逻辑:

protected boolean hasDividerBeforeChildAt(int childIndex) {if (childIndex == 0) {return (mShowDividers & SHOW_DIVIDER_BEGINNING) != 0;} else if (childIndex == getChildCount()) {return (mShowDividers & SHOW_DIVIDER_END) != 0;} else if ((mShowDividers & SHOW_DIVIDER_MIDDLE) != 0) {boolean hasVisibleViewBefore = false;for (int i = childIndex - 1; i >= 0; i--) {if (getChildAt(i).getVisibility() != GONE) {hasVisibleViewBefore = true;break;}}return hasVisibleViewBefore;}return false;}

基本就是根据子孩子的位置进行相应的判断,第一个位置,最后一个位置,还有中间所有位置,返回一个boolean值,会根据这个值来判断是否画分割线。然后回到drawDividersVertical方法中,它会在遍历子View的最后调用drawHorizontalDivider方法,查看一下这个方法:

void drawHorizontalDivider(Canvas canvas, int top) {mDivider.setBounds(getPaddingLeft() + mDividerPadding, top,getWidth() - getPaddingRight() - mDividerPadding, top + mDividerHeight);mDivider.draw(canvas);}

发现分割线其实是通过Drawable的setBounds方法进行设置的,然后会调用 Drawable的draw方法对分割线进行绘制。drawDividersHorizontal方法的逻辑跟drawDividersVertical方法差不多,它最后调用的是drawVerticalDivider方法。

 void drawDividersHorizontal(Canvas canvas) {final int count = getVirtualChildCount();final boolean isLayoutRtl = ViewUtils.isLayoutRtl(this);for (int i = 0; i < count; i++) {final View child = getVirtualChildAt(i);if (child != null && child.getVisibility() != GONE) {if (hasDividerBeforeChildAt(i)) {final LayoutParams lp = (LayoutParams) child.getLayoutParams();final int position;if (isLayoutRtl) {position = child.getRight() + lp.rightMargin;} else {position = child.getLeft() - lp.leftMargin - mDividerWidth;}drawVerticalDivider(canvas, position);}}}

然后我们查看一下onMeasure方法,内部就是根据Orientation的不同,调用不同的方法:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {if (mOrientation == VERTICAL) {measureVertical(widthMeasureSpec, heightMeasureSpec);} else {measureHorizontal(widthMeasureSpec, heightMeasureSpec);}}

查看measureVertical方法,内容较多,我们一点点分析,下面这段代码会循环遍历所有的子View,然后做出相应的判断,如果hasDividerBeforeChildAt方法返回true,mTotalLength会加上分割线的高度,这个方法我们前面已经看过他内部的逻辑,然后会获取子view的LayoutParams,totalWeight用于记录Weight的总和:

for (int i = 0; i < count; ++i) {final View child = getVirtualChildAt(i);if (child == null) {mTotalLength += measureNullChild(i);continue;}if (child.getVisibility() == View.GONE) {i += getChildrenSkipCount(child, i);continue;}if (hasDividerBeforeChildAt(i)) {mTotalLength += mDividerHeight;}LinearLayoutCompat.LayoutParams lp = (LinearLayoutCompat.LayoutParams) child.getLayoutParams();totalWeight += lp.weight;

接下来会对heightMode进行判断,跟MeasureSpec.EXACTLY等属性进行比较,还会判断是否使用了权重,根据heightMode的值不同会有不同的处理方式,mTotalLength的值的处理是不同的,同时如果不满足if语句的条件,会调用 measureChildBeforeLayout方法进行一次测量:

<pre name="code" class="java">            if (heightMode == MeasureSpec.EXACTLY && lp.height == 0 && lp.weight > 0) {// Optimization: don't bother measuring children who are going to use// leftover space. These views will get measured again down below if// there is any leftover space.final int totalLength = mTotalLength;mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin);skippedMeasure = true;} else {int oldHeight = Integer.MIN_VALUE;if (lp.height == 0 && lp.weight > 0) {// heightMode is either UNSPECIFIED or AT_MOST, and this// child wanted to stretch to fill available space.// Translate that to WRAP_CONTENT so that it does not end up// with a height of 0oldHeight = 0;lp.height = LayoutParams.WRAP_CONTENT;}// Determine how big this child would like to be. If this or// previous children have given a weight, then we allow it to// use all available space (and we will shrink things later// if needed).measureChildBeforeLayout(child, i, widthMeasureSpec, 0, heightMeasureSpec,totalWeight == 0 ? mTotalLength : 0);if (oldHeight != Integer.MIN_VALUE) {lp.height = oldHeight;}final int childHeight = child.getMeasuredHeight();final int totalLength = mTotalLength;mTotalLength = Math.max(totalLength, totalLength + childHeight + lp.topMargin +lp.bottomMargin + getNextLocationOffset(child));if (useLargestChild) {largestChildHeight = Math.max(childHeight, largestChildHeight);}}
<pre name="code" class="java">void measureChildBeforeLayout(View child, int childIndex,int widthMeasureSpec, int totalWidth, int heightMeasureSpec,int totalHeight) {measureChildWithMargins(child, widthMeasureSpec, totalWidth,heightMeasureSpec, totalHeight);}

当heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED时,mTotalLength值的计算方式是不同的

 if (mTotalLength > 0 && hasDividerBeforeChildAt(count)) {mTotalLength += mDividerHeight;}if (useLargestChild &&(heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED)) {mTotalLength = 0;for (int i = 0; i < count; ++i) {final View child = getVirtualChildAt(i);if (child == null) {mTotalLength += measureNullChild(i);continue;}if (child.getVisibility() == GONE) {i += getChildrenSkipCount(child, i);continue;}final LinearLayoutCompat.LayoutParams lp = (LinearLayoutCompat.LayoutParams)child.getLayoutParams();// Account for negative marginsfinal int totalLength = mTotalLength;mTotalLength = Math.max(totalLength, totalLength + largestChildHeight +lp.topMargin + lp.bottomMargin + getNextLocationOffset(child));}}

到最后有下面一段代码:

  <span style="white-space:pre">	</span>maxWidth += getPaddingLeft() + getPaddingRight();
<span style="white-space:pre">	</span>// Check against our minimum widthmaxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());setMeasuredDimension(ViewCompat.resolveSizeAndState(maxWidth, widthMeasureSpec, childState),heightSizeAndState);

measureVertical方法最后是通过setMeasuredDimension方法对测量的值进行设置的,至于 maxWidth的值在源码的前面有相应的判断进行赋值,所以整个measure的方法基本围绕 maxWidth和mTotalLength值的确定展开的,其中如果hasDividerBeforeChildAt返回的值为true,mTotalLength会加上分割线的高度,最后通过setMeasuredDimension赋值。

最后我们看看onLayout方法

protected void onLayout(boolean changed, int l, int t, int r, int b) {if (mOrientation == VERTICAL) {layoutVertical(l, t, r, b);} else {layoutHorizontal(l, t, r, b);}}

看一下layoutVertical的逻辑,里面基本围绕以下两个值展开的:

        int childTop;int childLeft;
for (int i = 0; i < count; i++) {final View child = getVirtualChildAt(i);if (child == null) {childTop += measureNullChild(i);} else if (child.getVisibility() != GONE) {final int childWidth = child.getMeasuredWidth();final int childHeight = child.getMeasuredHeight();final LinearLayoutCompat.LayoutParams lp =(LinearLayoutCompat.LayoutParams) child.getLayoutParams();int gravity = lp.gravity;if (gravity < 0) {gravity = minorGravity;}final int layoutDirection = ViewCompat.getLayoutDirection(this);final int absoluteGravity = GravityCompat.getAbsoluteGravity(gravity,layoutDirection);switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {case Gravity.CENTER_HORIZONTAL:childLeft = paddingLeft + ((childSpace - childWidth) / 2)+ lp.leftMargin - lp.rightMargin;break;case Gravity.RIGHT:childLeft = childRight - childWidth - lp.rightMargin;break;case Gravity.LEFT:default:childLeft = paddingLeft + lp.leftMargin;break;}if (hasDividerBeforeChildAt(i)) {childTop += mDividerHeight;}childTop += lp.topMargin;setChildFrame(child, childLeft, childTop + getLocationOffset(child),childWidth, childHeight);childTop += childHeight + lp.bottomMargin + getNextLocationOffset(child);i += getChildrenSkipCount(child, i);}}

循环遍历子View,根据不同的gravity对childLeft和childTop进行赋值,如果存在分割线childTop会加上分割线的高度mDividerHeight,最后是通过setChildFrame方法进行layout的完成的,可以查看这个方法内部,调用了child的layout方法

 private void setChildFrame(View child, int left, int top, int width, int height) {child.layout(left, top, left + width, top + height);}

到这里,所有的LinearLayoutCompat的源码分析,就结束了,为什么要看分割线绘制的源码,因为在很多控件中并没有分割线,我们可以通过学习谷歌的源码,仿照着进行分割线的绘制,比如recyclerView就没有分割线,但我们可以自己写一个分割线,对于 recyclerView分割线设置,有很多大神的博客都有描述,这里就不在赘述了,以后的博文会陆续给大家带来Material Design其他控件的博客。

更多Android进阶指南 可以扫码 解锁 《Android十大板块文档》

1.Android车载应用开发系统学习指南(附项目实战)

2.Android Framework学习指南,助力成为系统级开发高手

3.2023最新Android中高级面试题汇总+解析,告别零offer

4.企业级Android音视频开发学习路线+项目实战(附源码)

5.Android Jetpack从入门到精通,构建高质量UI界面

6.Flutter技术解析与实战,跨平台首要之选

7.Kotlin从入门到实战,全方面提升架构基础

8.高级Android插件化与组件化(含实战教程和源码)

9.Android 性能优化实战+360°全方面性能调优

10.Android零基础入门到精通,高手进阶之路

敲代码不易,关注一下吧。ღ( ´・ᴗ・` ) 🤔

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

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

相关文章

自动驾驶多任务框架Hybridnets——同时处理车辆检测、可驾驶区域分割、车道线分割模型部署(C++/Python)

一、多感知任务 在移动机器人的感知系统&#xff0c;包括自动驾驶汽车和无人机&#xff0c;会使用多种传感器来获取关键信息&#xff0c;从而实现对环境的感知和物体检测。这些传感器包括相机、激光雷达、雷达、惯性测量单元&#xff08;IMU&#xff09;、全球导航卫星系统&am…

SpringCloud(二)

1.Nacos配置管理 Nacos除了可以做注册中心&#xff0c;同样可以做配置管理来使用。 1.1.统一配置管理 当微服务部署的实例越来越多&#xff0c;达到数十、数百时&#xff0c;逐个修改微服务配置就会让人抓狂&#xff0c;而且很容易出错。我们需要一种统一配置管理方案&#…

NIFI实现数据库数据增量同步

说明 nifi版本&#xff1a;1.23.2&#xff08;docker镜像&#xff09; 需求背景 将数据库中的数据同步到另一个数据库中&#xff0c;要求对于新增的数据和历史有修改的数据进行增量同步 模拟数据 建表语句 源数据库和目标数据库结构要保持一致&#xff0c;这样可以避免后…

固定资产管理数据怎么算?

在企业的运营中&#xff0c;固定资产的管理是一个至关重要的环节。然而&#xff0c;对于许多企业来说&#xff0c;理解和管理这些资产的数据却常常是一团迷雾。那么&#xff0c;固定资产管理数据究竟应该如何计算呢&#xff1f;这是一个需要我们深入探讨的问题。  我们需要明…

MySQL——命令行客户端的字符集问题

原因&#xff1a;服务器端认为你的客户端的字符集是utf-8&#xff0c;而实际上你的客户端的字符集是GBK。 查看所有字符集&#xff1a;SHOW VARIABLES LIKE character_set_%; 解决方案&#xff0c;设置当前连接的客户端字符集 “SET NAMES GBK;”

Android12之/proc/pid/status参数含义(一百六十五)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

php://filter协议在任意文件读取漏洞(附例题)

php://filter php://fiter 中文叫 元器封装&#xff0c;咱也不知道为什么这么翻译&#xff0c;目前我的理解是可以通过这个玩意对上面提到的php IO流进行处理&#xff0c;及现在可以对php的 IO流进行一定操作。 过滤器&#xff1a;及通过php://filter 对php 的IO流进行的具体…

微服务之流控、容错组件sentinel

背景 2012年阿里巴巴研发的流量治理组件&#xff0c;核心功能流控、容错 有什么功能 流量控制 流量控制 网关控制 黑白名单 熔断降级 熔断 保护分布式系统防止因为调用下有服务时产生故障或者请求超时等异常影响上游服务&#xff0c;使用熔断方案&#xff0c;类似断路器…

T2I-Adapter:增强文本到图像生成的控制能力

链接&#xff1a;GitHub - TencentARC/T2I-Adapter: T2I-Adapter 文本到图像生成 (T2I) 是人工智能领域的一个重要研究方向。近年来&#xff0c;随着深度学习技术的发展&#xff0c;T2I 技术取得了显著进展&#xff0c;生成的图像在视觉效果上已经与真实图像难以区分。 然而&…

ILS解析漏洞复现

搭建好ILS后&#xff0c;访问127.0.0.1:8000 写一个phpinfo的脚本 可以看到。现在是不能访问的 赋予 IIS 解析 phpinfo 能力 打开服务器管理器&#xff0c;打开 IIS 管理器 点击处理程序映射 再次访问&#xff0c;发现程序可以访问 将index.php改为index.png 此时php脚本自然是…

【pdf密码】如何限制他人对PDF文件编辑?

制作好的PDF文件&#xff0c;先要设置一个密码防止他人对文件进行编辑&#xff0c;那么我们可以对PDF文件设置限制编辑&#xff0c;设置方法很简单&#xff0c;我们在PDF编辑器中点击文件 – 属性 – 安全&#xff0c;在权限下拉框中选中【密码保护】 然后在密码保护界面中&…

查看创建好的数据库

MySQL从小白到总裁完整教程目录:https://blog.csdn.net/weixin_67859959/article/details/129334507?spm1001.2014.3001.5502 语法格式: show create database 数据库名称; 案列:查看testing数据库信息 mysql> show create database testing; ------------------------…

SpringMVC相关知识点

1.Spring MVC的理解&#xff1f; 首先&#xff0c;MVC模型是模型&#xff0c;视图&#xff0c;控制器的简写&#xff0c;其思想核心是通过将请求处理控制&#xff0c;业务逻辑&#xff0c;数据封装&#xff0c;数据显示等流程节点分离的思想来组织代码。 所以&#xff0c;MVC是…

华为星闪联盟:引领无线通信技术创新的先锋

星闪&#xff08;NearLink&#xff09;&#xff0c;是由华为倡导并发起的新一代无线短距通信技术&#xff0c;它从零到一全新设计&#xff0c;是为了满足万物互联时代个性化、多样化的极致、创新体验需求而诞生的。这项技术汇聚了中国300多家头部企业和机构的集体智慧&#xff…

【STM32】FSMC—扩展外部 SRAM 初步使用 1

基于野火指南者《零死角玩转 STM32F103—指南者》的学习 STM32F103系列 FSMC Flexible Static Memory Controller简介 1.详细功能参看《STM32F10x参考手册》&#xff0c;这边是概述 是一个外设&#xff0c;挂载在AHB总线下。 可以用于驱动包括 SRAM、NOR FLASH 以及 NAND FL…

C#自定义控件组件实现Chart图表(多Y轴,选择图例加粗,选择放大,缩放,点击查看信息等功能)

先看看ECharts的效果 C# 工具箱里的Chart控件就不演示了,很多效果没办法做出来,做出来效果也很不理想。所以,需要自己去手动实现工具箱里的Chart没办法实现的效果; 先看看实现后的效果 绑定数据 点击图表 点击右侧图例加粗 选择放大 右键 点击缩小,恢复

RJ45水晶头网线顺序出错排查

线序 网线水晶头RJ45常用的线序标准ANSI / TIA-568定义了T568A与T568B两种线序&#xff0c;一般使用T568B&#xff0c;水晶头8个孔对应的8条线颜色如下图&#xff1a; 那1至8的编号&#xff0c;是从水晶头哪一面为参考呢&#xff0c;如下图&#xff0c;是水晶头金手指一面&am…

华为云云耀云服务器L实例评测 | 由于自己原因导致MySQL数据库被攻击 【更新中。。。】

目录 引出起因&#xff08;si因&#xff09;解决报错诶嘿&#xff0c;连上了 不出意外&#xff0c;就出意外了打开数据库what&#xff1f;&#xff1f;&#xff1f; 找华为云求助教训&#xff1a;备份教训&#xff1a;密码 解决1.改密码2.新建一个MySQL&#xff0c;密码设置复杂…

node.js下载安装环境配置以及快速使用

目录 一、下载 二、安装 三、测试安装是否成功 四、配置环境 五、测试配置环境是否成功 六、安装淘宝镜像 七、快速上手 1、建立一个自己的工作目录 2、下载工作代码 八、各种配置文件匹配问题入坑 九、总结 一、下载 Node.js 中文网 想选择其他版本或者其他系统使用…

Linux服务使用宝塔面板搭建网站,并发布公网访问 - 内网穿透

文章目录 前言1. 环境安装2. 安装cpolar内网穿透3. 内网穿透4. 固定http地址5. 配置二级子域名6. 创建一个测试页面 前言 宝塔面板作为简单好用的服务器运维管理面板&#xff0c;它支持Linux/Windows系统&#xff0c;我们可用它来一键配置LAMP/LNMP环境、网站、数据库、FTP等&…