正确实践Jetpack SplashScreen API —— 在所有Android系统上使用总结,内含原理分析

news2024/12/23 9:49:14

1.前言

文章末尾有演示的APK链接,感兴趣的同学,可以自行下载体验一下

官方Android 12的Splash Screen文档地址
官方Splash Screen兼容库,支持所有版本系统

本篇文章主要围绕下面三个问题来介绍:

  • 我们能从Android 12 SplashScreen API里面学到什么?
  • 新出的SplashScreen兼容库又是什么?能做成什么样子?
  • 小甲同学:我想看Android12 SplashScreen源码,可以吗?

前方高能预警:一定要记得『点赞❤️+关注❤️+收藏❤️』起来,划走了可就再也找不到了😅😅🙈🙈

进入正题,我们先介绍:SplashScreen如何使用,以及目前会遇到的问题,如何无缝过渡?会出现什么问题,怎么解决?

2.SplashScreen使用

首先我们需要把compileSdk和targetSdk(可选)升级到31

2.1.Android12版本

(A).主题和外观配置

<!--文章末尾我们会把包含所有示例的链接地址提供出来,如有需要:请翻到文章末尾-->

<!-- values-v31/themes.xml -->
<!--单一颜色填充「启动画面」窗口背景-->
<item name="android:windowSplashScreenBackground">@color/...</item>

<!--「启动画面」中心的图标,
     可以配置AnimationDrawable 和 AnimatedVectorDrawable类型的drawable-->
<item name="android:windowSplashScreenAnimatedIcon">@drawable/...</item>

<!--「启动画面」中心图标动画的持续时间,这个属性不会对屏幕显示的实际时间产生任何影响-->
<item name="android:windowSplashScreenAnimationDuration">1000</item>

<!--「启动画面」中心图标后面设置背景-->
<item name="android:windowSplashScreenIconBackgroundColor">@color/...</item>

<!--「启动画面」底部显示的品牌图标-->
<item name="android:windowSplashScreenBrandingImage">@drawable/...</item>

(B).延长启动画面

val content: View = findViewById(android.R.id.content)
    content.viewTreeObserver.addOnPreDrawListener(
        object : ViewTreeObserver.OnPreDrawListener {
            override fun onPreDraw(): Boolean {
                // 模拟一些数据的初始化,再取消挂起
                return if (viewModel.isReady) {
                    // 取消挂起,恢复页面内容绘制
                    content.viewTreeObserver.removeOnPreDrawListener(this)
                    true
                } else {
                    // 挂起,内容还没有准备好
                    false
                }
            }
        }
    )

©.关闭启画面的动画

// 自己定制关闭的动画
splashScreen.setOnExitAnimationListener { splashScreenView ->
        val slideUp = ObjectAnimator.ofFloat(
            // 你们自己控制,自己随便写什么动画,这里我们测试让图标移动
            splashScreenView.iconView,
            View.TRANSLATION_Y,
            0f,
            -splashScreenView.height.toFloat()
        )
        slideUp.interpolator = AnticipateInterpolator()
        slideUp.duration = 200L
        slideUp.doOnEnd { splashScreenView.remove() }
        slideUp.start()
    }

(D).遇到的问题

  • android:windowSplashScreenBrandingImage 定义的图片尺寸要求是多少?总觉得有点拉伸;
  • 使用AnimationDrawable 或者 AnimatedVectorDrawable,来设置中心图标,会出现“中心图标”消失的情况,静态图标不会有这种问题出现;
  • Android12父主题设置android:windowBackground被覆盖,看不到效果

问题1: 在源码里面也没有看到具体的值或者比例大小,怎么办呢?

小技巧: 使用一个超大的正方形的图标设置进去测试了一下,拉伸不要紧,我们要的是比例
然后测量了一下比例为2.5 : 1,所以设计品牌名图标的时候,可以设置为400 * 160这样的比例为2.5:1的图标

问题2: 针对中心图标会闪现消失的问题做测试,
测试一:静态Icon、测试二:动态Icon


静态中心图标 - 正常

下面我们来测试动态中心图标,为了方便测试出效果,我们覆盖住图标后面的背景色,方便对比,最后发现:测试结果不太理想,效果不行

<!--AnimationDrawable写法-->
<!--没有真机测试,这个写法,效果看起来也挺奇怪的,可能是模拟器且是预览版的问题吧-->
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="true">
    <item android:drawable="@mipmap/ic_launcher" android:duration="600" />
    <item android:drawable="@drawable/api12_logo" android:duration="200" />
    <item android:drawable="@mipmap/ic_launcher" android:duration="200" />
</animation-list>

动态中心图标,不正常
仔细看图标后面的「蓝色背景」

我们再来看一下官方文档中的顺滑效果:


官方效果顺滑

对比官方的效果,猜测可能是模拟器和预览版Android12的问题,主要是没有真机来测试Android12这个效果,不过这难不到我们,如果你的模拟器也有同样问题,请跟着我们做如下操作:

下面我们使用AnimatedVectorDrawable来制作动态图标,
为了观察出效果:我们打开模拟器的开发者选项,找到Animator时长缩放设置为:动画时长x10,来往下看效果:


10倍慢放 - 看着才正常

笑脸眼睛动画的矢量图文件 👇👇,点击查看在线制作矢量图动画

<!--仅测试玩耍,感兴趣的可以自己去制作一个-->
<?xml version="1.0" encoding="utf-8"?>
<animated-vector
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:aapt="http://schemas.android.com/aapt">
    <aapt:attr name="android:drawable">
        <vector
            android:name="vector"
            android:width="24dp"
            android:height="24dp"
            android:viewportWidth="24"
            android:viewportHeight="24">
            <group android:name="group">
                <path
                    android:name="path_4"
                    android:pathData="M 11.99 2 C 6.47 2 2 6.48 2 12 C 2 17.52 6.47 22 11.99 22 C 17.52 22 22 17.52 22 12 C 22 6.48 17.52 2 11.99 2 Z M 12 20 C 7.58 20 4 16.42 4 12 C 4 7.58 7.58 4 12 4 C 16.42 4 20 7.58 20 12 C 20 16.42 16.42 20 12 20 Z M 12 17.5 C 14.33 17.5 16.32 16.05 17.12 14 L 15.45 14 C 14.76 15.19 13.48 16 12 16 C 10.52 16 9.25 15.19 8.55 14 L 6.88 14 C 7.68 16.05 9.67 17.5 12 17.5 Z"
                    android:fillColor="#FFFFFF"/>
            </group>
            <group android:name="group_1">
                <path
                    android:name="path_1"
                    android:pathData="M 8.5 9.5 M 7 9.5 C 7 9.102 7.158 8.721 7.439 8.439 C 7.721 8.158 8.102 8 8.5 8 C 8.898 8 9.279 8.158 9.561 8.439 C 9.842 8.721 10 9.102 10 9.5 C 10 9.898 9.842 10.279 9.561 10.561 C 9.279 10.842 8.898 11 8.5 11 C 8.102 11 7.721 10.842 7.439 10.561 C 7.158 10.279 7 9.898 7 9.5"
                    android:fillColor="#FFFFFF"/>
                <path
                    android:name="path_3"
                    android:pathData="M 8.5 9.5 M 7 9.5 C 7 9.102 7.158 8.721 7.439 8.439 C 7.721 8.158 8.102 8 8.5 8 C 8.898 8 9.279 8.158 9.561 8.439 C 9.842 8.721 10 9.102 10 9.5 C 10 9.898 9.842 10.279 9.561 10.561 C 9.279 10.842 8.898 11 8.5 11 C 8.102 11 7.721 10.842 7.439 10.561 C 7.158 10.279 7 9.898 7 9.5"
                    android:fillColor="#FFFFFF"/>
            </group>
            <group android:name="group_2">
                <path
                    android:name="path"
                    android:pathData="M 15.5 9.5 M 14 9.5 C 14 9.102 14.158 8.721 14.439 8.439 C 14.721 8.158 15.102 8 15.5 8 C 15.898 8 16.279 8.158 16.561 8.439 C 16.842 8.721 17 9.102 17 9.5 C 17 9.898 16.842 10.279 16.561 10.561 C 16.279 10.842 15.898 11 15.5 11 C 15.102 11 14.721 10.842 14.439 10.561 C 14.158 10.279 14 9.898 14 9.5"
                    android:fillColor="#FFFFFF"/>
                <path
                    android:name="path_2"
                    android:pathData="M 15.5 9.5 M 14 9.5 C 14 9.102 14.158 8.721 14.439 8.439 C 14.721 8.158 15.102 8 15.5 8 C 15.898 8 16.279 8.158 16.561 8.439 C 16.842 8.721 17 9.102 17 9.5 C 17 9.898 16.842 10.279 16.561 10.561 C 16.279 10.842 15.898 11 15.5 11 C 15.102 11 14.721 10.842 14.439 10.561 C 14.158 10.279 14 9.898 14 9.5"
                    android:fillColor="#FFFFFF"/>
            </group>
        </vector>
    </aapt:attr>
    <target android:name="group_1">
        <aapt:attr name="android:animation">
            <objectAnimator
                android:propertyName="translateX"
                android:duration="1000"
                android:valueFrom="0"
                android:valueTo="7"
                android:valueType="floatType"
                android:interpolator="@android:interpolator/fast_out_slow_in"/>
        </aapt:attr>
    </target>
    <target android:name="group_2">
        <aapt:attr name="android:animation">
            <objectAnimator
                android:propertyName="translateX"
                android:duration="1000"
                android:valueFrom="0"
                android:valueTo="-7"
                android:valueType="floatType"
                android:interpolator="@android:interpolator/fast_out_slow_in"/>
        </aapt:attr>
    </target>
</animated-vector>

后来我们又用了AnimationDrawable测试了一下慢放效果也不行,你仔细想一下:图片轮播放效果能好吗?
所以:AnimationDrawable不推荐,我们这里推荐使用:AnimatedVectorDrawable为矢量图添加动画效果

问题3: Android12父主题设置android:windowBackground被覆盖,看不到效果

不要紧,只要我们的UI设计师(美工)按照如下尺寸规范来设计,使用静态中心图标,一样可以实现同样效果:
中心图标: 图标内容区域内边距2/3,防止元素被切
品牌名图标: 设计的尺寸比例为:2.5:1

2.2.SplashScreen兼容库

点击查看官方Splash Screen兼容库文档

(A).依赖库

点击查看Core库里面的最新版本

// 可在所有Android版本上使用的兼容库
implementation 'androidx.core:core-splashscreen:1.0.0-alpha02'

(B).主题和外观配置

  • 定义Activity应该使用的主题

<style name="Theme.App" parent="Theme.MaterialComponents.xxxxx.DarkActionBar">
        <item name="android:windowBackground">@color/...</item>
        <item name="android:statusBarColor">@android:color/transparent</item>
        <item name="android:windowLightStatusBar" tools:targetApi="m">......</item>
        <item name="android:navigationBarColor">@android:color/transparent</item>
    </style>
  • 创建父主题给启动画面使用
<style name="Theme.App.Starting" parent="Theme.SplashScreen.IconBackground">
        <item name="android:windowBackground">@drawable/...</item>
        <item name="windowSplashScreenBackground">@color/...</item>
        <item name="windowSplashScreenAnimationDuration">200</item>
        <item name="postSplashScreenTheme">@style/Theme.App</item>
</style>
  • AndroidManifest.xml配置Activity的主题
<manifest>
   <application android:theme="@style/Theme.App.Starting">
    <!-- application和activity,两个选一个配置: @style/Theme.App.Starting -->
        <activity android:theme="@style/Theme.App.Starting">
...

©.初始化SplashScreen

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val splashScreen = installSplashScreen()
        setContent { ...... }
        splashScreen.setKeepVisibleCondition {
            !mainViewModel.mockDataLoading()
        }
        splashScreen.setOnExitAnimationListener(this)
    }

(D).中心图标大小修改

<item name="splashScreenIconSize">@dimen/....</item>

(E).遇到的问题

兼容库目前存在的问题

  • 没有android:windowSplashScreenBrandingImage这个属性
  • 配置了中心图标,会裁剪成圆形
  • 低版本系统不配置windowSplashScreenAnimatedIcon会出现默认的Icon
  • Android12父主题设置android:windowBackground被覆盖,看不到效果

问题1: 是因为兼容库的layout文件目录下面的splash_screen_view.xml没有“品牌名的视图”,大家点击查看一下,两个布局的xml内容就知道了:
frameworks下面的Android12的splash_screen_view.xml
core-splashscreen下面的兼容库的splash_screen_view.xml

但是我们在Android12即values-v31的themes.xml里面依然可以配置android:windowSplashScreenBrandingImage这个属性,因为Android12的SplashScreen是集成在frameworks里面的;

问题2: 是因为兼容库里面使用了MaskedDrawable包装了Icon,会裁剪成圆形,图标内容设计要保留2/3的内边距,否则会出现内容被裁剪掉的问题;
如何修复这个裁剪圆形问题呢?

把源码拷贝出来,总共就3个源代码文件,自己复制出来修改删除也可以的
或者,图标设计准则为:内容保留内边距为2/3,防止元素被裁剪

问题3: 写一个透明的drawable.xml然后替换就行了,类似如下方式

<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="@android:color/transparent"/>
    <size android:width="0dp" android:height="0dp"/>
</shape>

问题4: Android12父主题设置android:windowBackground被覆盖,看不到效果

不要紧,只要我们的UI设计师(美工)按照如下尺寸规范来设计,使用静态中心图标,一样可以实现同样效果:
中心图标: 图标内容区域内边距2/3,防止元素被切
品牌名图标: 设计的尺寸比例为:2.5:1

(F).制作一个启动页

  • 1.模仿快手App的启动页
    只需要配置父主题的android:windowBackground

Android5.0 ~ Android11 效果

由于我们在文章上面介绍到Android12上,无法为SplashScreen设置父主题的android:windowBackground,但我们依然可以通过配置静态中心图标来做到一样的效果的,请看下面的效果:


Android12 效果

如果你的UI设计师,给你矢量图,那么你就可以让中心图标在Android12系统上动起来了😆
另外,可以建议UI设计师:统一所有系统上,启动页“中心”图标,居中展示,不然会有点怪

  • 2.动态图标启动页
    如果设计成动态启动图标,这个需要考虑2个因素:

一、 低版本系统表现效果不一致,有些系统里面,动态图标只在启动页关闭的时候才显示(亲测Android平板5.1.1系统就是这样的);
二、 如何兼容低版本系统,是先展示底部品牌名,最后只能等动态图标显示咯?

如果喜欢折腾的同学,可以多测试测试,我在使用Android10.0测试动态图标的时候,效果看着还可以,具体系统下限在哪?
这个看你们产品设计定位了,还有测试妹妹是否同意你们用,效果是否符合你们的产品;

建议的做法是:

  • Android 5.0 ~ Android 11.0系统,都统一使用android:windowBackground配置启动页背景
  • Android12.0 如果UI设计师给你做了矢量图,你可以做动态的中心图标,不给你,使用静态图标也可以的,参考上面:模拟快手App启动页
    为了在模拟器上能正常显示出效果,我们在模拟器的开发者选项,找到Animator时长缩放设置为:动画时长x10,放慢10倍,缺真机测试😂😂😂😂😂

Android12 动态启动页图标

3.源码分析

我们这里只分析Android12 SplashScreen,兼容库没有太多内容不足500行,感兴趣的同学可以自己阅读一下

我们在XXXActivity里面第一次用到了splashScreen.setOnExitAnimationListener,从这里开始往源头开始找,在下面的方法初始化了SplashScreen

//android.app.Activity
private SplashScreen getOrCreateSplashScreen() {
    synchronized (this) {
        if (mSplashScreen == null) {
           mSplashScreen = new SplashScreen.SplashScreenImpl(this);
        }
        return mSplashScreen;
    }
}

我们来看SplashScreenImpl实现类

//android.app.Activity

class SplashScreenImpl implements SplashScreen {
    ......
    //把SplashScreenImpl添加到这个单例类里面
    private final SplashScreenManagerGlobal mGlobal;
    public SplashScreenImpl(Context context) {
        mGlobal = SplashScreenManagerGlobal.getInstance();
    }
    @Override
    public void setOnExitAnimationListener(@NonNull SplashScreen.OnExitAnimationListener listener) {
        ......
        mGlobal.addImpl(this); // 用于后面执行启动画面将退出的回调
    }
    ......
    public void setSplashScreenTheme(@StyleRes int themeId) {
        ......
        try {
            //设置启动画面的主题
            AppGlobals.getPackageManager().setSplashScreenTheme(......);
        } catch (RemoteException e) {
            Log.w(TAG, "Couldn't persist the starting theme", e);
        }
    }
}

// 启动画面管理器
class SplashScreenManagerGlobal {
    ......
    // 管理多个闪屏实现
    private final ArrayList<SplashScreenImpl> mImpls = new ArrayList<>();

    private SplashScreenManagerGlobal() {
        // 向此进程注册启动画面管理器
        ActivityThread.currentActivityThread().registerSplashScreenManager(this);
    }
    ......
    
    private static final Singleton<SplashScreenManagerGlobal> sInstance =
    new Singleton<SplashScreenManagerGlobal>() {
        @Override
        protected SplashScreenManagerGlobal create() {
            return new SplashScreenManagerGlobal();
        }
    };

    private void addImpl(SplashScreenImpl impl) {
        synchronized (mGlobalLock) {
            mImpls.add(impl);
        }
    }

    private void removeImpl(SplashScreenImpl impl) {
        synchronized (mGlobalLock) {
            mImpls.remove(impl);
        }
    }
    ......
    public void handOverSplashScreenView(IBinder token,SplashScreenView splashScreenView) {
        //调用的是 => splashScreenView.transferSurface();
        transferSurface(splashScreenView);
        //回调 => impl.mExitAnimationListener.onSplashScreenExit(view);
        dispatchOnExitAnimation(token, splashScreenView);
    }
    ......
}

我们看到初始化SplashScreenManagerGlobal的时候,向此进程注册启动画面管理器

//android.app.ActivityThread

public void registerSplashScreenManager(SplashScreen.SplashScreenManagerGlobal manager) {
    synchronized (this) {
        mSplashScreenGlobal = manager;
    }
}

如何把SplashScreen添加到当前的窗口的呢?
ActivityThread继承ClientTransactionHandler,里面有一个这样的抽象方法:

//android.app.ClientTransactionHandler
public abstract void handleAttachSplashScreenView(@NonNull ActivityClientRecord r,
            @NonNull SplashScreenViewParcelable parcelable);

ActivityThread肯定会实现这个方法,那么是谁调用了它呢?由于篇幅问题,就不一行一行代码的去介绍分析了,感兴趣的同学,可以自己深入研究,我们下面贴出来调用的流程图看看 谁调用了handleAttachSplashScreenView(),它的调用链流程图如下:

好了,看完流程图,我们再看一下ActivityThread#handleAttachSplashScreenView

//android.app.ActivityThread

@Override
public void handleAttachSplashScreenView(@NonNull ActivityClientRecord r,
@Nullable SplashScreenView.SplashScreenViewParcelable parcelable) {
    final DecorView decorView = (DecorView) r.window.peekDecorView();
    if (parcelable != null && decorView != null) {
        createSplashScreen(r, decorView, parcelable);
    }
    ......
}

private void createSplashScreen(ActivityClientRecord r, DecorView decorView,
 SplashScreenView.SplashScreenViewParcelable parcelable) {
    // 初始化SplashScreenView构建器
    final SplashScreenView.Builder builder = new SplashScreenView.Builder(r.activity);
    // 从parcelable中获取配置数据,并通过build()初始化SplashScreenView,设置数据
    final SplashScreenView view = builder.createFromParcel(parcelable).build();
    // 把SplashScreenView添加到DecorView中
    decorView.addView(view);
    // 设置SystemUI颜色
    view.attachHostActivityAndSetSystemUIColors(r.activity, r.window);
    // 刷新视图
    view.requestLayout();
    ......
}

核心的部分源码已经分析差不多了,剩下的一些源码,感兴趣的同学可以自己查看阅读

4.总结

  • compileSdk升级到31
  • 产品中统一使用兼容库SplashScreen
implementation 'androidx.core:core-splashscreen:最新版本'
  • 演示示例中资源目录
drawable —— 定义低版本的drawable资源
drawable-v23 —— 定义6.0以上的资源
drawable-v31 —— 定义Android12及以上的资源
values —— 定义默认资源
values-night —— 定义默认深色模式资源
values-v23 —— 定义6.0以上系统资源
values-v31 —— 定义Android12及以上的资源
values-night-v31 —— 定义Android12及以上的深色模式资源
  • 启动页图标设计准则
    中心图标大图,内容需要保留2/3的内边距否则图标会被裁剪掉,另外:图标尺寸大小可以修改;
    底部品牌名图标:尺寸比例需要为 2.5:1
    兼容库SplashScreen低版本不支持设置底部品牌图标,
    Android12需要在values-v31目录手动添加如下属性,才可以显示品牌名图标
<!--兼容库没有这个属性,我们需要在values-v31单独配置一下-->
<item name="android:windowSplashScreenBrandingImage">@drawable/...</item>
  • Android12以下系统可以使用android:windowBackground为父主题设置窗口背景,切记不要在Android12及以上系统设置父主题的窗口背景(因为没有效果😅😅)

  • Android12系统以下系统,使用android:windowBackground的话,一定要给windowSplashScreenAnimatedIcon设置一个透明的drawable,否则会出现机器人图标

  • windowSplashScreenBackground 这个属性的颜色一定要注意,配置有问题的话,启动页过渡到主页面的时候,会有这个颜色闪出来,建议和Activity的android:windowBackground配置成一样的颜色

  • 在启动画面上面,添加一个“广告或者推广页面”,代码和效果如下:

override fun onSplashScreenExit(splashScreenViewProvider: SplashScreenViewProvider) {
    if(splashScreenViewProvider.view is ViewGroup){
        // 在这里添加一个启动页广告或者推广页面
        val composeView = ComposeView(this@SplashScreenCompatActivity).apply {
            setContent {
                SplashAdScreen(onCloseAd = {
                    splashScreenViewProvider.remove()
                })
            }
        }
        (splashScreenViewProvider.view as ViewGroup).addView(composeView)
        return
    }
}

实践 - 启动页添加广告或者推广页

参考地址

  • 在线流程图制作
  • 官方文档 Splash screens
  • Google官网介绍矢量图
  • 在线svg编辑器
  • 在线制作矢量图动画
  • 在线合并多个GIF制作

文章中示例的演示APK及源码地址:

静态图标启动页动态图标启动页
(Android12系统有动画效果)
启动页加广告
下载:SplashScreen快手启动页效果的apk001下载:SplashScreen快手启动页效果的apk002下载:SplashScreen启动页广告apk
提取码:7gj2提取码:b6ce提取码:fnva

点击查看:SplashScreen演示示例的源码

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

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

相关文章

订单数据越来越多,如何优化数据库性能?

“增删改查”都是查找问题&#xff0c;因为你都得先找到数据才能对数据做操作。那存储系统性能问题&#xff0c;其实就是查找快慢问题。 存储系统一次查询所耗时间取决两个因素&#xff1a; 查找的时间复杂度数据总量 查找的时间复杂度取决于&#xff1a; 查找算法存储数据…

基于Java-SpringBoot+vue实现的前后端分离信息管理系统设计和实现

基于Java-SpringBootvue实现的前后端分离信息管理系统设计和实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言…

后台执行限制总结

后台限制的发展历程 前台定义 针对后台Service procState < PROCESS_STATE_IMPORTANT_BACKGROUND7 针对后台启动Activity procState < PROCESS_STATE_BOUND_TOP3 针对后台启动FGS/后台启动FGS的while-in-use权限 procState < PROCESS_STATE_BOUND_FOREGROUND_SERVICE…

【Linux】文本编辑器-vim使用

目  录1 vim的基本概念2 vim的基本操作3 vim常用模式命令集3.1 vim正常模式命令集3.2 vim末行模式命令集4 vim的简单配置1 vim的基本概念 vim编辑器与vi编辑器一样都是多模式编辑器&#xff0c;不同的是vim编辑器是vi编辑器的升级版本&#xff0c;vim不仅兼容vi的所有指令&am…

Django by Example·第二章|Enhancing Your Blog with Advanced Features@笔记

Django by Example第二章|Enhancing Your Blog with Advanced Features笔记 这本书的结构确实很不错&#xff0c;如果能够坚持看下去&#xff0c;那么Django框架的各种用法也就掌握的七七八八了。之前写过一篇这本书的第一章&#xff0c;看完第一章就算是入门了&#xff0c;但…

acwing差分

题目&#xff1a;输入一个长度为 n 的整数序列。接下来输入 m 个操作&#xff0c;每个操作包含三个整数 l,r,c&#xff0c;表示将序列中 [l,r] 之间的每个数加上 c。请你输出进行完所有操作后的序列。输入格式第一行包含两个整数 n 和 m。第二行包含 n 个整数&#xff0c;表示整…

【C++高阶数据结构】跳表(skiplist)

&#x1f3c6;个人主页&#xff1a;企鹅不叫的博客 ​ &#x1f308;专栏 C语言初阶和进阶C项目Leetcode刷题初阶数据结构与算法C初阶和进阶《深入理解计算机操作系统》《高质量C/C编程》Linux ⭐️ 博主码云gitee链接&#xff1a;代码仓库地址 ⚡若有帮助可以【关注点赞收藏】…

第十一章Thymeleaf学习

文章目录什么是Thymeleaf什么是模板引擎Thymeleaf的同行Thymeleaf优势一个实例来认识大概过程导入对应的jar包配置对应的xml文件对应的ViewBaseServlet编写——对应的模板引擎写对应的Servlet类并且继承ViewBaseServlet对应index.html资源——对应的模板Thymeleaf的基础语法th名…

337. 打家劫舍 III

目录题目思路代码题目 小偷又发现了一个新的可行窃的地区。这个地区只有一个入口&#xff0c;我们称之为 root 。 除了 root 之外&#xff0c;每栋房子有且只有一个“父“房子与之相连。一番侦察之后&#xff0c;聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”…

笔试强训(11)

第一题:二进制插入二进制插入__牛客网 给定32位整数n和m&#xff0c;同时我们指定i和j&#xff0c;将m的二进制位数插入到n的二进制位数的j到i位&#xff0c;我们保证n的j到i位均是等于0的&#xff0c;况且m的二进制位数小于等于i-j1&#xff0c;其中二进制的位数从0开始从低到…

js设计模式(八)-总体感受一下设计模式

前言 首先&#xff0c;不得不说我们是站在巨人的肩膀上写代码&#xff0c;前辈们已经很合理的帮助我们总结出来了23种设计模式&#xff0c;虽然有些已经被语言直接使用Api实现了&#xff0c;感谢走在前沿的攻城狮。 但是真真正正的看一遍所有的设计模式还是很有必要的&#x…

MyBatis查询数据库

1.MyBatis 是什么&#xff1f; MyBatis 是⼀款优秀的持久层框架&#xff0c;它⽀持⾃定义 SQL、存储过程以及⾼级映射。MyBatis 去除了⼏乎所有的 JDBC 代码以及设置参数和获取结果集的⼯作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接⼝和 Java POJO&#xf…

计算机基础——计算机分类

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 前言 本章将会讲解计算机分类应用领域以及发展趋势 一.计算机分类 计算机并非只有日常所…

并行计算 Clion配置使用OpenMP

文章目录配置CMakeList.txt文件OpenMP之HelloWorld数据共享属性shared子句private子句default子句default(shared)default(none)配置CMakeList.txt文件 文件底部加入以下内容&#xff0c;即可支持OpenMP FIND_PACKAGE(OpenMP REQUIRED) if (OPENMP_FOUND)message("OPENM…

STM32MP157驱动开发——Linux DAC驱动

STM32MP157驱动开发——Linux DAC驱动0.前言一、DAC 简介二、驱动源码分析1.设备树下的 DAC 节点2.驱动源码分析1&#xff09;stm32_dac 结构体2&#xff09;stm32_adc_probe 函数3&#xff09;stm32_dac_iio_info 结构体三、驱动开发1.修改设备树2.使能DAC驱动四、 运行测试0.…

读书笔记 -公司改造 和 紧迫感

读书笔记 -公司改造 - 三枝匡 读书笔记 -公司改造 - 三枝匡 2022 年夏天的时候在微信读书上读了这本书&#xff0c;这是我们 CSDN 的创始人蒋涛推荐的&#xff0c;当时记了一些笔记如下。 总结&#xff1a; 每个有一定的历史&#xff0c;比较成功、或者尚未非常成功的公司遇…

基于Java+SpringBoot+vue+element实现毕业就业招聘系统

基于JavaSpringBootvueelement实现毕业就业招聘系统 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获取源码…

用最简单的案例带你掌握C++中各种指针

1、前言 指针&#xff0c;作为C/C中最神秘、功能最强大的语法&#xff0c;着实是难以理解 、难以掌握、难以运用。&#x1f625; 但是&#xff0c;能灵活的使用指针&#xff0c;对利用C/C开发程序将有很大的帮助&#xff0c;让我们一起来了解了解吧。 2、啥是指针&#xff1f…

参加《2022 中国开发者影响力盛典》我的 4 重收获!

感谢 CSDN 邀请&#xff0c;西红柿有幸参加了 2022 中国开发者影响力盛典暨 CSDN 企业生态汇&#xff0c;让我有了一个不虚此行的下午&#xff0c;也跟大家分享一下我在会上的 4 重收获吧~第一重收获&#xff1a;互联网圈大佬 会议聚焦开发者生态建设主题&#xff0c;分享了 CS…

分布式基础篇4 —— 基础篇完结

分类维护一、三级分类后端实现准备工作跨域问题关闭 ESLint 检查前端实现二、分类删除前端完善分类列表后端实现——删除配置发送请求代码片段前端实现——删除三、分类增加前端实现四、分类修改五、拖拽菜单拖拽效果实现拖拽数据收集拖拽功能完成拖拽功能完善六、批量删除品牌…