WeexAndroid扩展组件Spinner(对应前端select标签)
作为一名Android开发者,在使用weex编写项目的过程中,业务需要实现一个下拉框的组件,于是动手写了个。
- Android扩展之Component 扩展
- Android扩展组件的步骤
- Js如何调用Android扩展组件
- Android扩展组件如何传参到Js
Android的Component 扩展要点
- 要点复制官方的,给第一次看Component 扩展的同行。
- Component 扩展类必须继承 WXComponent.
- Component 对应的设置属性的方法必须添加注解@WXComponentProp(name=value)
- Component 扩展的方法可以使用 int, double, float, String, Map, List 类型的参数
- 完成 Component 后一定要在初始化时注册 WXSDKEngine.registerComponent(“js调用时的名字”,自定义的组件.class);
咱们先定它个小目标,比如说写一个自定义组件
在Android Studio的项目中新建一个类继承自WXComponent,实现其中四个参数的构造函数。
public class WXSpinnerTest extends WXComponent<Spinner> {
public WXSpinnerTest(WXSDKInstance instance, WXDomObject dom, WXVContainer parent, boolean isLazy) {
super(instance, dom, parent, isLazy);
}
}
private定义一个Spinner控件,实现初始化组件主视图方法。
private Spinner spinner;
@Override
protected Spinner initComponentHostView(@NonNull Context context) {
spinner = new Spinner(context);
return spinner;
}
实现Js设置属性的方法必须添加注解,在公司实际项目中需要通过type查询出数据,而这里作为演示故没有做处理。
@WXComponentProp(name = "type")
public void initSpinner(String type){
//这里的type实际项目当中查询数据库时必要的参数,所以预留出来
list = new ArrayList<>();//list要在外部声明 private List<String> list
for (int i=0;i<10;i++){
list.add("霍比特人"+i);
}
ArrayAdapter<String> adapter = new ArrayAdapter<>(getContext(), R.layout.row_spn, list);
adapter.setDropDownViewResource(R.layout.row_spn_dropdown);
spinner.setAdapter(adapter);
}
public List<String> getList() {
List<String> list = new ArrayList<>();
for (int i=0;i<10;i++){
list.add("霍比特人"+i);
}
return list;
}
//adapter所用到的:row_spn.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/row_spn_tv"
android:layout_width="wrap_content"
android:layout_height="32dp"
android:gravity="center_vertical"
android:background="?selectableItemBackground"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:textDirection="locale"
android:textSize="16sp"/>
//adapter所用到的:row_spn_dropdown.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/row_spn_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:drawableTop="@mipmap/recycler_line"
android:drawablePadding="10dp"
android:textSize="16sp"
android:drawableBottom="@mipmap/recycler_line"
android:textDirection="locale"/>
到这里算基本完成Spinner组件的自定义(后面会写数据如何回显及Android事件传递到Js),接着需要在Application中注册扩展的组件关于Application步骤不懂的看别人的吧。
InitConfig config = new InitConfig.Builder()
.setImgAdapter(new ImageAdapter())
.setHttpAdapter(new OkgoAdapter())
.setJSExceptionAdapter(new JSExceptionAdapter())
// .setUtAdapter(new UserTrackAdapter())
.build();
WXSDKEngine.initialize(this, config);
//注册模块和组件
try {
WXSDKEngine.registerComponent("wxspinnertest", WXSpinnerTest.class);
} catch (WXException e) {
e.printStackTrace();
}
Js调用Android扩展的组件
关于weex项目的初始化
(偷懒)随便打开一个能最快被android项目打开的文件,直接输入我们在Application里定义的wxspinnertest。
<template>
<div class="app">
<div class="div-top-link">
</div>
<div class="style_div">
<text class="label_text">魔戒</text>
<wxspinnertest class="value_text mobile" :type="type"></wxspinnertest>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'app',
data () {
return {
type:1
}
}
}
</script>
<style>
.div-top-link {
width: 750px;
height: 128px;
flex-direction: row;
justify-content: space-between;
background-color: #456ea6;
align-items: center;
padding-left: 20px;
padding-right: 20px;
}
.style_div{
background-color: #ffffff;
height: 70px;
flex-direction: row;
justify-content: center;
align-items:center;
border-bottom-width: 1px;
border-bottom-color: #f2f2f2;
border-bottom-style: solid;
font-size: 50px;
margin-top: 20px;
margin-bottom: 20px;
padding-top: 20px;
padding-bottom: 20px;
padding-right: 20px;
}
.label_text{
width: 187px;
color: #333;
font-size: 34px;
height: 70px;
line-height: 70px;
}
.value_text{
width: 460px;
height: 70px;
line-height: 70px;
color: #333;
font-size: 34px;
}
</style>
这一步算是基本完成了简单的Spinner下拉选择,实际项目中不光有名字,还有已选择的Value等数据实体。那么问题来了,如何把Android选择的内容返回到Js当中呢?
Android扩展的组件如何传参到Js
我们需要看一下继承的WXComponent类中关于事件传递,其中发现了fireEvent方法适合我们,方法内调用的是WXSDKInstance.fireEvent,而内部又调用WXBridgeManager.getInstance().fireEventOnNode方法,在此方法里边调用addJSEventTask方法,里边使用WXHashMap把我们想要传递的参数封装到KEY_ARGS(args)中。
如果以上没看懂的可以去看看内部如何调用,这里不做过多解释,回到我们初衷,如何实现Android扩展组件Spinner选择的数据回传到Js当中。
重点内容: 在Android扩展组件Spinner类的initSpinner方法中实现监听事件并调用fireEvent方法
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long l) {
Map<String, Object> resp = new HashMap();
resp.put("data", list.get(position));
fireEvent("refresh",resp);
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
划重点: put的是Key是’data’, fireEvent的是”refresh”
在Vue文件中,绑定refresh的监听事件,事件回调AndroidWeex源码内封装的KEY_ARGS(args),具体如下:
1、在template模板spinnertest标签中增加事件refresh
<wxspinnertest class="value_text" :type="type" @refresh="onrefresh"></wxspinnertest>
2、在script脚本实现onrefresh事件,并增加回调的args。
const modal = weex.requireModule('modal')
export default {
name: 'app',
data () {
return {
type:1
}
},
methods:{
onrefresh(args){
modal.toast({
message: '选择的魔戒是'+args.data,
duration: 0.3
})
},
}
}
Vue文件如何让扩展组件Spinner显示指定的值
一般情况下,有新增就会有详情修改,那么我们只实现了新增的情况,而实际项目中,获取的详情譬如:魔戒为霍比特人4,要如何处理呢?
我们需要再增加个扩展方法用于回显:
1、Android扩展组件Spinner文件中增加扩展方法value,贴下最终Spinner类全部代码
public class WXSpinnerTest extends WXComponent<Spinner> {
private Spinner spinner;
private List<String> list;
public WXSpinnerTest(WXSDKInstance instance, WXDomObject dom, WXVContainer parent, boolean isLazy) {
super(instance, dom, parent, isLazy);
}
@Override
protected Spinner initComponentHostView(@NonNull Context context) {
spinner = new Spinner(context);
return spinner;
}
@WXComponentProp(name = "type")
public void initSpinner(String type){
//这里的type实际项目当中查询数据库时必要的参数,所以预留出来
list = new ArrayList<>();
for (int i=0;i<10;i++){
list.add("霍比特人"+i);
}
ArrayAdapter<String> adapter = new ArrayAdapter<>(getContext(), R.layout.row_spn, list);
adapter.setDropDownViewResource(R.layout.row_spn_dropdown);
spinner.setAdapter(adapter);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long l) {
Map<String, Object> resp = new HashMap();
resp.put("data", list.get(position));
fireEvent("refresh",resp);
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
}
@WXComponentProp(name = "value")
public void onSpinnerValue(int value){
spinner.setSelection(value);//这里直接传入的是下标
}
}
2、Vue文件Script的data中增加个value,值为4,
template的wxspinnertest标签增加绑定value,贴下全部代码。
<template>
<div class="app">
<div class="div-top-link">
</div>
<div class="style_div">
<text class="label_text">魔戒</text>
<wxspinnertest class="value_text" :type="type" :value="value" @refresh="onrefresh"></wxspinnertest>
</div>
</div>
</div>
</template>
<script>
const modal = weex.requireModule('modal')
export default {
name: 'app',
data () {
return {
type:1,
value:4
}
},
methods:{
onrefresh(args){
modal.toast({
message: '选择的魔戒是'+args.data,
duration: 0.3
})
}
}
}
</script>
<style>
.div-top-link {
width: 750px;
height: 128px;
flex-direction: row;
justify-content: space-between;
background-color: #456ea6;
align-items: center;
padding-left: 20px;
padding-right: 20px;
}
.style_div{
background-color: #ffffff;
height: 70px;
flex-direction: row;
justify-content: center;
align-items:center;
border-bottom-width: 1px;
border-bottom-color: #f2f2f2;
border-bottom-style: solid;
font-size: 50px;
margin-top: 20px;
margin-bottom: 20px;
padding-top: 20px;
padding-bottom: 20px;
padding-right: 20px;
}
.label_text{
width: 187px;
color: #333;
font-size: 34px;
height: 70px;
line-height: 70px;
}
.value_text{
width: 460px;
height: 70px;
line-height: 70px;
color: #333;
font-size: 34px;
}
</style>
结语
自此,Android扩展组件Spinner的实现过程已经介绍完毕,因个人技术有限,在实现过程中可能存在并不是很好的处理方式,如事件传递,下拉框位置固定等,在Vue文件中需要将原生扩展的组件进行再次封装,以减少不必要的style等。另一方面IOS及Web如何配合实现并没有了解,还望多多指正,共同学习成长。