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? = nullfun find(view: ConstraintLayout, //父控件context: Context, //上下文gradle: ArrayList<GetListData>, //几级){clearList()mParentView = viewfor (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.idlayoutParams.topToTop = view.idif (mGradle.leftMargin != 0){layoutParams.leftMargin = mGradle.leftMargin}}else{layoutParams.startToEnd = mRVList[i-1].idlayoutParams.topToTop = mRVList[i-1].idif (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 = layoutParamsmRecyclerView.layoutManager = LinearLayoutManager(context)mRecyclerView.itemAnimator = DefaultItemAnimator()val mAdapter = QnZtListAdapter(R.layout.item_get_list,mGradle)mRecyclerView.adapter = mAdaptermAdapterList.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 = trueadapter.notifyDataSetChanged()}}}//获取对应层级的列表private fun getList(i: Int): RecyclerView?{var mL: RecyclerView? = nullif (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? = nullif (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.Serializableclass QnZtListAdapter : BaseQuickAdapter<GetListUtils.TestData, BaseViewHolder> {constructor(layoutResId: Int) : super(layoutResId) {}private var gradle: GetListUtils.GetListData? = nullconstructor(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.nameif (item.select){tvGetTxt.setTextColor(Color.RED)}else{tvGetTxt.setTextColor(Color.GRAY)}if (gradle != null){//界面高度if (gradle!!.itemHeight != 0){val lp: ViewGroup.LayoutParams = clGetList.layoutParamslp.height = gradle!!.itemHeightclGetList.layoutParams = lp}//字体大小if (gradle!!.itemSize != 0f){tvGetTxt.textSize = gradle!!.itemSize}}}}
}
item_get_list
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayoutandroid: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"><Viewandroid: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"/><TextViewandroid: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 = falseif (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 = falseif (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 = falseif (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 = falseif (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.ConstraintLayoutandroid: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比较繁琐,后续看看能不能集中处理

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

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

相关文章

69 # 强制缓存的配置

强制缓存 强制缓存&#xff1a;以后的请求都不需要访问服务器&#xff0c;状态码为 200协商缓存&#xff1a;每次都判断一下&#xff0c;告诉是否需要找缓存&#xff0c;状态码为 304 默认强制缓存&#xff0c;不缓存首页&#xff08;如果已经断网&#xff0c;那这个页面应该…

Python发送QQ邮件

使用Python的smtplib可以发送QQ邮件&#xff0c;代码如下 #!/usr/bin/python3 import smtplib from email.mime.text import MIMEText from email.header import Headersender 111qq.com # 发送邮箱 receivers [222qq.com] # 接收邮箱 auth_code "abc" # 授权…

Dockerfile概念、镜像原理、制作及案例讲解

1.Docker镜像原理 Linux文件操作系统讲解 2.镜像如何制作 3.Dockerfile概念 Docker网址&#xff1a;https://hub.docker.com 3.1 Dockerfile关键字 4.案例

【数据结构OJ题】链表分割

原题链接&#xff1a;https://www.nowcoder.com/practice/0e27e0b064de4eacac178676ef9c9d70?tpId8&&tqId11004&rp2&ru/activity/oj&qru/ta/cracking-the-coding-interview/question-ranking 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2…

爬虫逆向实战(十七)--某某丁简历登录

一、数据接口分析 主页地址&#xff1a;某某丁简历 1、抓包 通过抓包可以发现数据接口是submit 2、判断是否有加密参数 请求参数是否加密&#xff1f; 通过查看“载荷”模块可以发现有一个enPassword加密参数 请求头是否加密&#xff1f; 通过查看请求头可以发现有一个To…

【面试高频题】难度 3/5,字典树热门运用题

题目描述 这是 LeetCode 上的 「745. 前缀和后缀搜索」 &#xff0c;难度为 「困难」。 Tag : 「字典树」 设计一个包含一些单词的特殊词典&#xff0c;并能够通过前缀和后缀来检索单词。 实现 WordFilter 类&#xff1a; WordFilter(string[] words) 使用词典中的单词 words 初…

无法将“环境变量”项识别为 cmdlet、函数、脚本文件或可运行程序的名称(pycharm)

无法将“配置的任何一个环境变量”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。 记录解决“无法将“C:......conda.exe”项识别为 cmdlet、函数、脚本文件或可运行程序的名称”以及“表达式或语句中包含意外的标记”的系列问题(VSCode开发环境)一、Conda.exe无法正常识…

【Java高级开发高频面试题】面试者角度的口述版

文章目录 1.具备扎实的Java基础集合HashMap底层工作原理HashMap版本问题HashMap并发修改异常HashMap影响HashMap性能的因素HashMap使用优化 SynchronizedThreadLocalAQS线程池JVM内存模型类加载机制与双亲委派垃圾回收算法、垃圾回收器、空间分配担保策略引用计数器算法、可达性…

创建 Web 内容目录

创建 Web 内容目录 按照下方所述&#xff0c;创建一个名为 /home/curtis/ansible/webcontent.yml 的 playbook &#xff1a; 该 playbook 在 dev 主机组中的受管节点上运行 创建符合下列要求的目录 /webdev &#xff1a; 所有者为 webdev 组 具有常规权限&#xff1a;ownerread…

Nginx反向代理

目录 一.简介1.反向代理 二.案例1.案例12.案例2 一.简介 1.反向代理 1.1反向代理&#xff1a; 是指代理服务器来接收Internet上的客户端请求&#xff0c;然后将请求转发给内部网络上的服务器&#xff0c;并将从服务器上得到的结果返回给客户端。此时代理服务器对外就表现为一…

循环队列的实现(c语言)

前言 循环队列是队列的一种特殊的结构&#xff0c;在生产者——消费者模型中常常使用它&#xff0c; 它在逻辑上是一个环形的连续的结构。在物理可以使用数组来实现。 目录 1.循环队列的逻辑结构 2.空的循环队列和满的循环队列 3.循环队列插入和删除 4.代码实现 …

音视频实时通话解决方案

1、问题提出 想要实现音视频通话,对于大部分人可能会觉得很难,但是实际上,有些事情并没有大家想的那样困难,只要功夫深,铁杵磨成针。 机缘巧合下,在业务中,我也遇到了一个业务场景需要实现音视频通话,我们不可能自己从零开始干,我本次用到的核心是WebRTC。 2、WebRT…

治疗偏头痛等亚疼痛的远程电神经调控(REN)设备

原文链接&#xff1a; NERIVIO CE标志适应症扩展到青少年和成人偏头痛的预防和急性治疗 (prnewswire.com) 公司官网&#xff1a; Homepage - Theranica APP下载链接&#xff1a; Migraine Headache Treatment - Nerivio 使用过程问题&#xff1a; 常见问题 - 无药物偏头痛两…

Flink状态和状态管理

1.什么是状态 官方定义&#xff1a;当前计算流程需要依赖到之前计算的结果&#xff0c;那么之前计算的结果就是状态。 这句话还是挺好理解的&#xff0c;状态不只存在于Flink&#xff0c;也存在生活的方方面面&#xff0c;比如看到一个认识的人&#xff0c;如何识别认识呢&am…

Python Web框架:Django、Flask和FastAPI巅峰对决

今天&#xff0c;我们将深入探讨Python Web框架的三巨头&#xff1a;Django、Flask和FastAPI。无论你是Python小白还是老司机&#xff0c;本文都会为你解惑&#xff0c;带你领略这三者的魅力。废话不多说&#xff0c;让我们开始这场终极对比&#xff01; Django&#xff1a;百…

web基础入门和php语言基础入门 二

web基础入门和php语言基础入门 二 MySQL入门-续MySQL之数据查询操作MySQL其他知识点 php语言基础入门认识PHPPHP的工作流程安装PHP环境认识一个PHP程序PHP基础知识点进入正题 PHP与WEB交互PHP与MySQL交互总结 MySQL入门-续 MySQL之数据查询操作 WHERE 子句&#xff0c;条件限…

# 快速评估立功科技基于S32K324的TMS方案

文章目录 1.前言2.立功科技的TMS方案介绍2.1 介绍资料2.2 简要介绍 3.S32K3_TriMotor评估板测试3.1 环境搭建S32 Design Studio for S32 Platform 3.4安装RTD 2.0.0安装Freemaster 3.2 3.2 例程测试3.3 例程适配3.4 双核烧录3.5 测试 1.前言 最近和一些做汽车水泵/风机的客户交…

maven如何建立JavaWeb项目并连接数据库,验证登录

这里是建立建立web项目&#xff1a;Maven如何创建Java web项目&#xff08;纯干货版&#xff09;&#xff01;&#xff01;&#xff01;_明天更新的博客-CSDN博客 我们主要演示如何连接数据库验证登录。 1.在webapp目录下创建我们的登录页面&#xff1a;index.jsp 还需要再…

Android漏洞之战——整体加壳原理和脱壳技巧详解

一、前言 为了帮助更加方便的进行漏洞挖掘工作&#xff0c;前面我们通过了几篇文章详解的给大家介绍了动态调试技术、过反调试技术、Hook技术、过反Hook技术、抓包技术等&#xff0c;掌握了这些可以很方便的开展App漏洞挖掘工作&#xff0c;而最后我们还需要掌握一定的脱壳技巧…

opencv基础:几个常用窗口方法

开始说了一些opencv中的一些常用方法。 namedWindow方法 在OpenCV中&#xff0c;namedWindow函数用于创建一个窗口&#xff0c;并给它指定一个名字。这个函数的基本语法如下&#xff1a; import cv2cv2.namedWindow(窗口名称, 标识 )窗口名称&#xff1a;其实窗口名称&…