Android低代码开发 - 直接创建一个下拉刷新列表界面

看了我Android低代码开发 - 让IDE帮你写代码这篇文章的小伙伴,大概都对Dora全家桶开发框架有基本的认识了吧。本篇文章将会讲解如何使用dora-studio-plugin快捷创建一个下拉刷新列表界面。

效果演示

请添加图片描述

这样直接通过图形界面的方式就创建好了下拉刷新上拉加载+空态界面+列表的基础代码,接下来开发起来就方便了。

依赖库

截屏2024-06-13 10.39.15.png

DoraTitleBar:建议用最新版本1.37

DoraEmptyLayout:必须用1.12版本

SwipeLayout和PullableRecyclerView:用1.0版本就好

IntelliJ IDEA插件1.4版本更新内容

生成布局文件的模板
/*
 * Copyright (C) 2022 The Dora Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.dorachat.templates.recipes.app_package.res.layout

fun swipeLayoutActivityXml(
        packageName: String,
  activityClass: String
) = """
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context="${packageName}.${activityClass}">

    <data>
    
    </data>
    
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <dora.widget.DoraTitleBar
            android:id="@+id/titleBar"
            android:layout_width="match_parent"
            android:layout_height="50dp"
            app:dview_title="@string/app_name"
            android:background="@color/colorPrimary"/>

        <dora.widget.DoraEmptyLayout
            android:id="@+id/emptyLayout"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
            <dora.widget.pull.SwipeLayout
                android:id="@+id/swipeLayout"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
                <include layout="@layout/layout_swipe_layout_header" />
                <dora.widget.pull.PullableRecyclerView
                    android:id="@+id/recyclerView"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:background="@color/colorPanelBg" />
                <include layout="@layout/layout_swipe_layout_footer" />
            </dora.widget.pull.SwipeLayout>
        </dora.widget.DoraEmptyLayout>
    </LinearLayout>
</layout>
"""
生成Java和Kotlin代码的模板
/*
 * Copyright (C) 2022 The Dora Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.dorachat.templates.recipes.app_package.src

fun swipeLayoutActivityKt(
        applicationPackage: String,
  packageName: String,
        activityClass: String,
  bindingName: String,
  layoutName: String
) = """
package ${packageName}

import android.os.Bundle

import dora.BaseActivity
import dora.widget.pull.SwipeLayout

import ${applicationPackage}.R
import ${applicationPackage}.databinding.${bindingName}

class ${activityClass} : BaseActivity<${bindingName}>() {

   override fun getLayoutId(): Int {
          return R.layout.${layoutName}
   }

   override fun initData(savedInstanceState: Bundle?, binding: ${bindingName}) {
          TODO("Not yet implemented")
            // For Example:
            // binding.swipeLayout.setOnSwipeListener(object : SwipeLayout.OnSwipeListener {
            //
            //     override fun onRefresh(swipeLayout: SwipeLayout) {
            //     }
            //
            //     override fun onLoadMore(swipeLayout: SwipeLayout) {
            //     }
            // })
   }
}
"""

fun swipeLayoutActivity(
        applicationPackage: String,
        packageName: String,
        activityClass: String,
        bindingName: String,
        layoutName: String
) = """
package ${packageName};

import android.os.Bundle;
import androidx.annotation.Nullable;

import dora.BaseActivity;
import dora.widget.pull.SwipeLayout;

import ${applicationPackage}.R;
import ${applicationPackage}.databinding.${bindingName};

public class ${activityClass} extends BaseActivity<${bindingName}> {

   @Override
    protected int getLayoutId() {
        return R.layout.${layoutName};
    }

   @Override
    public void initData(@Nullable Bundle savedInstanceState, ${bindingName} binding) {
        // TODO: Not yet implemented
        // For Example:
        // binding.swipeLayout.setOnSwipeListener(new SwipeLayout.OnSwipeListener() {
        //
        //     @Override
        //     public void onRefresh(SwipeLayout swipeLayout) {
        //     }
        //     
        //     @Override
        //     public void onLoadMore(SwipeLayout swipeLayout) {
        //     }
        // });
   }
}
"""
DoraTemplateRecipe.kt新增生成代码的方法

fun RecipeExecutor.swipeLayoutActivityRecipe(
    moduleData: ModuleTemplateData,
    activityClass: String,
    activityTitle: String,
    layoutName: String,
    packageName: String
) {
    val (projectData, srcOut, resOut) = moduleData

    generateManifest(
        moduleData = moduleData,
        activityClass = activityClass,
        packageName = packageName,
        isLauncher = false,
        hasNoActionBar = false,
        generateActivityTitle = false
    )

    if (projectData.language == Language.Kotlin) {
        save(
            swipeLayoutActivityKt(projectData.applicationPackage ?: packageName, packageName, activityClass,
                buildBindingName(layoutName), layoutName), srcOut.resolve("${activityClass}.${projectData.language.extension}"))
    }
    if (projectData.language == Language.Java) {
        save(swipeLayoutActivity(projectData.applicationPackage ?: packageName, packageName, activityClass,
            buildBindingName(layoutName), layoutName), srcOut.resolve("${activityClass}.${projectData.language.extension}"))
    }
    save(swipeLayoutActivityXml(packageName, activityClass), resOut.resolve("layout/${layoutName}.xml"))

    open(resOut.resolve("layout/${layoutName}.xml"))

}
新增一个向导界面模板
/*
 * Copyright (C) 2022 The Dora Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.dorachat.templates.recipes

import com.android.tools.idea.wizard.template.*
import com.android.tools.idea.wizard.template.impl.activities.common.MIN_API
import java.io.File

object SwipeLayoutActivityTemplate : Template {
    override val category: Category
        get() = Category.Activity
    override val constraints: Collection<TemplateConstraint>
        get() = emptyList()     // AndroidX, kotlin
    override val description: String
        get() = "创建一个dora.BaseActivity,来自https://github.com/dora4/dora"
    override val documentationUrl: String?
        get() = null
    override val formFactor: FormFactor
        get() = FormFactor.Mobile
    override val minSdk: Int
        get() = MIN_API
    override val name: String
        get() = "SwipeLayout DataBinding Activity"
    override val recipe: Recipe
        get() = {
            swipeLayoutActivityRecipe(
                    it as ModuleTemplateData,
                    activityClassInputParameter.value,
                    activityTitleInputParameter.value,
                    layoutNameInputParameter.value,
                    packageName.value
            )
        }
    override val uiContexts: Collection<WizardUiContext>
        get() = listOf(WizardUiContext.ActivityGallery, WizardUiContext.MenuEntry, WizardUiContext.NewProject, WizardUiContext.NewModule)
    override val useGenericInstrumentedTests: Boolean
        get() = false
    override val useGenericLocalTests: Boolean
        get() = false

    override val widgets: Collection<Widget<*>>
        get() = listOf(
                TextFieldWidget(activityTitleInputParameter),
                TextFieldWidget(activityClassInputParameter),
                TextFieldWidget(layoutNameInputParameter),
                PackageNameWidget(packageName),
                LanguageWidget()
        )

    override fun thumb(): Thumb {
        return Thumb { findResource(this.javaClass, File("template_activity.png")) }
    }

    val activityClassInputParameter = stringParameter {
        name = "Activity Name"
        default = "MainActivity"
        help = "The name of the activity class to create"
        constraints = listOf(Constraint.CLASS, Constraint.UNIQUE, Constraint.NONEMPTY)
        suggest = { layoutToActivity(layoutNameInputParameter.value) }
    }

    var layoutNameInputParameter: StringParameter = stringParameter {
        name = "Layout Name"
        default = "activity_main"
        help = "The name of the layout to create for the activity"
        constraints = listOf(Constraint.LAYOUT, Constraint.UNIQUE, Constraint.NONEMPTY)
        suggest = { activityToLayout(activityClassInputParameter.value) }
    }

    val activityTitleInputParameter = stringParameter {
        name = "Title"
        default = "Main"
        help = "The name of the activity. For launcher activities, the application title"
        visible = { false }
        constraints = listOf(Constraint.NONEMPTY)
        suggest = { buildClassNameWithoutSuffix(activityClassInputParameter.value, "Activity") }
    }
    val packageName = defaultPackageNameParameter
}
将向导界面模板添加到向导模板提供者
/*
 * Copyright (C) 2022 The Dora Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.dorachat.templates.recipes

import com.android.tools.idea.wizard.template.WizardTemplateProvider

class DoraTemplateWizardProvider: WizardTemplateProvider() {
    override fun getTemplates() = listOf(
            DataBindingActivityTemplate,
            DataBindingFragmentTemplate,
            MenuPanelActivityTemplate,
            SwipeLayoutActivityTemplate,
            MVVMActivityTemplate,
            MVVMFragmentTemplate)
}
更新版本日志
patchPluginXml {
    version.set("${project.version}")
    sinceBuild.set("213")
    untilBuild.set("223.*")
    changeNotes.set("""
    <h3>1.4</h3>
  新增对SwipeLayout的支持<br/>
    <h3>1.3</h3>
  新增对MenuPanel的支持<br/>
    <h3>1.2</h3>
  新增对BaseVMActivity和BaseVMFragment的支持<br/>
    <h3>1.1</h3>
  initData()方法中增加databinding参数<br/>
    <h3>1.0</h3>
  初始版本,能够创建Java和Kotlin版本的MVVM Activiy和MVVM Fragment<br/>
  """)
}

代码讲解

DoraEmptyLayout为什么可以识别SwipeLayout里面的RecyclerView?
open fun showContent() {
    runMain {
        if (contentView is RecyclerView) {
            if ((contentView as RecyclerView).adapter == null ||
                    (contentView as RecyclerView).adapter!!.itemCount == 0) {
                showEmpty()
                return@runMain
            }
        }
        // 1.12开始支持遍历容器,确保一个EmptyLayout里面只能放一个RecyclerView
        if (contentView is ViewGroup) {
            for (i in 0 until childCount) {
                val view = getChildAt(i)
                if (view is RecyclerView) {
                    if (view.adapter == null ||
                        view.adapter!!.itemCount == 0) {
                        showEmpty()
                        return@runMain
                    }
                }
            }
        }
        val view = showStateView(STATE_CONTENT)
        this.content?.invoke(view)
    }
}

我们可以看到DoraEmptyLayout类从1.11升级到1.12版本的过程中,新增了以下代码来支持SwipeLayout。

if (contentView is ViewGroup) {
    for (i in 0 until childCount) {
        val view = getChildAt(i)
        if (view is RecyclerView) {
            if (view.adapter == null ||
                        view.adapter!!.itemCount == 0) {
                showEmpty()
                return@runMain
            }
        }
    }
}        

这样就不难理解了,如果遇到了刷新布局,如SwipeLayout,就再解析一层找RecyclerView。当然,一个DoraEmptyLayout里面只能放一个RecyclerView。

SwipeLayout是何方神圣?
  • 支持暗色模式
  • 支持英语、阿拉伯语、德语、西班牙语、法语、意大利语、日语、韩语、葡萄牙语、俄语、泰语、越南语、简体中文和繁体中文等世界10几个主流语种
  • 支持自定义可拉动的内容布局
  • 支持插件创建
  • 与DoraEmptyLayout空态布局完美兼容(需要使用v1.12以上版本)
  • 界面丝滑
通过PullableRecyclerView源码来看怎么自定义可拉动的内容布局
package dora.widget.pull

import android.content.Context
import android.util.AttributeSet
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import dora.widget.swipelayout.R

class PullableRecyclerView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null,
                                                     defStyle: Int = 0)
                                                : RecyclerView(context, attrs, defStyle), Pullable {

    private var canPullDown = true
    private var canPullUp = true

    init {
        val a = context.obtainStyledAttributes(attrs, R.styleable.PullableRecyclerView, defStyle, 0)
        canPullDown = a.getBoolean(R.styleable.PullableRecyclerView_dview_canPullDown, canPullDown)
        canPullUp = a.getBoolean(R.styleable.PullableRecyclerView_dview_canPullUp, canPullUp)
        a.recycle()
    }

    fun setCanPullDown(canPullDown: Boolean) {
        this.canPullDown = canPullDown
    }

    fun setCanPullUp(canPullUp: Boolean) {
        this.canPullUp = canPullUp
    }

    override fun canPullDown(): Boolean {
        return if (canPullDown) {
            val layoutManager = layoutManager as LinearLayoutManager?
            val adapter = adapter
            if (adapter != null) {
                return if (adapter.itemCount == 0) {
                    false
                } else layoutManager!!.findFirstVisibleItemPosition() == 0
                    && getChildAt(0).top >= 0
            }
            false
        } else {
            false
        }
    }

    override fun canPullUp(): Boolean {
        if (canPullUp) {
            val layoutManager = layoutManager as LinearLayoutManager
            if (adapter != null && adapter?.itemCount!! == 0) {
                return false
            } else if (layoutManager.findLastVisibleItemPosition() == ((adapter as Adapter).itemCount - 1)) {
                // 滑到底部了
                if (getChildAt(layoutManager.findLastVisibleItemPosition() - layoutManager.findFirstVisibleItemPosition()) != null
                        && getChildAt(
                        layoutManager.findLastVisibleItemPosition()
                                - layoutManager.findFirstVisibleItemPosition()).bottom <= measuredHeight
                ) {
                    return true
                }
            }
            return false
        } else {
            return false
        }
    }
}

它实现了一个顶层接口Pullable,通过canPullDown()canPullUp()两个方法来在运行时动态判断可不可以下拉刷新和上拉加载。

private var canPullDown = true
private var canPullUp = true

里面提供了两个属性,表示是否有下拉和上拉能力,如果设置为false,则无论条件达成与否都不能进行刷新和加载。

<dora.widget.pull.PullableRecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/colorPanelBg"
    app:dview_canPullDown="true"
    app:dview_canPullUp="false"/>

可以通过属性设置这两个变量,比如不需要上拉加载就把上拉的设置为false,app:dview_canPullUp=“false”。

设置完成刷新和加载的监听
binding.swipeLayout.setOnSwipeListener(new SwipeLayout.OnSwipeListener() {

    @Override
    public void onRefresh(SwipeLayout swipeLayout) {
    }

    @Override
    public void onLoadMore(SwipeLayout swipeLayout) {
    }
});

通过调用swipeLayout的refreshFinish(state)loadMoreFinish(state)来结束刷新和加载状态。

const val SUCCEED = 0
const val FAIL = 1

有成功和失败两种状态可以设置。所以,你在onRefresh()或onLoadMore()的最后一行调用刷新状态即可。

源码链接

下拉刷新:https://github.com/dora4/dview-swipe-layout

空态布局:https://github.com/dora4/dview-empty-layout

代码生成插件:https://github.com/dora4/dora-studio-plugin

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何高效管理和监控 Elasticsearch 别名及索引?

0、引言 在 Elasticsearch 项目中&#xff0c;管理和监控索引是开发者的一项重要任务。 尤其是当我们需要在项目的管理部分展示索引和别名的统计信息时&#xff0c;了解如何有效地列出这些别名和索引显得尤为重要。 本篇博客将介绍几种在 Elasticsearch 中列出别名和索引的方法…

用表头设置控制表格内列的排序和显示隐藏

项目背景 : react ant 需求 : 点击表头设置弹窗 , 拖拽可控制外部表格列的排序 , 开关可控制外部表格列的显示和隐藏 实现效果如下 :注意 : 1. 拖拽效果参考了ant-table中的拖拽效果(这块代码放最后) 2. 后台反了json格式(用is_show控制显示和隐藏 , 我给他传…

【应用案例】如何解决无人驾驶车辆的动力转向问题

埃尔朗根-纽伦堡大学名称为高能赛车运动队(High-Octane Motorsports e.V.)的学生方程式车队都设计、构建和制造具有创新意义且独特的赛车。然后&#xff0c;他们将参加三种不同类别的大学生方程式比赛&#xff1b;该项赛事中的参赛队伍来自于世界各地。 电动、无人驾驶和燃油车…

17.路由配置与页面创建

路由配置与页面创建 官网&#xff1a;https://router.vuejs.org/zh/ Vue Router 和 组合式 API | Vue Router (vuejs.org) 1. 修改index.ts import { RouteRecordRaw, createRouter, createWebHistory } from "vue-router"; import Layout from /layout/Index.vueco…

python长方形周长面积 2024年3月青少年编程电子学会python编程等级考试二级真题解析

目录 python长方形周长面积 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序代码 四、程序说明 五、运行结果 六、考点分析 七、 推荐资料 1、蓝桥杯比赛 2、考级资料 3、其它资料 python长方形周长面积 2024年3月 python编程等级考试级编程题 一、…

linux系统宝塔服务器temp文件夹里总是被上传病毒php脚本

目录 简介 上传过程 修复上传漏洞 tmp文件夹总是被上传病毒文件如下图: 简介 服务器时不时的会发送短信说你服务器有病毒, 找到了这个tmp文件, 删除了之后又有了。 确实是有很多人就这么无聊, 每天都攻击你的服务器。 找了很久的原因, 网上也提供了一大堆方法,…

天锐绿盾 | 无感知加密软件、透明加密系统、数据防泄漏软件

摘要&#xff1a;文件加密软件,包含禁止非授权的文件泄密和抄袭复制解决方案即使被复制泄密都是自动加密无法阅读,透明加密,反复制软件,内网监控,文件加密,网络安全方案,透明文件加密,加密文件,图纸加密,知识产权保护,加密数据; 通过绿盾信息安全管理软件&#xff0c;系统在不改…

2024/06/13--代码随想录算法2/17| 62.不同路径、63. 不同路径 II、343. 整数拆分 (可跳过)、96.不同的二叉搜索树 (可跳过)

62.不同路径 力扣链接 动态规划5步曲 确定dp数组&#xff08;dp table&#xff09;以及下标的含义&#xff1a; dp[i][j] &#xff1a;表示从&#xff08;0 &#xff0c;0&#xff09;出发&#xff0c;到(i, j) 有dp[i][j]条不同的路径。确定递推公式&#xff0c;dp[i][j] d…

Java——递归

一、递归介绍 1、什么是递归 递归在Java编程中是指一个方法调用自身的编程技巧。 public static void foo() {//...foo();//方法调用自身//...} 2、递归用于什么场景 递归是一种常见的算法设计方法&#xff0c;特别适用于解决那些可以分解为相似子问题的问题。常见的递归问…

诺派克ROPEX控制器维修RES-5008 RES-5006

德国希尔科诺派克ROPEX热封控制器维修型号包括&#xff1a;RES-401&#xff0c;RES-402&#xff0c;RES-403&#xff0c;RES-406&#xff0c;RES-407&#xff0c;RES-408&#xff0c;RES-409&#xff0c;RES-420&#xff0c;RES-440&#xff0c;RES-5008&#xff0c;RES-5006&a…

阿里三面:Redis大key怎么处理?

阿里三面&#xff1a;Redis大key怎么处理&#xff1f; 一、什么是大key&#xff1f; 首先大key不是key很大而是key对应的value值很大,一般而言如果String类型值大于10KB&#xff0c;Hash&#xff0c;Set&#xff0c;Zset&#xff0c;List类型的元素的个数大于5000个都可以称之…

18. 《C语言》——【Nice2016年校招笔试题引发的思考】

亲爱的读者&#xff0c;大家好&#xff01;我是一名正在学习编程的高校生。在这个博客里&#xff0c;我将和大家一起探讨编程技巧、分享实用工具&#xff0c;并交流学习心得。希望通过我的博客&#xff0c;你能学到有用的知识&#xff0c;提高自己的技能&#xff0c;成为一名优…

中国版Sora?快手「可灵」到底行不行?

“可灵”与Sora有相似的技术架构&#xff0c;生成的视频动作流畅、幅度大&#xff0c;对物理世界理解力与还原度很高。可生成120秒、每秒30帧的高清视频&#xff0c;分辨率高达1080p&#xff0c;并且支持多种不同的屏幕比例。 “中国版SORA”到底是不是名副其实&#xff1f;能…

谷歌浏览器124版本Webdriver驱动下载

查看谷歌浏览器版本 在浏览器的地址栏输入&#xff1a; chrome://version/回车后即可查看到对应版本(不要点击帮助-关于Google chrome&#xff0c;因为点击后会自动更新谷歌版本) 114之前版本&#xff1a;下载链接 ​​​​​​123以后版本&#xff1a;下载链接&#xff0…

【机器学习】通用大模型VS垂直大模型,你更加青睐哪一方?

目录 前言AI大模型的战场&#xff1a;通用与垂直的分化通用大模型&#xff1a;广泛适用的利器垂直大模型&#xff1a;深入领域的利器谁能够形成绝对优势&#xff1f;结语通用大模型文章推荐 前言 AI大模型的战场正在分化&#xff1a; 通用大模型在落地场景更广泛毋庸置疑&…

idea插件开发之实现设置信息持久化存储

写在前面 在idea中设置的信息&#xff0c;我们重启idea后&#xff0c;这些信息还是在的&#xff0c;这其实是通过idea插件的持久化存储功能实现的&#xff0c;本文一起来看下如何实现。 1&#xff1a;正戏 为了方便测试&#xff0c;首先定义如下的ui: 我们需要在代码中给按…

干货分享:宏集物联网HMI通过S7 MPI协议采集西门子400PLC数据

前言 为了实现和西门子PLC的数据交互&#xff0c;宏集物联网HMI集成了S7 PPI、S7 MPI、S7 Optimized、S7 ETH等多个驱动来适配西门子200、300、400、1200、1500、LOGO等系列PLC。 本文主要介绍宏集HMI通过S7 MPI协议采集西门子400PLC数据的操作步骤&#xff0c;其他协议的操作…

C++入门 string的模拟实现

目录 再谈swap string常见接口模拟实现 构造函数 & 析构函数 拷贝构造 & 赋值运算符重载 begin迭代器 & end迭代器 size & swap & clear & c_str operator[ ] & reserve push_back & append operator & find insert & erase…

计算机网络之网络层知识总结

网络层功能概述 主要任务 主要任务是把分组从源端传到目的端&#xff0c;为分组交换网上的不同主机提供通信服务。网络层传输单位是数据报。 分组和数据报的关系&#xff1a;把数据报进行切割之后&#xff0c;就是分组。 主要功能&#xff1a; 路由选择与分组转发 路由器…

openh264 编码器源码分析:WelsCodeOneSlice 函数

介绍 功能&#xff1a;openh264 编码每个 slice 的核心函数原型&#xff1a; int32_t WelsCodeOneSlice (sWelsEncCtx* pEncCtx, SSlice* pCurSlice, const int32_t kiNalType)参数&#xff1a; pEncCtx&#xff1a;指向编码上下文结构体sWelsEncCtx的指针&#xff0c;包含编…