Flutter & OpenHarmony 社交App表情选择器组件开发教程

前言
表情是社交应用中丰富用户表达的重要元素。一个优秀的表情选择器需要支持多个表情分类、流畅的滚动体验、最近使用记录以及搜索功能。本文将详细讲解如何在Flutter和OpenHarmony平台上构建功能完善的表情选择器组件。
Flutter表情选择器实现
首先定义表情数据结构。
class EmojiCategory {
final String name;
final IconData icon;
final List<String> emojis;
EmojiCategory({
required this.name,
required this.icon,
required this.emojis,
});
}
final List<EmojiCategory> emojiCategories = [
EmojiCategory(
name: '笑脸',
icon: Icons.emoji_emotions,
emojis: ['😀', '😃', '😄', '😁', '😆', '😅', '🤣', '😂'],
),
EmojiCategory(
name: '手势',
icon: Icons.waving_hand,
emojis: ['👍', '👎', '👌', '✌️', '🤞', '🤟', '🤘', '👋'],
),
];
EmojiCategory定义表情分类,包含名称、图标和表情列表。预定义的分类数据可以根据需求扩展。
class EmojiPicker extends StatefulWidget {
final Function(String) onEmojiSelected;
const EmojiPicker({
Key? key,
required this.onEmojiSelected,
}) : super(key: key);
State<EmojiPicker> createState() => _EmojiPickerState();
}
class _EmojiPickerState extends State<EmojiPicker> {
int _selectedCategoryIndex = 0;
Widget build(BuildContext context) {
return Container(
height: 280,
color: Colors.white,
child: Column(
children: [
_buildCategoryBar(),
Expanded(child: _buildEmojiGrid()),
],
),
);
}
EmojiPicker组件管理分类选择状态。固定高度280像素适合键盘弹出时的空间。Column垂直排列分类栏和表情网格。
Widget _buildCategoryBar() {
return Container(
height: 44,
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(color: Colors.grey[200]!),
),
),
child: Row(
children: emojiCategories.asMap().entries.map((entry) {
final index = entry.key;
final category = entry.value;
final isSelected = index == _selectedCategoryIndex;
return Expanded(
child: GestureDetector(
onTap: () => setState(() => _selectedCategoryIndex = index),
child: Container(
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: isSelected ? Colors.blue : Colors.transparent,
width: 2,
),
),
),
child: Icon(
category.icon,
color: isSelected ? Colors.blue : Colors.grey,
),
),
),
);
}).toList(),
),
);
}
分类栏使用Row均匀分布各分类图标。选中的分类显示蓝色下划线和蓝色图标,未选中显示灰色。asMap().entries获取索引和值的映射,方便判断选中状态。
Widget _buildEmojiGrid() {
final emojis = emojiCategories[_selectedCategoryIndex].emojis;
return GridView.builder(
padding: EdgeInsets.all(8),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 8,
mainAxisSpacing: 8,
crossAxisSpacing: 8,
),
itemCount: emojis.length,
itemBuilder: (context, index) {
return GestureDetector(
onTap: () => widget.onEmojiSelected(emojis[index]),
child: Center(
child: Text(
emojis[index],
style: TextStyle(fontSize: 24),
),
),
);
},
);
}
}
表情网格使用GridView实现,每行8个表情。点击表情触发onEmojiSelected回调,将选中的表情传递给父组件。字号24像素确保表情清晰可见。
OpenHarmony ArkTS实现
鸿蒙系统上的表情选择器实现。
@Component
struct EmojiPicker {
@State selectedCategoryIndex: number = 0
onEmojiSelected: (emoji: string) => void = () => {}
private categories: EmojiCategory[] = [
{ name: '笑脸', icon: $r('app.media.ic_emoji'), emojis: ['😀', '😃', '😄', '😁'] },
{ name: '手势', icon: $r('app.media.ic_hand'), emojis: ['👍', '👎', '👌', '✌️'] },
]
build() {
Column() {
this.CategoryBar()
this.EmojiGrid()
}
.height(280)
.backgroundColor(Color.White)
}
@State管理选中分类索引。categories定义表情分类数据。Column垂直排列分类栏和表情网格。
@Builder
CategoryBar() {
Row() {
ForEach(this.categories, (category: EmojiCategory, index: number) => {
Column() {
Image(category.icon)
.width(24)
.height(24)
.fillColor(index === this.selectedCategoryIndex ? '#007AFF' : Color.Gray)
}
.layoutWeight(1)
.height(44)
.justifyContent(FlexAlign.Center)
.border({
width: { bottom: index === this.selectedCategoryIndex ? 2 : 0 },
color: '#007AFF'
})
.onClick(() => {
this.selectedCategoryIndex = index
})
})
}
.width('100%')
.border({ width: { bottom: 1 }, color: '#E5E5EA' })
}
CategoryBar使用ForEach遍历分类列表。选中分类显示蓝色图标和下划线。layoutWeight(1)让各分类等宽分布。
@Builder
EmojiGrid() {
Grid() {
ForEach(this.categories[this.selectedCategoryIndex].emojis, (emoji: string) => {
GridItem() {
Text(emoji)
.fontSize(24)
}
.onClick(() => this.onEmojiSelected(emoji))
})
}
.columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr')
.rowsGap(8)
.columnsGap(8)
.padding(8)
.layoutWeight(1)
}
}
EmojiGrid使用Grid组件实现8列布局。ForEach遍历当前分类的表情列表。点击表情触发回调。layoutWeight(1)让网格占据剩余空间。
最近使用功能扩展
在Flutter中实现最近使用表情:
class RecentEmojis {
static const String _key = 'recent_emojis';
static const int _maxCount = 16;
static Future<List<String>> getRecent() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getStringList(_key) ?? [];
}
static Future<void> addRecent(String emoji) async {
final prefs = await SharedPreferences.getInstance();
final recent = await getRecent();
recent.remove(emoji);
recent.insert(0, emoji);
if (recent.length > _maxCount) {
recent.removeLast();
}
await prefs.setStringList(_key, recent);
}
}
RecentEmojis类使用SharedPreferences存储最近使用的表情。addRecent方法将新表情添加到列表开头,并限制最大数量为16个。这种设计让用户能够快速访问常用表情。
总结
本文详细介绍了表情选择器组件在Flutter和OpenHarmony两个平台上的实现。表情是社交应用丰富用户表达的重要元素,需要支持分类浏览和快速选择。两个平台的实现都采用了分类导航和网格布局。在实际项目中,还可以扩展表情搜索、自定义表情包、GIF表情等功能。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
更多推荐


所有评论(0)