Android进阶之多级列表

遇到一个需求需要显示多级列表,因为界面是在平板上的,所以层级是从左向右往下排的,类似于
在这里插入图片描述
我当时的写法是在xml布局里一个个RecyclerView往下排的

在这里插入图片描述
当然前提是已经规定好最大的层级我才敢如此去写界面,如果已经明确规定只有两级或者三级,当然如果可以的话,不管多少级都这么写也是没毛病的

作为一名开发者,如果以后也用到类似的需求,并且级数不是固定的话,这么写肯定是有很多瑕疵的,所以想着怎么样去做一个轮子,以后遇到直接拿来用就行,不用每次都去搭界面,写逻辑,当然网络上也有类似的代码,但是感觉和自己的有多少出入,那不如自己来写一套吧

下面是效果图,界面有些丑,没有花时间去做一些美化,只是为了展示不同的效果,毕竟真正用起来界面样式还是多样化没法固定的

在这里插入图片描述
在这里插入图片描述
首先的问题是如何去分级,一开始想法是把所有数据放进入,自己去解析数据进行分级,但是又可能涉及到部分数据需要网络请求等复杂的环境

问题一: 如何解决一开始就分级还是点击之后逐级显示?

答: 自主触发,不自行解析添加,告诉我添加我再去添加

问题二: 不同条件下如何去分级?

答: 要定义一个自己的规则,可能不完善但是后面可以自己添加,否则出现要写死或者部分要网络请求的时候无法完整判断,而且不同的数据结构可能连参数名字都不一样,所以需要自主分类并且添加数据

思路:

1.一开始传入最大多少级,以及每一级的样式(比如宽度,背景),动态创建对应级数的列表并和适配器存储起来(别忘了关闭界面的时候或者不使用的时候去销毁),这样就不会存在每次点击都重新创建列表的情况,每次点击只是对应的显示隐藏和替换数据而已

2.我需要创建第一级的时候,我将第一级的数据筛选出来,将步骤1存储的第一级适配器拿出来塞数据

3.如果我一开始就要将第一级相关的全部显示出来我只要自己去根据数据筛选出对应的下一级,继续往里面塞

4.如果我要点击之后显示,那我也和第三步骤一样,点击之后我再去筛选,再去塞数据

5.我点之后要将所有下面的级数隐藏,在去显示对应的层级,否则就会出现我已经出现了三级,此时我点击其他的层级没有第三极,但是上次的第三极还在那显示

6.样式问题,不同的需求有不同的样式,这点无能为力,只能自己去修改样式,但是最基础的每一级的宽度,间距,背景,以及每一个条目的字体大小,高度是必须的,我可以统一规定起来

具体实现:

首先导入用到的三方依赖

 implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.4'

其中的适配器里的实体类要根据自己的情况去更改

1.创建多级列表:

xml布局里的主布局要用约束布局
将不同层级样式给Util去创建

        //这个集合存储的是每一层级的样式以及信息,会根据该集合的长度去创建最大多少级
        val mList: ArrayList<GetListUtils.GetListData> = arrayListOf()
        //第一级样式
        mList.add(GetListUtils.GetListData(width = 200,itemSize = 16f,itemHeight = 160, bGround = "#CC00FFFF"))
        //第二级样式
        mList.add(GetListUtils.GetListData(itemSize = 14f,itemHeight = 140,leftMargin = 60, bDrawable = getDrawable(R.mipmap.ic_launcher)))
        //第三极样式
        mList.add(GetListUtils.GetListData(width = 180,itemSize = 12f,itemHeight = 120,leftMargin = 80,bGround = "#CC33ff00"))
        //第四级样式
        mList.add(GetListUtils.GetListData(itemSize = 10f,itemHeight = 100,leftMargin = 30,bGround = "#CCFFFF33"))
        //第五级样式
        mList.add(GetListUtils.GetListData(itemSize = 8f,itemHeight = 80,leftMargin = 70))

        //这里是布局里的主布局,要用约束布局!!!
        val clAll = findViewById<ConstraintLayout>(R.id.cl_all)
        //层级列表和主布局传进去
        GetListUtils.find(clAll,context = this,mList)

2.自行分类,将数据塞给对应的层级,这里是筛选出第一级数据,并把数据给第一级

这里的模拟数据集合就需要替换成项目中真正的数据类了(TestData)

        //模拟数据 type当前类型 parentType 父级,默认parentType = 0 为一级
        val mListAll: ArrayList<GetListUtils.TestData> = arrayListOf()

        mListAll.add(GetListUtils.TestData(name = "美食",type = 1, parentType = 0))
        mListAll.add(GetListUtils.TestData("饮品",2,0))

        mListAll.add(GetListUtils.TestData("西瓜",3,1))
        mListAll.add(GetListUtils.TestData("火龙果",4,1))
        mListAll.add(GetListUtils.TestData("葡萄",5,1))
        mListAll.add(GetListUtils.TestData("橘子",6,1))
        mListAll.add(GetListUtils.TestData("可乐",7,2))
        mListAll.add(GetListUtils.TestData("雪碧",8,2))
        mListAll.add(GetListUtils.TestData("美年达",9,2))

        mListAll.add(GetListUtils.TestData("西瓜汁",10,3))
        mListAll.add(GetListUtils.TestData("冰镇西瓜",11,3))
        mListAll.add(GetListUtils.TestData("火龙果块",12,4))
        mListAll.add(GetListUtils.TestData("冰葡萄",13,5))
        mListAll.add(GetListUtils.TestData("橘子汁",14,6))
        mListAll.add(GetListUtils.TestData("无糖可乐",15,7))
        mListAll.add(GetListUtils.TestData("满糖可乐",16,7))

        mListAll.add(GetListUtils.TestData("西瓜皮",17,11))
        mListAll.add(GetListUtils.TestData("西瓜籽",18,11))
        mListAll.add(GetListUtils.TestData("西瓜瓤",19,11))
        mListAll.add(GetListUtils.TestData("火龙果籽",20,12))
        mListAll.add(GetListUtils.TestData("橘子皮",21,14))
        mListAll.add(GetListUtils.TestData("橘子核",22,14))

        mListAll.add(GetListUtils.TestData("西瓜子",23,18))


        //筛选一级目录
        val mList1: ArrayList<GetListUtils.TestData> = arrayListOf()
        mListAll.forEach {
            if (it.parentType == 0){
                mList1.add(it)
            }
        }
        //设置一级目录
        GetListUtils.setListData(1,mList1,object :GetListUtils.OnListener{
            override fun onClick(l: GetListUtils.TestData) {
                

            }
        })

默认显示对应的层级,只需要继续筛选,继续塞数据即可

        //筛选二级目录
        val mList2: ArrayList<GetListUtils.TestData> = arrayListOf()
        mListAll.forEach {
            if (it.parentType == 1){
                mList1.add(it)
            }
        }
        GetListUtils.setListData(2,mList2,object :GetListUtils.OnListener{
            override fun onClick(l: GetListUtils.TestData) {
            }

        })

以上就是使用方式, setListData(当前层级,层级数据,点击事件回调)

以下全部代码,供参考

GetListUtils
/**
 * 动态添加集合
 * */
object GetListUtils {

    private val mRVList: ArrayList<RecyclerView> = arrayListOf()
    private val mAdapterList: ArrayList<QnZtListAdapter> = arrayListOf()
    private var mParentView: ConstraintLayout? = null

    fun find(view: ConstraintLayout, //父控件
             context: Context, //上下文
             gradle: ArrayList<GetListData>, //几级
    ){
        clearList()
        mParentView = view
        for (i in 0 until gradle.size){
            val mGradle = gradle[i]
            val mRecyclerView = RecyclerView(context)
            mRecyclerView.id = View.generateViewId()
            mRVList.add(mRecyclerView)
            val layoutParams = ConstraintLayout.LayoutParams(
                mGradle.width,
                ViewGroup.LayoutParams.WRAP_CONTENT
            )
            if (i == 0){
                layoutParams.startToStart = view.id
                layoutParams.topToTop = view.id

                if (mGradle.leftMargin != 0){
                    layoutParams.leftMargin = mGradle.leftMargin
                }
            }else{
                layoutParams.startToEnd = mRVList[i-1].id
                layoutParams.topToTop = mRVList[i-1].id

                if (mGradle.leftMargin != 0){
                    layoutParams.leftMargin = mGradle.leftMargin
                }
            }
            //背景图优先级高
            if (mGradle.bDrawable != null){
                mRecyclerView.background = mGradle.bDrawable
            }else{
                if (mGradle.bGround.isNotEmpty()){
                    mRecyclerView.setBackgroundColor(Color.parseColor(mGradle.bGround))
                }
            }
            mRecyclerView.layoutParams = layoutParams
            mRecyclerView.layoutManager = LinearLayoutManager(context)
            mRecyclerView.itemAnimator = DefaultItemAnimator()

            val mAdapter = QnZtListAdapter(R.layout.item_get_list,mGradle)
            mRecyclerView.adapter = mAdapter
            mAdapterList.add(mAdapter)
            view.addView(mRecyclerView)
        }
    }

    //设置数据
    fun setListData(i: Int, l: ArrayList<TestData>,k: OnListener){
        val a = getAdapter(i)
        if (a != null){
            a.setList(l)
            a.setOnItemClickListener { adapter, view, position ->
                //点击当前层级,隐藏下一层级
                for (j in 0 until mRVList.size){
                    //这里减一是因为点击的时候是i点击的当前级数,要从下一级开始
                    if (j > i-1){
                        mRVList[j].visibility = View.GONE
                    }
                }
                //这里加一是因为i是当前级数,要从下一级开始
                //下标从零开始为什么还要加一呢?因为获取列表里面减一了
                if (getList(i+1) != null){
                    getList(i+1)!!.visibility = View.VISIBLE
                }
                val mData = adapter.data as ArrayList<TestData>
                //回调
                k.onClick(mData[position])
                //更新选中状态
                mData.forEach {
                    it.select = false
                }
                mData[position].select = true
                adapter.notifyDataSetChanged()
            }
        }
    }

    //获取对应层级的列表
    private fun getList(i: Int): RecyclerView?{
        var mL: RecyclerView? = null
        if (mRVList.isNotEmpty() && i-1 < mRVList.size){
            try {
                mL = mRVList[i - 1]
            }catch (e: java.lang.Exception){
                e.printStackTrace()
            }
        }
        return mL
    }

    //获取对应层级的适配器
    private fun getAdapter(i: Int): QnZtListAdapter?{
        var mAdapter: QnZtListAdapter? = null
        if (mAdapterList.isNotEmpty() && i-1 < mAdapterList.size){
            try {
                mAdapter = mAdapterList[i - 1]
            }catch (e: java.lang.Exception){
                e.printStackTrace()
            }
        }
        return mAdapter
    }

    //置空操作
    fun clearList(){
        mRVList.clear()
        mAdapterList.clear()
        if (mParentView != null){
            mParentView!!.removeAllViews()
        }
    }

    interface OnListener {
        fun onClick(l: TestData)
    }

    //需要的数据类
    data class GetListData(
        var width: Int = ViewGroup.LayoutParams.WRAP_CONTENT, //宽度
        var leftMargin: Int = 0, //左间距
        var bGround: String = "", //背景颜色
        var bDrawable: Drawable? = null, //背景图片
        var itemSize: Float = 0f, //条目字体大小
        var itemHeight: Int = ViewGroup.LayoutParams.WRAP_CONTENT, //条目字体高度
    ):java.io.Serializable

    //模拟数据
    data class TestData(
        var name: String? = "", //名称
        var type: Int? = 0, //分类
        var parentType: Int? = 0, //父类
        var select: Boolean = false //是否选中
    ):java.io.Serializable


    class QnZtListAdapter : BaseQuickAdapter<GetListUtils.TestData, BaseViewHolder> {

        constructor(layoutResId: Int) : super(layoutResId) {}

        private var gradle: GetListUtils.GetListData? = null

        constructor(layoutResId: Int, data: GetListUtils.GetListData) : super(layoutResId) {
            this.gradle = data
        }

        override fun convert(helper: BaseViewHolder, item: GetListUtils.TestData) {
            //总布局
            val clGetList = helper.getView<ConstraintLayout>(R.id.cl_get_list)
            //第一条不显示分割线
            if (helper.adapterPosition == 0){
                helper.setGone(R.id.view_line,true)
            }

            val tvGetTxt = helper.getView<TextView>(R.id.tv_get_txt)
            tvGetTxt.text = item.name

            if (item.select){
                tvGetTxt.setTextColor(Color.RED)
            }else{
                tvGetTxt.setTextColor(Color.GRAY)
            }

            if (gradle != null){
                //界面高度
                if (gradle!!.itemHeight != 0){
                    val lp: ViewGroup.LayoutParams = clGetList.layoutParams
                    lp.height = gradle!!.itemHeight
                    clGetList.layoutParams = lp
                }
                //字体大小
                if (gradle!!.itemSize != 0f){
                    tvGetTxt.textSize = gradle!!.itemSize
                }

            }
        }

    }
}
item_get_list
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    android:id="@+id/cl_get_list"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <View
        android:id="@+id/view_line"
        android:layout_width="0dp"
        android:layout_height="1px"
        android:background="#CC666666"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>

    <TextView
        android:id="@+id/tv_get_txt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        tools:text = "哈哈哈"/>

</androidx.constraintlayout.widget.ConstraintLayout>
AddListActivity
/**
 * 动态创建多级列表*/
class AddListActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_add_list)

        //这个集合存储的是每一层级的样式以及信息,会根据该集合的长度去创建最大多少级
        val mList: ArrayList<GetListUtils.GetListData> = arrayListOf()
        //第一级样式
        mList.add(GetListUtils.GetListData(width = 200,itemSize = 16f,itemHeight = 160, bGround = "#CC00FFFF"))
        //第二级样式
        mList.add(GetListUtils.GetListData(itemSize = 14f,itemHeight = 140,leftMargin = 60, bDrawable = getDrawable(R.mipmap.ic_launcher)))
        //第三极样式
        mList.add(GetListUtils.GetListData(width = 180,itemSize = 12f,itemHeight = 120,leftMargin = 80,bGround = "#CC33ff00"))
        //第四级样式
        mList.add(GetListUtils.GetListData(itemSize = 10f,itemHeight = 100,leftMargin = 30,bGround = "#CCFFFF33"))
        //第五级样式
        mList.add(GetListUtils.GetListData(itemSize = 8f,itemHeight = 80,leftMargin = 70))

        //这里是布局里的主布局,要用约束布局!!!
        val clAll = findViewById<ConstraintLayout>(R.id.cl_all)
        //层级列表和主布局传进去
        GetListUtils.find(clAll,context = this,mList)

        //模拟数据 type当前类型 parentType 父级,默认parentType = 0 为一级
        val mListAll: ArrayList<GetListUtils.TestData> = arrayListOf()

        mListAll.add(GetListUtils.TestData(name = "美食",type = 1, parentType = 0))
        mListAll.add(GetListUtils.TestData("饮品",2,0))

        mListAll.add(GetListUtils.TestData("西瓜",3,1))
        mListAll.add(GetListUtils.TestData("火龙果",4,1))
        mListAll.add(GetListUtils.TestData("葡萄",5,1))
        mListAll.add(GetListUtils.TestData("橘子",6,1))
        mListAll.add(GetListUtils.TestData("可乐",7,2))
        mListAll.add(GetListUtils.TestData("雪碧",8,2))
        mListAll.add(GetListUtils.TestData("美年达",9,2))

        mListAll.add(GetListUtils.TestData("西瓜汁",10,3))
        mListAll.add(GetListUtils.TestData("冰镇西瓜",11,3))
        mListAll.add(GetListUtils.TestData("火龙果块",12,4))
        mListAll.add(GetListUtils.TestData("冰葡萄",13,5))
        mListAll.add(GetListUtils.TestData("橘子汁",14,6))
        mListAll.add(GetListUtils.TestData("无糖可乐",15,7))
        mListAll.add(GetListUtils.TestData("满糖可乐",16,7))

        mListAll.add(GetListUtils.TestData("西瓜皮",17,11))
        mListAll.add(GetListUtils.TestData("西瓜籽",18,11))
        mListAll.add(GetListUtils.TestData("西瓜瓤",19,11))
        mListAll.add(GetListUtils.TestData("火龙果籽",20,12))
        mListAll.add(GetListUtils.TestData("橘子皮",21,14))
        mListAll.add(GetListUtils.TestData("橘子核",22,14))

        mListAll.add(GetListUtils.TestData("西瓜子",23,18))


        //筛选一级目录
        val mList1: ArrayList<GetListUtils.TestData> = arrayListOf()
        mListAll.forEach {
            if (it.parentType == 0){
                mList1.add(it)
            }
        }
        //设置一级目录
        GetListUtils.setListData(1,mList1,object :GetListUtils.OnListener{
            override fun onClick(l: GetListUtils.TestData) {
                //点击一级目录后筛选二级
                val mList2: ArrayList<GetListUtils.TestData> = arrayListOf()
                mListAll.forEach {
                    //还原选中状态,如果默认选中第一个用for循环去设置
                    it.select = false
                    if (l.type == it.parentType){
                        mList2.add(it)
                    }
                }
                //设置二级目录
                GetListUtils.setListData(2,mList2,object :GetListUtils.OnListener{
                    override fun onClick(l: GetListUtils.TestData) {
                        //点击二级目录后筛选三级
                        val mList3: ArrayList<GetListUtils.TestData> = arrayListOf()
                        mListAll.forEach {
                            //还原选中状态,如果默认选中第一个用for循环去设置
                            it.select = false
                            if (l.type == it.parentType){
                                mList3.add(it)
                            }
                        }
                        //设置三级目录
                        GetListUtils.setListData(3,mList3,object :GetListUtils.OnListener{
                            override fun onClick(l: GetListUtils.TestData) {
                                //点击三级目录筛选四级目录
                                val mList4: ArrayList<GetListUtils.TestData> = arrayListOf()
                                mListAll.forEach {
                                    //还原选中状态,如果默认选中第一个用for循环去设置
                                    it.select = false
                                    if (l.type == it.parentType){
                                        mList4.add(it)
                                    }
                                }
                                //设置四级目录
                                GetListUtils.setListData(4,mList4,object :GetListUtils.OnListener{
                                    override fun onClick(l: GetListUtils.TestData) {
                                        //点击四级目录筛选五级目录
                                        val mList5: ArrayList<GetListUtils.TestData> = arrayListOf()
                                        mListAll.forEach {
                                            //还原选中状态,如果默认选中第一个用for循环去设置
                                            it.select = false
                                            if (l.type == it.parentType){
                                                mList5.add(it)
                                            }
                                        }
                                        GetListUtils.setListData(5,mList5,object :GetListUtils.OnListener{
                                            override fun onClick(l: GetListUtils.TestData) {
                                                Toast.makeText(this@AddListActivity,l.name,Toast.LENGTH_SHORT).show()
                                            }
                                        })
                                    }
                                })
                            }
                        })
                    }
                })

            }
        })

    }

    override fun onDestroy() {
        super.onDestroy()
        GetListUtils.clearList()
    }
}
activity_add_list
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    android:id="@+id/cl_all"
    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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".AddListActivity">

</androidx.constraintlayout.widget.ConstraintLayout>

自测效果基本满意~ 就是要修改对应的TestData比较繁琐,后续看看能不能集中处理

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

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

相关文章

一.net core 自动化发布到docker (Jenkins安装)

目录 1.安装Jenkins 参考资料:https://www.jenkins.io/doc/book/installing/docker/#downloading-and-running-jenkins-in-docker 1.Open up a terminal window.(打开一个终端窗口。) 2.Create a bridge network in Docker using the following docker network create comma…

SpringBoot整合、SpringBoot与异步任务

目录 一、背景描述二、简单使用方法三、原理五、使用自定义线程池1、默认使用2、如何使用自定义线程池 六、Async失效情况1、同一个类中&#xff0c;一个方法调用 Async标注的方法 一、背景描述 java 的代码是同步顺序执行&#xff0c;当我们需要执行异步操作时我们通常会去创…

【Maven】SpringBoot项目使用maven-assembly-plugin插件多环境打包

SpringBoot项目使用maven-assembly-plugin插件多环境打包 1.创建SpringBoot项目并在pom.xml文件中添加maven-assembly-plugin配置 <!-- 多环境配置 --><profiles><!-- 开发环境 --><profile><id>dev</id><properties><prof…

List和ObservableCollection和ListBinding在MVVM模式下的对比

List和ObservableCollection和ListBinding在MVVM模式下的对比 List 当对List进行增删操作后&#xff0c;并不会对View进行通知。 //Employee public class Employee : INotifyPropertyChanged {public event PropertyChangedEventHandler? PropertyChanged;public string N…

聊聊在集群环境中本地缓存如何进行同步

前言 之前有发过一篇文章聊聊如何利用redis实现多级缓存同步。有个读者就给我留言说&#xff0c;因为他项目的redis版本不是6.0版本&#xff0c;因此他使用我文章介绍通过MQ来实现本地缓存同步&#xff0c;他的同步流程大概如下图 他原来的业务流程是每天凌晨开启定时器去爬取…

MPLS实验

实验题目如下&#xff1a; 实验拓扑如下&#xff1a; 实验要求如下&#xff1a; 【1】R1与R5MPLS VPN 【2】R6与R7MPLS VPN 【3】R7可以访问R2/3/4的环回 实验思路如下&#xff1a; &#xff08;1&#xff09;合理的IP配置 &#xff08;2&#xff09;R2、R3、R4的 IGP 配…

张俊林:由ChatGPT反思大语言模型(LLM)的技术精要

转自&#xff1a;https://mp.weixin.qq.com/s/eMrv15yOO0oYQ-o-wiuSyw 导读&#xff1a;ChatGPT出现后惊喜或惊醒了很多人。惊喜是因为没想到大型语言模型&#xff08;LLM,Large Language Model&#xff09;效果能好成这样&#xff1b;惊醒是顿悟到我们对LLM的认知及发展理念&a…

RabbitMQ简单使用

RabbitMq是一个消息中间件&#xff1a;它接收消息、转发消息。你可以把它理解为一个邮局&#xff1a;当你向邮箱里寄出一封信后&#xff0c;邮递员们就能最终将信送到收信人手中。 RabbitMq、消息相关术语如下&#xff1a; 生产者&#xff1a;生产者只发送消息&#xff0c;发…

怎样让音频速度变慢?请跟随以下方法进行操作

怎样让音频速度变慢&#xff1f;在会议录音过程中&#xff0c;经常会遇到主讲人语速过快&#xff0c;导致我们无法清晰听到对方说的内容。如果我们能够减慢音频速度&#xff0c;就能更好地记录对方的讲话内容。此外&#xff0c;在听到快速播放的外语或方言时&#xff0c;我们也…

YOLOv5基础知识入门(3)— 目标检测相关知识点

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。YOLO算法发展历程和YOLOv5核心基础知识学习完成之后&#xff0c;接下来我们就需要学习目标检测相关知识了。为了让大家后面可以顺利地用YOLOv5进行目标检测实战&#xff0c;本节课就带领大家学习一下目标检测的基础知识点&…

MySQL入门学习教程(一)

mysql简介 1、什么是数据库 &#xff1f; 数据库&#xff08;Database&#xff09;是按照数据结构来组织、存储和管理数据的仓库&#xff0c;它产生于距今六十多年前&#xff0c;随着信息技术和市场的发展&#xff0c;特别是二十世纪九十年代以后&#xff0c;数据管理不再仅仅…

【数据库系统】-- 【1】DBMS概述

1.DBMS概述 01数据库系统概述02数据库技术发展概述03关系数据库概述04数据库基准测试 01数据库系统概述 几个基本概念 为什么使用数据库系统 数据库发展的辉煌历程 02数据库技术发展概述 数据模型 应用领域 ● OLTP ● OLAP ● HTAP ● GIS OLTP与OLAP 与其他技术相…

代码随想录算法训练营(二叉树总结篇)

一.二叉树的种类 1.满二叉树&#xff1a;就是说每一个非叶子节点的节点都有两个子节点。 2.完全二叉树&#xff1a;此二叉树只有最后一层可能没填满&#xff0c;并且存在的叶子节点都集中在左侧&#xff01;&#xff01;&#xff01; &#xff08;满二叉树也是完全二叉树&…

【UE4 RTS】09-Day and Night

前言 本篇博客实现的效果是太阳和天空会随着游戏时间的变化而变化。 效果 步骤 1. 设置“LightSource”为可移动的 2. 新建一个文件夹&#xff0c;命名为“Lighting” 3. 打开游戏状态“RTS_GameState_BP”&#xff0c;添加一个函数命名为“GetGameSpeed” 添加一个浮点类型…

bilibili倍数脚本,油猴脚本

一. 内容简介 bilibili倍数脚本&#xff0c;油猴脚本 二. 软件环境 2.1 Tampermonkey 三.主要流程 3.1 创建javascript脚本 点击添加新脚本 就是在 (function() {use strict;// 在这编写自己的脚本 })();倍数脚本&#xff0c;含解析 // UserScript // name bi…

TikTok带货有什么优势?品牌营销的新趋势

在当今数字化时代&#xff0c;品牌营销正日益倾向于社交媒体平台&#xff0c;而TikTok作为一款全球热门的短视频社交平台&#xff0c;正在成为品牌营销的新趋势。TikTok带货&#xff0c;也就是品牌利用TikTok平台进行商品推广和销售&#xff0c;已成为一种创新的、高效的营销方…

GPT-4 如何为我编写测试

ChatGPT — 每个人都在谈论它,每个人都有自己的观点,玩起来很有趣,但我们不是在这里玩— 我想展示一些实际用途,可以帮助您节省时间并提高效率。 我在本文中使用GPT-4 动机 我们以前都见过这样的情况——代码覆盖率不断下降的项目——部署起来越来越可怕,而且像朝鲜一样…

【深入理解ES6】块级作用域绑定

1. var声明及变量提升机制 提升&#xff08;Hoisting&#xff09;机制&#xff1a;通过关键字var声明的变量&#xff0c;都会被当成在当前作用域顶部生命的变量。 function getValue(condition){if(condition){var value "blue";console.log(value);}else{// 此处…

Jetpack之MutableLiveData和LiveData源码分析

先看一下MutableLiveData的源码&#xff0c;它是继承于LiveData,主要是重写了setValue和postValue方法。 上图我们知道这两个方法都是调用了livedata的各自对应的方法&#xff0c;我们点进去看看livedata的这两个方法是protect 的 允许子类和自己调用&#xff0c;而MutableLiv…

Qt在mac安装

先在app store下载好Xcode 打开Xcode 随便建个文件给它取个名字找个地方放提醒没建立git link,不用理他打开终端, 输入/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"