recyclerview中树状结构的实现,加载本地中文件夹信息

news2025/1/18 9:08:41

引文:
在项目实现中,对于树状图结构的分析一直无法实现正确的效果,结果查看别人的项目都不要适合我的应用场景,但是查看其实原理是差不多的,但是我没有看明白,所以一直在看这方面的东西。查阅并修改他人的代码实现文件夹效果,看着还是有点繁琐,先记录,后续再进行数据的修改。声明一点,我的代码是在别人的代码的基础上进行修改。

  • 效果呈现
    在这里插入图片描述

  • 系统讲解

    • 需要的控件:recyclerview(其实使用Listview也可以,就是adapter中结构不一样)
    • 实现步骤
      (1)数据初始化
      (2)点击监听,数据更新
      (3)数据处理,构建树状结构
  • 具体的代码实现如下所示:

1、在activity或者在fragment中进行数据的初始化和数据更新

private void getLocalData() {
		//获取本地路径
		List<FileNodeBean> fileList = new ArrayList<>();
		//获取本地文件目录
		File path = Environment.getExternalStorageDirectory();
		Log.d(TAG, "onClick: " + path.getName());
		//获取文件子项
		File[] mfile = path.listFiles();
		List<File> mAllLocalData = new ArrayList<>();

		//目录初始化
		for (int i = 0 ; i < mfile.length; i++) {
		//本地文件中存在隐藏的文件,不需要显示
			if (!mfile[i].isHidden()) {
				if (MineTypeUtil.isShowFile(mfile[i])){
					FileNodeBean fileNode = new FileNodeBean("local" + i, 0, mfile[i].getName());
					fileNode.setParent(null);
					fileNode.setLevel(0);
					fileNode.setId(mfile[i].getPath());
					fileNode.setPath(mfile[i].getPath());
					fileNode.setVidelFile(MineTypeUtil.isVideoFile(mfile[i].getPath()));
					fileList.add(fileNode);

					mAllLocalData.add(mfile[i]);
				}
			}
		}
		//适配adapter,初始化数据
			mFileAdapter = new FileAdapter(mFileRecyclerView, mContext);
			mFileAdapter.updateData(fileList, 0);
			mFileRecyclerView.setAdapter(mFileAdapter);
			//点击图标的监听事件
			mFileAdapter.setNodeDataListener(new FileAdapter.onNodeDataListener() {
				@Override
				public void onNodeDataListener(FileNodeBean node) {
					Log.d(TAG, "onNodeDataListener: + getName " + node.getName());
					List<FileNodeBean> childList = new ArrayList<>();

					for (int i = 0 ; i < mAllLocalData.size(); i++) {
						//通过路径判断获取点击的item
						if (mAllLocalData.get(i).getPath().equals(node.getPath())) {
							Log.d(TAG, "onNodeDataListener:node.path " + node.getPath());
							if (mAllLocalData.get(i).listFiles() != null){
							//获取是否存在子项
								Log.d(TAG, "onNodeDataListener:listfile " + mAllLocalData.get(i).listFiles());
								int m = 0;
								//遍历点击item的子项
								for (int j = 0; j < mAllLocalData.get(i).listFiles().length; j++) {

									//子项为目录或者音频文件时
									if (MineTypeUtil.isShowFile(mAllLocalData.get(i).listFiles()[j])){
										m++;
										FileNodeBean fileNodeBean = new FileNodeBean();
										fileNodeBean.setId(mAllLocalData.get(i).listFiles()[j].getPath());
										fileNodeBean.setName(mAllLocalData.get(i).listFiles()[j].getName());
										fileNodeBean.setExpand(false);
										fileNodeBean.setParent(node);
										fileNodeBean.setPath(mAllLocalData.get(i).listFiles()[j].getPath());
										fileNodeBean.setVidelFile(MineTypeUtil.isVideoFile(mAllLocalData.get(i).listFiles()[j].getPath()));
										fileNodeBean.setLevel(node.getLevel() + 1);
										childList.add(fileNodeBean);
										//更新列表
										if (node.isExpand()){
											mAllLocalData.remove(mAllLocalData.get(i).listFiles()[j]);
										}else {
											mAllLocalData.add(i + m, mAllLocalData.get(i).listFiles()[j]);
										}
									}
								}
							//更新fieList的数据
							for(int k = 0; k < fileList.size(); k++){
								if (fileList.get(k).getPath().equals(node.getPath())) {
									fileList.get(k).setChildren(childList);
									break;
								}
							}
							//对于数据展开与闭合的处理

							if (node.isExpand()) {
								childList.clear();
								node.setChildren(childList);
								node.setExpand(!node.isExpand());
								mFileAdapter.updateData(fileList, node.getLevel() - 1);
							} else {
								node.setChildren(childList);
								node.setExpand(!node.isExpand());
								mFileAdapter.updateData(fileList, node.getLevel() + 1);
							}
						}else {
								Log.d(TAG, "onNodeDataListener: " + mAllLocalData.get(i).listFiles());
								Toast.makeText(mContext, "子项为空", Toast.LENGTH_SHORT).show();
							}
							break;
						}

					}}
			});

	}
  • recyclerview中adapter处理,继承于TreeListViewAdapter ,将一些通用的数据进行处理
public class FileAdapter extends TreeListViewAdapter {

	private static final String TAG = " TreeListViewAdapter ";
	private onNodeDataListener onNodeDataListener;
	private FileAdapter.onItemDataListener onItemDataListener ;
	
	public FileAdapter(RecyclerView mTree, Context context) {
		super(mTree, context);
	}

	private List<FileNodeBean> mDatas= new ArrayList<>();
	//数据更新,每一次点击之后,数据展开关闭产生的数据变化
	@Override
	public void updateData(List<FileNodeBean> datas, int defaultExpandLevel) {

		super.updateData(datas, defaultExpandLevel);
	}

	@Override
	protected void getBindViewHolder(FileNodeBean node, RecyclerView.ViewHolder holder, int position) {
		ViewHolder mHolder = (ViewHolder)holder;

		if (node.isVidelFile()){
			mHolder.typeImage.setImageResource(R.mipmap.icon_file_manager_video);
			mHolder.mExpandImage.setVisibility(View.GONE);
		}else {
			mHolder.typeImage.setImageResource(R.mipmap.icon_file_manager_folder);
			mHolder.mExpandImage.setVisibility(View.VISIBLE);
		}

		mHolder.mExpandImage.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {

				expandOrCollapse(position);
			//	setChecked(node, node.isExpand());

				onNodeDataListener.onNodeDataListener(node);
				notifyDataSetChanged();
			}
		});
		holder.itemView.setSelected(node.isSelelct());

		if (node.isExpand()){
			mHolder.mExpandImage.setBackgroundResource(R.mipmap.icon_file_folder_expand);
		}else {
			mHolder.mExpandImage.setBackgroundResource(R.mipmap.icon_file_folder_unexpand);
		}
		mHolder.tvName.setText(node.getName());

		//增加一个item的点击事件,修改item的状态
		holder.itemView.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				for (int i = 0 ; i < mNodes.size(); i++){
					if (node.getId().equals(mNodes.get(i).getId())){
					
					}else {

						mNodes.get(i).setSelelct(false);
						Log.d("lucky", "onClick: " + mNodes.get(i).isSelelct());
					}
				}
				Log.d("lucky", "onClick: " + node.isSelelct());
				onItemDataListener.onItemDataListener(node);

				notifyDataSetChanged();
			}
		});
	}

	@NonNull
	@Override
	public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
		View view = mInflater.inflate(R.layout.file_move_folder_path_item, parent, false);
		RecyclerView.ViewHolder holder = new  ViewHolder(view);
		view.setTag(holder);
		return holder;
	}



	class ViewHolder extends RecyclerView.ViewHolder{
		TextView tvName;
		ImageView mExpandImage;

		ImageView typeImage;

		public ViewHolder(@NonNull View itemView) {
			super(itemView);
			tvName = itemView.findViewById(R.id.folder_name);
			mExpandImage = itemView.findViewById(R.id.expand_change_image);
			typeImage = itemView.findViewById(R.id.folder_image);
		}
	}

	public void setNodeDataListener(onNodeDataListener setNodeDataListener) {
		this.onNodeDataListener = setNodeDataListener;
	}

	public void setSelelctDataListener(onItemDataListener itemDataListener) {
		this.onItemDataListener = itemDataListener;
	}


	public interface onNodeDataListener {
		void onNodeDataListener(FileNodeBean node);
	}

	public interface onItemDataListener {
		void onItemDataListener(FileNodeBean node);
	}
}

2、TreeListViewAdapter 表示通用结构中的实现:

public abstract class TreeListViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {


	private static final String TAG =  " TreeListViewAdapter ";
	protected Context mContext;
	/**
	 * 存储所有可见的Node
	 */
	protected List<FileNodeBean> mNodes = new ArrayList<>();
	protected LayoutInflater mInflater;

	/**
	 * 存储所有的Node
	 */
	protected List<FileNodeBean> mAllNodes = new ArrayList<>();

	public TreeListViewAdapter(RecyclerView mTree, Context context){
		mContext = context;
		mInflater = LayoutInflater.from(context);

	}

	//上一个状态的所有node
	private List<FileNodeBean> beforeDatas = new ArrayList<>();
	public void updateData(List<FileNodeBean> datas, int defaultExpandLevel) {


		/**
		 * 对所有的Node进行排序
		 */
		mAllNodes = TreeHelper.getSortedNodes(datas, defaultExpandLevel);
		/**
		 * 过滤出可见的Node
		 */
		mNodes = TreeHelper.filterVisibleNode(mAllNodes);

		Log.d("TAG", "updateData: " + mNodes.size() + "  " + mAllNodes.size());


	}

	/**
	 * 相应ListView的点击事件 展开或关闭某节点
	 */
	public void expandOrCollapse(int position) {
		FileNodeBean n = mNodes.get(position);

		if (n != null) {// 排除传入参数错误异常
			//item不为叶子节点
			if (!n.isLeaf()) {
				//n.setExpand(!n.isExpand());
				mNodes = TreeHelper.filterVisibleNode(mAllNodes);
				notifyDataSetChanged();// 刷新视图
			}
		}

	}



	@Override
	public int getItemCount() {
		return mNodes.size();
	}



	@Override
	public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {

		FileNodeBean nodeBean = mNodes.get(position);
		holder.itemView.setPadding((nodeBean.getLevel()+1) * 40, 3, 3, 3);
		getBindViewHolder(nodeBean, holder, position);


	}

	protected abstract void getBindViewHolder(FileNodeBean node, RecyclerView.ViewHolder holder, int position);

	@Override
	public long getItemId(int position) {
		return position;
	}


}

3、MineTypeUtil 用于判断文件的类型

public class MineTypeUtil {
	private static final char SEPARATOR = '/';
	private static final char EXTENSION_SEPARATOR = '.';
	public static final String GENERIC_MIME_TYPE = "application/octet-stream";
	private static final Map<String, String> sExtensionToMimeTypeMap =
			MapBuilder.<String, String>newHashMap()
					// Compatibility (starting from L), in the order they appear in Android source.
					.put("mp3", "application/mp3")
					.put("wav", "application/wav")
					.put("gsm", "application/gsm")
					.put("text", "application/text")
					.buildUnmodifiable();
	private static final String TAG = "MineTypeUtil";

	public static String getMimeType(@NonNull String path) {
		String extension = getExtension(path);
		extension = extension.toLowerCase(Locale.US);
		String mimeType = sExtensionToMimeTypeMap.get(extension);
		if (!TextUtils.isEmpty(mimeType)) {
			return mimeType;
		}
		mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
		if (!TextUtils.isEmpty(mimeType)) {
			return mimeType;
		}
		return GENERIC_MIME_TYPE;
	}

	public static String getExtension(@NonNull String path) {
		int index = indexOfExtensionSeparator(path);
		if (path == null){
			index = -1;
		}
		return index != -1 ? path.substring(index + 1) : "";
	}

	public static int indexOfExtensionSeparator(@NonNull String path) {
		int lastSeparatorIndex = indexOfLastSeparator(path);
		if (path == null){
			return -1;
		}
		int lastExtensionSeparatorIndex = path.lastIndexOf(EXTENSION_SEPARATOR);
		return lastSeparatorIndex > lastExtensionSeparatorIndex ? -1 : lastExtensionSeparatorIndex;
	}

	public static int indexOfLastSeparator(@NonNull String path) {
		if (path == null){
			return -1;
		}
		return path.lastIndexOf(SEPARATOR);
	}

	public static boolean isShowFile(File file) {
		String path = file.getPath();
		boolean isVideo = false;
		isVideo = isVideoFile(path);

		if (!file.isHidden() && (isVideo || file.isDirectory())) {

			return true;
		}
		return false;
	}
	public static boolean isVideoFile(String path){
		if (MineTypeUtil.getMimeType(path).equals("application/mp3") || MineTypeUtil.getMimeType(path).equals("application/wav")
				|| MineTypeUtil.getMimeType(path).equals("application/gsm")) {
			return true;
		}
		return false;
	}
}

用于辅助处理MineTypeUtil 的文件信息

public class MapBuilder<K, V, M extends Map<K, V>> {

	@NonNull
	private M mMap;

	private MapBuilder(@NonNull M map) {
		mMap = map;
	}

	@NonNull
	public static <K, V> MapBuilder<K, V, HashMap<K, V>> newHashMap() {
		return new MapBuilder<>(new HashMap<>());
	}

	@NonNull
	public static <K, V, M extends Map<K, V>> MapBuilder<K, V, M> buildUpon(@NonNull M map) {
		return new MapBuilder<>(map);
	}

	@NonNull
	public M build() {
		M map = mMap;
		mMap = null;
		return map;
	}

	@NonNull
	public Map<K, V> buildUnmodifiable() {
		Map<K, V> map = Collections.unmodifiableMap(mMap);
		mMap = null;
		return map;
	}


	@NonNull
	public MapBuilder<K, V, M> put(@Nullable K key, @Nullable V value) {
		mMap.put(key, value);
		return this;
	}

	@NonNull
	public MapBuilder<K, V, M> remove(@Nullable K key) {
		mMap.remove(key);
		return this;
	}

	@NonNull
	public MapBuilder<K, V, M> putAll(@NonNull Map<? extends K, ? extends V> m) {
		mMap.putAll(m);
		return this;
	}

	@NonNull
	public MapBuilder<K, V, M> clear() {
		mMap.clear();
		return this;
	}

	@NonNull
	@RequiresApi(Build.VERSION_CODES.N)
	public MapBuilder<K, V, M> replaceAll(
			@NonNull BiFunction<? super K, ? super V, ? extends V> function) {
		mMap.replaceAll(function);
		return this;
	}

	@NonNull
	@RequiresApi(Build.VERSION_CODES.N)
	public MapBuilder<K, V, M> putIfAbsent(@Nullable K key, @Nullable V value) {
		mMap.putIfAbsent(key, value);
		return this;
	}

	@NonNull
	@RequiresApi(Build.VERSION_CODES.N)
	public MapBuilder<K, V, M> remove(@Nullable K key, @Nullable V value) {
		mMap.remove(key, value);
		return this;
	}

	@NonNull
	@RequiresApi(Build.VERSION_CODES.N)
	public MapBuilder<K, V, M> replace(@Nullable K key, @Nullable V oldValue,
									   @Nullable V newValue) {
		mMap.replace(key, oldValue, newValue);
		return this;
	}

	@NonNull
	@RequiresApi(Build.VERSION_CODES.N)
	public MapBuilder<K, V, M> replace(@Nullable K key, @Nullable V value) {
		mMap.replace(key, value);
		return this;
	}

	@NonNull
	@RequiresApi(Build.VERSION_CODES.N)
	public MapBuilder<K, V, M> merge(
			@Nullable K key, @NonNull V value,
			@NonNull BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
		mMap.merge(key, value, remappingFunction);
		return this;
	}
}

4、构建树状图的关键处理

public class TreeHelper {
	/**
	 * 传入node  返回排序后的Node
	 */
	public static List<FileNodeBean> getSortedNodes(List<FileNodeBean> datas,
											int defaultExpandLevel) {
		List<FileNodeBean> result = new ArrayList<FileNodeBean>();
		// 设置Node间父子关系
		List<FileNodeBean> nodes = convetData2Node(datas);
		// 拿到根节点
		List<FileNodeBean> rootNodes = getRootNodes(nodes);
		// 排序以及设置Node间关系
		for (FileNodeBean node : rootNodes) {
			addNode(result, node, defaultExpandLevel);
		}
		return result;
	}

	/**
	 * 过滤出所有可见的Node
	 */
	public static List<FileNodeBean> filterVisibleNode(List<FileNodeBean> nodes) {
		List<FileNodeBean> result = new ArrayList<FileNodeBean>();

		for (FileNodeBean node : nodes) {
			// 如果为根节点,或者上层目录为展开状态
			if (node.isRoot() || node.isParentExpand()) {
				result.add(node);
			}
		}
		return result;
	}

	/**
	 * 设置Node间,父子关系;让每两个节点都比较一次,即可设置其中的关系
	 */
	private static List<FileNodeBean> convetData2Node(List<FileNodeBean> nodes) {

		for (int i = 0; i < nodes.size(); i++) {
			FileNodeBean n = nodes.get(i);
			for (int j = i + 1; j < nodes.size(); j++) {
				FileNodeBean m = nodes.get(j);
				//id的类型为string类型
				if (m.getpId() instanceof String) {
					if (m.getpId().equals(n.getId())) {
						n.getChildren().add(m);
						m.setParent(n);
					} else if (m.getId().equals(n.getpId())) {
						m.getChildren().add(n);
						n.setParent(m);
					}
				} else {
					//id类型为int型
					if (m.getpId() == n.getId()) {
						n.getChildren().add(m);
						m.setParent(n);
					} else if (m.getId() == n.getpId()) {
						m.getChildren().add(n);
						n.setParent(m);
					}
				}
			}
		}
		return nodes;
	}

	// 拿到根节点
	private static List<FileNodeBean> getRootNodes(List<FileNodeBean> nodes) {
		List<FileNodeBean> root = new ArrayList<FileNodeBean>();
		for (FileNodeBean node : nodes) {
			if (node.getLevel() == 0 || node.isRoot()){
				root.add(node);
			}
//			if (node.isRoot())
//				root.add(node);
		}
		return root;
	}

	/**
	 * 递归,把一个节点上的所有的内容都挂上去
	 * @param nodes node为挂载后的数据
	 * @param node 需要增加的子项
	 * @param currentLevel
	 * @param <T>
	 * @param <B>
	 */
	private static <T, B> void addNode(List<FileNodeBean> nodes, FileNodeBean<T, B> node,
									    int currentLevel) {
		//将所有node加入到字符中


		node.setLevel(currentLevel);
		nodes.add(node);

		if (node.isLeaf()){
			return;
		}
		for (int i = 0 ; i < node.getChildren().size(); i++){
			addNode(nodes, node.getChildren().get(i), currentLevel + 1);
		}
		Log.d("Treehelper", "addNode: " + nodes.size());
	}
}

辅助处理事件

public class FileNodeBean<T, B> {


		/**
		 * ****************** 分级树状等字段
		 */
		//传入的实体对象
		public B bean;
		//父级id子级pid
		private T id;
		//根节点pId为0
		private T pId;
		//节点名称
		private String name;
		//当前的级别
		private int level;
		//是否展开
		private boolean isExpand = false;
		//子节点数据 ,套用当前node
		private List<FileNodeBean> children = new ArrayList<>();
		//父节点
		private FileNodeBean parent;
		//是否被checked选中
		private boolean isChecked;

		private boolean isSelelct;

		private String path;

		private boolean isVidelFile;

		public FileNodeBean() {
		}

		public FileNodeBean(T id, T pId, String name) {
			super();
			this.id = id;
			this.pId = pId;
			this.name = name;
		}

		public FileNodeBean(T id, T pId, String name, B bean) {
			super();
			this.id = id;
			this.pId = pId;
			this.name = name;
			this.bean = bean;
		}

	public boolean isVidelFile() {
		return isVidelFile;
	}

	public void setVidelFile(boolean videlFile) {
		isVidelFile = videlFile;
	}

	public String getPath() {
		return path;
	}

	public void setPath(String path) {
		this.path = path;
	}

	public boolean isSelelct() {
		return isSelelct;
	}

	public void setSelelct(boolean selelct) {
		isSelelct = selelct;
	}

	public boolean isChecked() {
			return isChecked;
		}

		public void setChecked(boolean isChecked) {
			this.isChecked = isChecked;
		}

		public T getId() {
			return id;
		}

		public void setId(T id) {
			this.id = id;
		}

		public T getpId() {
			return pId;
		}

		public void setpId(T pId) {
			this.pId = pId;
		}

		public String getName() {
			return name;
		}

		public void setName(String name) {
			this.name = name;
		}

		public void setLevel(int level) {
			this.level = level;
		}

		public boolean isExpand() {
			return isExpand;
		}

		public List<FileNodeBean> getChildren() {
			return children;
		}

		public void setChildren(List<FileNodeBean> children) {
			this.children = children;
		}

		public FileNodeBean getParent() {
			return parent;
		}

		public void setParent(FileNodeBean parent) {
			this.parent = parent;
			if (parent != null){
				this.pId = (T) parent.getId();
			}

		}

		/**
		 * 是否为跟节点
		 */
		public boolean isRoot() {
			return parent == null;
		}

		/**
		 * 判断父节点是否展开
		 */
		public boolean isParentExpand() {
			if (parent == null)
				return false;
			return parent.isExpand();
		}

		/**
		 * 是否是叶子界点
		 */
		public boolean isLeaf() {
			return children.size() == 0;
		}

		/**
		 * 获取当前所在层级,
		 * 设置层级间隔
		 */
		public int getLevel() {
			return parent == null ? 0 : parent.getLevel() + 1;
		}

		/**
		 * 设置展开
		 */
		public void setExpand(boolean isExpand) {
			this.isExpand = isExpand;
			if (!isExpand) {
				for (FileNodeBean node : children) {
					node.setExpand(isExpand);
				}
			}
		}

}

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

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

相关文章

ADSP21489之CCES开发笔记(九)

21489评估板调试SigmaStudio&#xff0c;录音&#xff0c;算法效果对比等等&#xff0c;依此写上该文章&#xff0c;以便有兴趣的朋友参考之用。 一、硬件链路图 二、导入21489Demo程序 2.1、Demo路径&#xff1a;2.2、导入ADI的21489的Demo程序 修改相关代码 oCommConfig.n…

小白学Pytorch系列--Torch.optim API Base class(1)

小白学Pytorch系列–Torch.optim API Base class(1) torch.optim是一个实现各种优化算法的包。大多数常用的方法都已得到支持&#xff0c;而且接口足够通用&#xff0c;因此将来还可以轻松集成更复杂的方法。 如何使用优化器 使用手torch.optim您必须构造一个优化器对象&…

下载和阅读Android源码

目录一、如何下载AOSP1.全量下载2.单个下载目录结构二、如何阅读AOSP1.要阅读哪些源码2.阅读源码的顺序和方式2.1 阅读顺序2.2 阅读方式3.用什么工具来阅读3.1 下载安装Source Insight3.2 导入AOSP源码3.3查看源码三、其他一、如何下载AOSP 源码下载是我们分析源码的开始&…

ctfshow愚人杯web复现

easy_signin 题目url base64解码是face.png&#xff0c;尝试flag.txt和flag.php&#xff0c;base64加密后传入都不对&#xff0c;用index.php加密后传入&#xff0c;看源码 将后面的base64解密得到flag 被遗忘的反序列化 源码 <?php# 当前目录中有一个txt文件哦 error_r…

Unity- 游戏结束以及重启游戏

文章目录游戏结束以及重启游戏建个游戏结束页面编写委托类 游戏主角 以及 ui管理类的脚本重启游戏游戏结束以及重启游戏 思路&#xff1a;利用Canvas创建好覆盖全屏的结束页面&#xff0c;默认关闭。游戏结束时&#xff0c;玩家控制的对象发起委托&#xff0c;ui管理收下委托&…

electron+vue3全家桶+vite项目搭建【六】集成vue-i18n 国际化

文章目录注意引入1.引入依赖2.集成vue i18n3.测试代码4.封装多语言切换组件5.测试多语言切换6.优化代码注意 已发现 9.2.2版本的vue-i18n 如果使用cnpm安装&#xff0c;打包会报错&#xff0c;使用npm或者pnpm安装依赖没有问题 引入 如果需要多语言支持&#xff0c;那么最好…

【100个 Unity实用技能】 | Lua中获取当前时间戳,时间戳和时间格式相互转换、时间戳转换为多久之前

Unity 小科普 老规矩&#xff0c;先介绍一下 Unity 的科普小知识&#xff1a; Unity是 实时3D互动内容创作和运营平台 。包括游戏开发、美术、建筑、汽车设计、影视在内的所有创作者&#xff0c;借助 Unity 将创意变成现实。Unity 平台提供一整套完善的软件解决方案&#xff…

【AI大比拼】文心一言 VS ChatGPT-4

摘要&#xff1a;本文将对比分析两款知名的 AI 对话引擎&#xff1a;文心一言和 OpenAI 的 ChatGPT&#xff0c;通过实际案例让大家对这两款对话引擎有更深入的了解&#xff0c;以便大家选择合适的 AI 对话引擎。 亲爱的 CSDN 朋友们&#xff0c;大家好&#xff01;近年来&…

Python自动录入ERP系统数据

大家好&#xff0c;我是毕加锁。 今天给大家带来的是用Python解决Excel问题的最佳姿势 文末送书&#xff01; 文末送书&#xff01; 文末送书&#xff01; 项目总体情况 软件&#xff1a;Pycharm 环境: Python 3.7.9(考虑到客户可能会有不同操作系统&#xff0c;为了兼容性…

【小程序】django学习笔记3

今天我们来做数据库和django的关联。 根据之前的代码应该看得出来我想做一个获取访客的ip地址并计算访问次数的app&#xff0c;所以必然会用到数据库。 这里选择用的是mysql(因为免费) 不一样的是这里我们打算用django提供的orm框架对数据库进行操作。 一. 环境准备 首先安…

SLAM面试笔记(3) - 视觉SLAM

目录 1 紧耦合、松耦合的区别 &#xff08;1&#xff09;紧耦合和松耦合的区别 &#xff08;2&#xff09;紧耦合和松耦合的分类 &#xff08;3&#xff09;为什么要使用紧耦合 2 SIFT和SUFT的区别 3 视差与深度的关系 4 闭环检测常用方法 5 描述PnP算法 6 梯度下降法…

SQL基础

目录 1.库操作 2.表操作 3.表操作--修改 4.表操作 --删表 5.添加数据 管理数据 查询表中数据&#xff08;重点&#xff09; 判空条件 1.模糊条件查询 2.聚合查询&#xff08;函数&#xff09; 3.排序查询 4.分页查询 5.分组查询&#xff08;配合聚合函数用于统计&a…

C++模拟实现读写锁

文章目录一、读者写者问题二、读写锁1.读写锁的概念2.读写锁的设计(1)成员变量(2)构造函数和析构函数(3)readLock函数(4)readUnlock函数(5)writeLock函数(6)writeUnlock函数3.RWLock类代码三、测试读写锁一、读者写者问题 在编写多线程的时候&#xff0c;有一种情况是非常常见…

为什么黑客不黑/攻击赌博网站?如何入门黑客?

攻击了&#xff0c;只是你不知道而已&#xff01; 同样&#xff0c;对方也不会通知你&#xff0c;告诉你他黑了赌博网站。 攻击赌博网站的不一定是正义的黑客&#xff0c;也可能是因赌博输钱而误入歧途的法外狂徒。之前看过一个警方破获的真实案件&#xff1a;28岁小伙因赌博…

Linux 操作系统原理作业 - 行人与机动车问题

大三上学期操作系统原理这门课中&#xff0c;老师给了一道作业《行人与机动车问题》&#xff1b; 即Linux多线程下处理行人与机动车谁优先的问题&#xff0c;需要用到多线程和互斥量&#xff1b; 行人 - 机动 车问题 假设有一个路口&#xff0c;有很多行人和机动车需要通过&a…

1673_MIT 6.828 Homework xv6 lazy page allocation要求翻译

全部学习汇总&#xff1a; GreyZhang/g_unix: some basic learning about unix operating system. (github.com) 在计划表中看到了这样一份作业&#xff0c;做一个简单的翻译整理。原来的页面&#xff1a;Homework: xv6 lazy page allocation (mit.edu) 家庭作业&#xff1a;x…

代码版本M、RC、GA、Release等标识的区别

引言 最近听说spring framework有了重大版本调整&#xff0c;出了6.0的GA版本了 那GA是啥意思呢&#xff1f; 看了下spring 官网和代码仓库&#xff0c;除了GA&#xff0c;还有M、RC、Release等 Spring FrameworkLevel up your Java code and explore what Spring can do f…

[Java Web]element | 一个由饿了么公司开发的前端框架,让你快速构建现代化、美观的 Web 应用程序。

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐所属专栏&#xff1a;Java Web ⭐如果觉得文章写的不错&#xff0c;欢迎点个关注一键三连&#x1f609;有写的不好的地方也欢迎指正&a…

【mybatis】mybatis的工作原理

目录一、工作流程二、说明2.1 构建SqlSessionFactory2.2 SqlSession的获取2.3 SqlSession执行语句三、源码结构3.1 接口层3.2 核心处理3.3 核心处理层四、代码示例4.1 通过inputStream构建SqlSessionFactory4.2 通过configuration构建SqlSessionFactory4.3 mybatis-config.xml示…

groovy环境搭建

什么是DSL? 领域特定语言DSL&#xff08;全称&#xff1a;domain specific language&#xff09; 常见的DSL语言有&#xff1a;UML、HTML、SQL、XML、Groovy 作用&#xff1a;解决某一特定领域的问题 什么是groovy? groovy是一种基于JVM的敏捷开发语言。 结合了Python、Ruby和…