加入收藏 |
设为首页 |
会员中心 | 我要投稿
|
李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
【REACT NATIVE 系列教程之十三】利用LISTVIEW与TEXTINPUT制作聊
发布时间:2020-12-15 05:19:48 所属栏目:百科 来源:网络整理
导读:本站文章均为 李华明Himi 原创,转载务必在明显处注明: 转载自【黑米GameDev街区】 原文链接: http://www.himigame.com/react-native/2346.html 本篇Himi来利用ListView和TextInput这两种组件实现对话、聊天框。 首先需要准备的有几点:(组件的学习就不赘述
本站文章均为
李华明Himi
原创,转载务必在明显处注明:
转载自【黑米GameDev街区】 原文链接:
http://www.himigame.com/react-native/2346.html
本篇Himi来利用ListView和TextInput这两种组件实现对话、聊天框。
首先需要准备的有几点:(组件的学习就不赘述了,简单且官方有文档)
1. 学习下 ListView:
官方示例:http://reactnative.cn/docs/0.27/tutorial.html#content
官方文档:http://reactnative.cn/docs/0.27/listview.html#content
2. 学习下:TextInput:
官方文档:http://reactnative.cn/docs/0.27/textinput.html#content
3. 获取组件实例常用的两种方式:
有时候,渲染出来的组件,我们需要拿到它的实例进行调用其函数等操作。假设有如下代码段:
|
render
(
)
{
return
(
<
Text
>
Himi
<
/
>
)
}
|
如上,如果我们想要拿到这个Text组件的实例对象,有如下两种形式:
第一种:
|
{
(
Text
ref
=
'_text'
>
)
}
|
使用时:this.refs._text ,通过this.refs进行获取。
第二种:
{
var
_text
;
(
=
{
(
text
=
>
{
_text
=
;
}
}
>
Himi
>
)
}
|
使用时:_text ,直接用这个变量即可。
如上都有了一定了解时,那么下面我们进行本篇的正题:
制作一个对话、聊天框,内容可滚动,且最新的消息永远保持在最底部显示!
一:首先我们先简单布局一个聊天场景,布局+各种小组件的使用(代码简单,不多说):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
import
React
,
{
Component
}
from
'react'
;
import
{
View
Text
TouchableHighlight
Image
PixelRatio
ListView
StyleSheet
TextInput
Alert
'react-native'
;
datas
[
{
isMe
:
false
talkContent
:
'最近在学习React Native哦!'
{
true
'听说是个跨平台开发原生App的开源引擎'
{
'嗯啊,很不错,可以尝试下吧。过了这段时间继续研究UE去了。唉~技术出身,就是放不下技术呀~'
{
'感觉编不下去对话了呀......感觉编不下去对话了呀......感觉编不下去对话了呀......感觉编不下去对话了呀......'
{
'无语!'
{
'自说自话,好难!随便补充点字数吧,嗯 就酱紫 :) '
{
'感觉编不下去对话了呀......感觉编不下去对话了呀..'
{
'GG,思密达编不下去了!'
]
;
export
default
class
FarmChildView
extends
.
Component
{
constructor
props
{
super
)
;
this
.
state
{
inputContentText
''
dataSource
:
new
.
DataSource
{
rowHasChanged
row1
row2
row1
!==
;
listHeight
0
;
footerY
;
}
componentDidMount
{
setState
{
state
dataSource
cloneWithRows
datas
)
;
}
renderEveryData
eData
{
(
<
View
style
{
flexDirection
'row'
alignItems
'center'
>
Image
source
==
?
null
:
require
(
'./res/headIcon/ox1.png'
}
?
:
styles
talkImg
}
/
>
?
talkViewRight
talkView
>
.
talkText
>
talkContent
}
>
/
View
>
Image
'./res/headIcon/ox2.png'
null
}
talkImgRight
}
>
>
;
}
myRenderFooter
e
{
}
pressSendBtn
{
}
{
(
.
container
>
topView
>
fontSize
:
20
marginTop
15
color
'#f00'
>
Himi
React
Native
系列教程
>
>
ListView
'_listView'
onLayout
)
>
{
nativeEvent
layout
height
;
}
}
renderRow
renderEveryData
bind
(
}
renderFooter
myRenderFooter
}
>
bottomView
>
searchBox
>
TextInput
'_textInput'
onChangeText
=
}
placeholder
' 请输入对话内容'
returnKeyType
'done'
inputText
}
>
>
TouchableHighlight
underlayColor
{
'#AAAAAA'
}
activeOpacity
{
0.5
}
onPress
pressSendBtn
}
>
sendBtn
>
.
bottomBtnText
>
发送
>
>
TouchableHighlight
>
>
>
;
}
}
styles
create
{
container
{
flex
1
backgroundColor
'#EEEEEE'
topView
:
{
'#DDDDDD'
height
52
padding
5
bottomView
{
5
sendBtn
{
'#FF88C2'
10
borderRadius
5
40
bottomBtnText
{
18
fontWeight
'bold'
talkView
{
'white'
marginLeft
marginRight
55
marginBottom
10
talkImg
{
width
10
talkText
{
16
{
'#90EE90'
justifyContent
'flex-end'
10
{
10
searchBox
{
// 类似于android中的layout_weight,设置为1即自动拉伸填充
// 设置圆角边
inputText
{
'transparent'
5
;
|
以上一共做了这么几件事:
- 顶部添加一个标题
- 添加一个ListView
- 底部添加一个输入框和发送按钮
以上代码需要讲解的有几点:
1.inputContentText 这个state中的变量用于记录用户在TextInput输入的内容
2. this.listHeight = 0; 获取到ListHeight的高度
this.footerY = 0; 记录ListView内容的最底部的Y位置。
(作用后续讲)
3. myRenderFooter(e){} 这里是当ListView的 renderFooter 函数触发时候调用的。(作用后续讲)
4.pressSendBtn 是当当点击发送按钮后,调用我们的自定义函数。
先看下布局后的效果图(点击查看动态效果):
二:下面我们实现点击发送后,将用户在输入框内输入的内容添加到我们的ListView上,并重绘!
主要处理逻辑,Himi已经设计好了,就是在pressSendBtn 函数中处理即可,处理代码段如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
if
inputContentText
trim
length
<=
{
alert
'提示'
'输入的内容不能为空'
;
return
;
}
push
{
this
;
refs
_textInput
clear
;
{
)
)
}
|
1. if( this.state.inputContentText.trim().length <= 0 )
inputContentText用来记录用户在输入框输入的内容,因此这里我们先对内容是否为空进行判定!
trim () 函数不多说了吧,去掉字符串首尾空格。纯空格的内容也不允许发送~
2. datas.push
这里是我们将新的数据添加到ListView中,其中文字内容就是我们记录的用户输入的内容
3. this.refs._textInput.clear()
这里就是我们一开始准备工作介绍的小3节,通过this.refs._textInput()来获取我们定义的TextInput组件实例。
4. 最后我们调用了 this.setState函数来对其两个变量进行修改:
inputContentText :把记录用户刚才输入在聊天框内的内容清空。
dataSource:更新ListView的数据,因为我们刚添加了一条数据
效果图如下(点击查看动态效果):
三:让新的数据永远展示在ListView的底部,其实就是想要一个新数据添加后,自动从下滚上来的效果。
Himi在做这一步的时候考虑过几种方式,下面介绍两种比较容易理解实现的方式:
a) 通过计算每个ListView的每一行View的高度来计算出位置,然后与ListView的视图高度进行对比,最后确定是否进行滚动操作(超出ListView的视图才应该滚动)
b) 根据官方ListView提供的renderFooter函数来完成!
renderFooter:
官方解释:“页头与页脚会在每次渲染过程中都重新渲染(如果提供了这些属性)。如果它们重绘的性能开销很大,把他们包装到一个StaticContainer或者其它恰当的结构中。页脚会永远在列表的最底部,而页头会在最顶部。”
粗糙的理解:每次绘制都会调用renderFooter这个绘制函数,而renderFooter就是绘制ListView最底部的位置。这里不是ListView视图最底部,而且ListView内容高度的最底部位置!!
因此我们通过ListView的renderFooter 绘制一个0高度的view,通过获取其Y位置,其实就是获取到了ListView内容高度底部的Y位置。
这里我们来介绍b方案,简单便捷。关于a方案,我想大家自己都很容易理解实现。
其实通过上面布局这段代码中,可以看到,Himi也已经对renderFooter的函数也绑到了自定义函数myRenderFooter上,所以我们只要在renderFooter中处理即可,如下代码:
{
{
footerY
y
;
if
&&
&&
>
listHeight
{
scrollDistance
-
footerY
;
_listView
scrollTo
y
:
-
scrollDistance
;
}
>
}
|
1. 首先我们先绘制一个0高度的view :return <View/>
2. 通过ListView的onLayout函数来获取并执行我们的滚动等逻辑。
onLayout 函数官方说明:
“当组件挂载或者布局变化的时候调用
参数为:{nativeEvent: { layout: {x,y,width,height}}}
这个事件会在布局计算完成后立即调用一次,不过收到此事件时新的布局可能还没有在屏幕上呈现,尤其是一个布局动画正在进行中的时候。”
3. this.footerY= e.nativeEvent.layout.y;
this.footerY 一开始说过了,用来记录0高度view的相对于ListView所在底部的Y位置。
注:这里Himi定义成this.footerY,原因是Himi也尝试了其他方式实现聊天滚动,为了方便使用。因此大家这里也可以定义var临时的即可。或者直接得到使用都无所谓啦~
4. if( this.listHeight && this.footerY &&this.footerY>this.listHeight )
this.listHeight:与第三步类似,Himi通过ListView的onLayout函数获取到其高度记录在此变量上。
这里的判断目的:当最新的内容高度大雨ListView视图高度后,再开始执行滚动逻辑。
5. 最后的滚动逻辑代码段:
var scrollDistance = this.listHeight – this.footerY;
this.refs._listView.scrollTo({y:-scrollDistance});
首先通过当前ListView的视图高度-内容底部Y位置,获取到相差的举例scrollDistance,这个距离就是我们需要ListView 滚动的举例,且取反滚动!
最后 _listView 是我们ListView的组件实例,因为ListView中也有ScrollView的特性,因此我们可以使用其:
scrollTo({x: 0,y: 0,animated: true})
对我们ListView进行动画滚动操作!
截此,我们的聊天、对话框完成,效果图如下(点击查看动态图):
备注:每一行数据中Himi都定义了一个isMe 的字段,这里来表示说话是对方还是自己。
isMe = true : 头像在右边,说话底为绿色。
isMe =false : 头像放左侧,说话底为白色。
其实这里Himi就是想做一些区分,模仿聊天的对话形式,所以加的变量。大家也可以各种自定义的啦~
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!