autojs模仿QQ长按弹窗菜单

简介: 我们自顶向下来写代码, 首先我们写的是setTestRecyclerViewAdapter.js, 他这个里面要做几件事:加载两个类, Adapter和Holder, Holder先加载, 因为他会在Adapter中使用

牙叔教程 简单易懂


分析弹框菜单

  1. 圆角
  2. 列表, 类似grid
  3. 箭头位于文字中间上(下)方


需求分析

如果要写一个这样的教程, 我们需要做什么

  1. 写一个列表, 用来触发长按选项
  2. 写一个弹窗菜单

代码分析

列表怎么写,

先来一个最简单的布局代码

"nodejs ui";

require("rhino").install();

const ui = require("ui");

class MainActivity extends ui.Activity {

 constructor() {

   super();

   this.items = [];

   for (var i = 10; i < 100; i++) {

     this.items.push(randomStr(i + 1));

   }

 }

 get layoutXmlFile() {

   return "layout.xml";

 }

 onContentViewSet() {}

}

ui.setMainActivity(MainActivity);


layout.xml文件内容, 就一个recyclerview

<column>

<androidx.recyclerview.widget.RecyclerView id="recyclerView" padding='12' layout_width="match_parent" layout_height="match_parent">

</androidx.recyclerview.widget.RecyclerView>

</column>

RecyclerView基础代码

在onContentViewSet这个方法中, 我们去写列表, 列表设置adapter即可;

我们要创建自己的Adapter类, 继承自RecyclerView.Adapter

class MyAdapter extends androidx.recyclerview.widget.RecyclerView.Adapter {}

这里用MyAdapter命名合适吗? 不合适, 如果你以后也用了MyAdapter, 那么可能造成类名冲突, 所以, 我们改个名字, 我们是在测试, 因此就叫 TestReayclerViewAdapter,

还有一点是, 因为我们要写两个类, 还有一个文件实例化两个类, 因此我们把这个三个文件放到同一个文件夹

我们自顶向下来写代码, 首先我们写的是setTestRecyclerViewAdapter.js, 他这个里面要做几件事:

  1. 加载两个类, Adapter和Holder, Holder先加载, 因为他会在Adapter中使用
  2. 实例化两个类

类呢, 我们先不写, 我们先写伪代码

setTestRecyclerViewAdapter.js

module.exports=function(recyclerView,items){

 await $java.defineClass(TestRecyclerViewViewHolder)

 await $java.defineClass(TestRecyclerViewAdapter)

 var adapter=new TestRecyclerViewAdapter(items)

 recyclerView.setAdapter(adapter)

}

这样写怎么样, 有问题吗?

有问题, 如果每次都defineClass, 那么就会报错, 重复定义类, 因此, 我们设置个flag, 类只定义一次

let definedClass = false;

module.exports = async function (recyclerView, items) {

 if (!definedClass) {

   await $java.defineClass(TestRecyclerViewViewHolder);

   await $java.defineClass(TestRecyclerViewAdapter);

   definedClass = true;

 }

 var adapter = new TestRecyclerViewAdapter(items);

 recyclerView.setAdapter(adapter);

};


这样就没问题了, 接下来我们写TestRecyclerViewAdapter, 为什么先写他呢, 前面说过了, 我们是自顶向下写,

TestRecyclerViewAdapter里面要写什么呢? 重写三个方法

  • onCreateViewHolder
  • onBindViewHolder
  • getItemCount
  • getItemViewType

TestRecyclerViewAdapter.js

const ui = require("ui");

class TestRecyclerViewAdapter extends androidx.recyclerview.widget.RecyclerView.Adapter {

 constructor(data) {

   super();

   this.data = data;

 }

 onCreateViewHolder(parent) {

   return new TestRecyclerViewViewHolder(ui.inflateXml(parent.getContext(), holderXml, parent));

 }

 onBindViewHolder(holder, position) {

   holder.bind(this.data[position], position);

 }

 getItemCount() {

   return this.data.length;

 }

 getItemViewType() {

   return 0;

 }

}

module.exports = TestRecyclerViewAdapter;

这个代码里面, 唯一需要变动的地方是holderXml

接下来该写TestRecyclerViewViewHolder

class TestRecyclerViewViewHolder extends androidx.recyclerview.widget.RecyclerView.ViewHolder {

 constructor(itemView) {

   super(itemView);

 }


 bind(item) {

   this.itemView.attr("text", item);

   this.item = item;

 }

}


module.exports = TestRecyclerViewViewHolder;


到这里为止, 一个recyclerview的骨架就成型了, 先看看效果

最简单的列表就是如此, 我们给他润色一下, 字体放大, 再加个圆角背景


列表有了, 接下来我们要考虑弹框的事情了, 那么第一个考虑的点就是, 长按事件

长按事件

长按事件在哪个文件写呢?

我们既可以在Adapter中写, 也可以在Holder中写,

如果在Holder中写, 那么我们就要把长按的方法, 从Adapter传给Holder, 我们需要多写几个字幕母, 因此我选择在Adapter中写长按事件

TestRecyclerViewAdapter.js 中 修改 onCreateViewHolder 方法即可

 onCreateViewHolder(parent) {

   let testRecyclerViewViewHolder = new TestRecyclerViewViewHolder(ui.inflateXml(parent.getContext(), holderXml, parent));

   testRecyclerViewViewHolder.itemView.setOnLongClickListener(() => {

     console.log("你长按了我: " + testRecyclerViewViewHolder.item);

     return true;

   });

   return testRecyclerViewViewHolder;

 }

长按事件可能是多种多样的, 因此, 我们在TestRecyclerViewAdapter.js中, 增加一个方法setLongClick

 setLongClick(longClick) {

   this.longClick = longClick;

 }

相应的修改onCreateViewHolder代码

 onCreateViewHolder(parent) {

   let testRecyclerViewViewHolder = new TestRecyclerViewViewHolder(ui.inflateXml(parent.getContext(), holderXml, parent));

   testRecyclerViewViewHolder.itemView.setOnLongClickListener(() => {

     this.longClick();

     return true;

   });

   return testRecyclerViewViewHolder;

 }

setTestRecyclerViewAdapter.js中的代码要添加一行

adapter.setLongClick(() => console.log("this is long click"));

代码修改了一些以后, 就应该测试一下, 测试正常以后, 再进行下一步操作, 小幅迭代


点击后出现弹框, 我们先不管菜单, 先弹个框出来

我们创建一个文件: showMenuWindow.js

const ui = require("ui");

const PopupWindow = android.widget.PopupWindow;

const ViewGroup = android.view.ViewGroup;

function showMenuWindow(view) {

 let popMenuWindow = ui.inflateXml(

   view.getContext(),

   `

   <column>

   <button id="btn1" text="btn1" />

   </column>

   `,

   null

 );

 let mPopWindow = new PopupWindow(popMenuWindow, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, true);

 mPopWindow.setOutsideTouchable(true);

 mPopWindow.showAsDropDown(view);

}

module.exports = showMenuWindow;


然后在setTestRecyclerViewAdapter.js文件中调用他

adapter.setLongClick(showMenuWindow);

因此showMenuWindow有一个参数view, 就是你长按的那个view, 所以我们还要去Adapter中修改setLongClick

   testRecyclerViewViewHolder.itemView.setOnLongClickListener(() => {

     this.longClick(testRecyclerViewViewHolder.itemView);

     return true;

   });

经过测试代码正常运行,

接下来呢, 是把这个弹框改成菜单的样式,

今天先写到这里, 下一个教程继续

环境


设备: 小米11pro
Android版本: 12
Autojs版本: 9.3.11



名人名言


思路是最重要的, 其他的百度, bing, stackoverflow, github, 安卓文档, autojs文档, 最后才是群里问问 --- 牙叔教程


声明


部分内容来自网络 本教程仅用于学习, 禁止用于其他用途


相关文章
|
6月前
|
搜索推荐
win10超好看的鼠标主题,你也来试试吧
win10超好看的鼠标主题,你也来试试吧
622 0
|
Android开发
autojs最近任务多界面
牙叔教程 简单易懂
544 0
|
Android开发
autojs按钮不可点击
牙叔教程 简单易懂
913 0
|
XML 前端开发 Android开发
autojs模仿QQ长按弹窗菜单(二)
这个菜单数据应该有哪些属性呢? ​菜单显示的文字 菜单点后的回调函数 因此, 数据大概是这样的
147 0
|
Android开发 容器
仿QQ对话列表滑动删除与置顶的原理及实现(一)
仿QQ对话列表滑动删除与置顶的原理及实现(一)
99 0
仿QQ对话列表滑动删除与置顶的原理及实现(一)
仿QQ对话列表滑动删除与置顶的原理及实现(二)
仿QQ对话列表滑动删除与置顶的原理及实现(二)
86 0
仿QQ对话列表滑动删除与置顶的原理及实现(二)