我们先来看一下总体的效果
1.逻辑归纳
其实咖啡详情页需要开发的逻辑也不是很多,总体写下来还是不叫轻松的。现将所有需要实现的逻辑归纳如下:
- 咖啡详情页的名称由上一个Slice传递后获取
- 温度和糖度选择后,底部的菜单栏随之更新
- 菜单栏的总价需要根据前一个Slice传递的价格不同显示不同的总价
- 当前咖啡种类数量的选择,当减到0时会有吐司弹框提示
2.开发流程
2.1 咖啡标题
由于咖啡标题是由上一个Slice设置的参数传递过来的,因此直接通过intent获取即可!
当intent不为空时,获取到咖啡标题和价格后更新到对应的组件中,这里我封装了loadCoffeeInfo
方法用于加载咖啡的初始信息
// 加载咖啡的详情页信息
private void loadCoffeeInfo(String coffeeTitle){
Text coffeeTitleTxt = (Text) findComponentById(ResourceTable.Id_coffee_title);
coffeeTitleTxt.setText(coffeeTitle);
Text priceTxt = (Text) findComponentById(ResourceTable.Id_buy_info);
String[] info = priceTxt.getText().split("\\+");
priceTxt.setText(coffeeTitle+"¥"+price+"+"+info[1]+"+"+info[2]);
Text totalPrice = (Text) findComponentById(ResourceTable.Id_total_price);
totalPrice.setText("¥"+price);
}
我们可以观察到这里除了对咖啡详情页的咖啡大标题进行更新 ,还需要对底部菜单栏中的咖啡标题进行更新
注:这里有一个地方需要注意一下
我们这里使用了正则表达式对菜单栏的口味选择进行了字符串分割,是以
+
分割的,所以正则表达式应该是"\\+"
2.2 温度和糖度选择
其实这里温度和糖度选择应该从后端拿到JSON数据,这里我为了简单就自己模仿了Luckin的两组数据,需要对温度和糖度的几个按钮组件件了事件监听
- 通过列表存放所有的按钮,对每一个按钮进行事件监听
- 将选中的按钮的字体和背景颜色进行修改【对其他的未被选中的也进行修改】
- 将选中的按钮信息实时更新到底部的菜单栏【我这里是封装了一个方法
updateMenu
,只要进行了按钮点击就会调用】
private String title;
private String temperature = "热";
private String sweet = "不另外加糖";
private Integer price;
private int totalNum = 1;
/**
* 获取用户的温度选择和口味选择
*/
private void getCoffeeChoose(){
ShapeElement selectElement = new ShapeElement();
selectElement.setRgbColor(new RgbColor(235,237,249));
selectElement.setCornerRadius(vp2px(8));
ShapeElement unselectElement = new ShapeElement();
unselectElement.setRgbColor(new RgbColor(255,255,255));
List<Button> temperatureBtnList = new ArrayList<>();
Button temperatureBtn = (Button) findComponentById(ResourceTable.Id_tem1);
Button temperatureBtn2 = (Button) findComponentById(ResourceTable.Id_tem2);
temperatureBtnList.add(temperatureBtn);
temperatureBtnList.add(temperatureBtn2);
for(Button tempBtn:temperatureBtnList){
tempBtn.setClickedListener(component-> {
temperature = temperatureBtn.getText();
tempBtn.setBackground(selectElement);
tempBtn.setTextColor(new Color(0xff242995));
for (Button curButton1 : temperatureBtnList) {
if (curButton1 != tempBtn) {
curButton1.setBackground(unselectElement);
curButton1.setTextColor(new Color(0xff6a6a6a));
}
}
updateMenu();
});
}
List<Button> sweetBtnList = new ArrayList<>();
Button sweet1 = (Button) findComponentById(ResourceTable.Id_sweet1);
Button sweet2 = (Button) findComponentById(ResourceTable.Id_sweet2);
Button sweet3 = (Button) findComponentById(ResourceTable.Id_sweet3);
sweetBtnList.add(sweet1);
sweetBtnList.add(sweet2);
sweetBtnList.add(sweet3);
for(Button sweetBtn:sweetBtnList){
sweetBtn.setClickedListener(component-> {
sweet = sweetBtn.getText();
sweetBtn.setBackground(selectElement);
sweetBtn.setTextColor(new Color(0xff242995));
for (Button curButton2 : sweetBtnList) {
if (curButton2 != sweetBtn) {
curButton2.setBackground(unselectElement);
curButton2.setTextColor(new Color(0xff6a6a6a));
}
}
updateMenu();
});
}
}
private int vp2px(int vp) {
return AttrHelper.vp2px(vp, this);
}
/**
* 更新购物车信息
*/
private void updateMenu(){
Text priceTxt = (Text) findComponentById(ResourceTable.Id_buy_info);
String[] info = priceTxt.getText().split("\\+");
priceTxt.setText(info[0]+"+"+temperature+"¥0+"+sweet+"¥0");
}
这里有几个小技巧:
- 将vp转化为px,可以直接调用我封装好的方法【比如通过Java代码设置ShapceElement的圆角半径就需要px】
- 设置文本颜色时可以调用setTextColor(new Color(
0xff242995
));【里面必须传递Color对象,Color对象里面可以传递16进制的颜色(但是注意一下前面有两个ff),也可以直接使用封装好的COLOR.RED等】 - 对于未被选中的按钮我们使用了两层for循环判断当前点击的按钮是否是自身【这里我自己也思考过时间复杂度O(n^2)的问题,但是细细一想这里的n这么小,对时间复杂度几乎没有什么影响了】
2.3 数量选择
对于数量选择,对加和减两个图片设置点击监听事件,判断当前是否减为0,如果为0需要使用吐司弹框提示
// 加载咖啡的详情页信息
private void loadCoffeeInfo(String coffeeTitle){
......
// 获取已点数量
Text txt_num = (Text) findComponentById(ResourceTable.Id_num2);
//获取加减
Component btn_minus = findComponentById(ResourceTable.Id_minus2);
Component btn_add = findComponentById(ResourceTable.Id_add2);
btn_add.setClickedListener(component -> {
int num = Integer.parseInt(txt_num.getText()) + 1;
txt_num.setText(num + "");
totalNum = num;
});
btn_minus.setClickedListener(component -> {
int num = Integer.parseInt(txt_num.getText());
if (num == 1){
ShowToastUtil.showToast(this,"再减就没有啦");
}else{
txt_num.setText(num - 1 + "");
totalNum = num - 1;
}
});
// TO DO...
// 实际开发中应该需要根据MainSlice传过来的CoffeeId加载页面内容【如轮播图,内容详情】
}
package com.amx.luckin.utils;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.Text;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.utils.Color;
import ohos.agp.utils.LayoutAlignment;
import ohos.agp.utils.TextAlignment;
import ohos.agp.window.dialog.ToastDialog;
import ohos.app.Context;
import static ohos.agp.components.ComponentContainer.LayoutConfig.MATCH_CONTENT;
import static ohos.agp.components.ComponentContainer.LayoutConfig.MATCH_PARENT;
public class ShowToastUtil {
public static void showToast(Context context, String str) {
// 创建文本组件
Text text = new Text(context);
text.setWidth(MATCH_CONTENT);
text.setHeight(MATCH_CONTENT);
text.setText(str); // 显示文本内容
text.setTextSize(60); // 字号
text.setPadding(30,10,30,10); // 内边距
text.setMultipleLine(true); // 可多行显示文本内容
text.setTextColor(Color.WHITE); // 文字颜色为白色
text.setTextAlignment(TextAlignment.CENTER); // 居中显示
// 文本组件使用灰色圆角背景
ShapeElement element = new ShapeElement();
element.setRgbColor(new RgbColor(0x888888FF));
element.setShape(ShapeElement.RECTANGLE);
element.setCornerRadius(15); // 圆角半径
text.setBackground(element);
// 创建定向布局,并加入文本组件
DirectionalLayout layout = new DirectionalLayout(context);
layout.setWidth(MATCH_PARENT);
layout.setHeight(MATCH_CONTENT);
layout.setAlignment(LayoutAlignment.CENTER); // 居中内容
layout.addComponent(text);
// 创建Toast对话框
ToastDialog toastDialog = new ToastDialog(context);
toastDialog.setComponent(layout); // 使用自定义组件
toastDialog
.setTransparent(true) // 设置背景透明
.setDuration(3000) // 显示时间 3000毫秒
.setAlignment(LayoutAlignment.BOTTOM + LayoutAlignment.HORIZONTAL_CENTER) // 居中下方显示
.setOffset(0, 60) // 距离底边距200px距离
.show();
}
}
2.4 结算后返回
当点击加入购物车后返回上一级Slice并携带结果
我们将前面设置的全局变量当做参数返回给上一个Slice,并通过setResult
将intent返回,最终通过terminate
关闭当前界面后返回
private void addChartNow(){
Button addChartBtn = (Button) findComponentById(ResourceTable.Id_add_chart);
addChartBtn.setClickedListener(component -> {
Intent intent = new Intent();
intent.setParam("price", price);
intent.setParam("title", title);
intent.setParam("temperature", temperature);
intent.setParam("sweet", sweet);
intent.setParam("totalNum", totalNum);
setResult(intent);
terminate(); // 关闭当前页面
});
}
3.整体代码
package com.amx.luckin.slice;
import com.amx.luckin.ResourceTable;
import com.amx.luckin.provider.CoffeeImagePageSliderProvider;
import com.amx.luckin.utils.ShowToastUtil;
import ohos.aafwk.ability.AbilitySlice;
import ohos.aafwk.content.Intent;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.*;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.utils.Color;
import java.util.ArrayList;
import java.util.List;
public class CoffeeDetailSlice extends AbilitySlice {
private final int[] images = {
ResourceTable.Media_lunbo2,
ResourceTable.Media_lunbo4};
private String title;
private String temperature = "热";
private String sweet = "不另外加糖";
private Integer price;
private int totalNum = 1;
@Override
protected void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_coffee_detail);
if (intent != null){
title = (String) intent.getParams().getParam("coffeeTitle");
price = (Integer) intent.getParams().getParam("coffeePrice");
loadCoffeeInfo(title);
}
loadPageSlider(); // 加载轮播图
getCoffeeChoose(); // 获取咖啡选择
addChartNow(); // 加入购物车
}
// 加载咖啡的详情页信息
private void loadCoffeeInfo(String coffeeTitle){
Text coffeeTitleTxt = (Text) findComponentById(ResourceTable.Id_coffee_title);
coffeeTitleTxt.setText(coffeeTitle);
Text priceTxt = (Text) findComponentById(ResourceTable.Id_buy_info);
String[] info = priceTxt.getText().split("\\+");
priceTxt.setText(coffeeTitle+"¥"+price+"+"+info[1]+"+"+info[2]);
Text totalPrice = (Text) findComponentById(ResourceTable.Id_total_price);
totalPrice.setText("¥"+price);
// 获取已点数量
Text txt_num = (Text) findComponentById(ResourceTable.Id_num2);
//获取加减
Component btn_minus = findComponentById(ResourceTable.Id_minus2);
Component btn_add = findComponentById(ResourceTable.Id_add2);
btn_add.setClickedListener(component -> {
int num = Integer.parseInt(txt_num.getText()) + 1;
txt_num.setText(num + "");
totalNum = num;
});
btn_minus.setClickedListener(component -> {
int num = Integer.parseInt(txt_num.getText());
if (num == 1){
ShowToastUtil.showToast(this,"再减就没有啦");
}else{
txt_num.setText(num - 1 + "");
totalNum = num - 1;
}
});
// TO DO...
// 实际开发中应该需要根据MainSlice传过来的CoffeeId加载页面内容【如轮播图,内容详情】
}
// 加载轮播图组件PageSlider
private void loadPageSlider(){
//根据id获得滑动页面组件对象
PageSlider ps = (PageSlider) this.findComponentById(ResourceTable.Id_coffee_detail_pageSlider);
//创建适配器对象,将当前界面对象和封装好的集合发送过去
CoffeeImagePageSliderProvider coffeeDetailImageProvider = new CoffeeImagePageSliderProvider(initPage(), this);
//将适配器加载至滑动组件上,完成同步组装
ps.setProvider(coffeeDetailImageProvider);
}
/**
* 获取用户的温度选择和口味选择
*/
private void getCoffeeChoose(){
ShapeElement selectElement = new ShapeElement();
selectElement.setRgbColor(new RgbColor(235,237,249));
selectElement.setCornerRadius(vp2px(8));
ShapeElement unselectElement = new ShapeElement();
unselectElement.setRgbColor(new RgbColor(255,255,255));
List<Button> temperatureBtnList = new ArrayList<>();
Button temperatureBtn = (Button) findComponentById(ResourceTable.Id_tem1);
Button temperatureBtn2 = (Button) findComponentById(ResourceTable.Id_tem2);
temperatureBtnList.add(temperatureBtn);
temperatureBtnList.add(temperatureBtn2);
for(Button tempBtn:temperatureBtnList){
tempBtn.setClickedListener(component-> {
temperature = temperatureBtn.getText();
tempBtn.setBackground(selectElement);
tempBtn.setTextColor(new Color(0xff242995));
for (Button curButton1 : temperatureBtnList) {
if (curButton1 != tempBtn) {
curButton1.setBackground(unselectElement);
curButton1.setTextColor(new Color(0xff6a6a6a));
}
}
updateMenu();
});
}
List<Button> sweetBtnList = new ArrayList<>();
Button sweet1 = (Button) findComponentById(ResourceTable.Id_sweet1);
Button sweet2 = (Button) findComponentById(ResourceTable.Id_sweet2);
Button sweet3 = (Button) findComponentById(ResourceTable.Id_sweet3);
sweetBtnList.add(sweet1);
sweetBtnList.add(sweet2);
sweetBtnList.add(sweet3);
for(Button sweetBtn:sweetBtnList){
sweetBtn.setClickedListener(component-> {
sweet = sweetBtn.getText();
sweetBtn.setBackground(selectElement);
sweetBtn.setTextColor(new Color(0xff242995));
for (Button curButton2 : sweetBtnList) {
if (curButton2 != sweetBtn) {
curButton2.setBackground(unselectElement);
curButton2.setTextColor(new Color(0xff6a6a6a));
}
}
updateMenu();
});
}
}
private int fp2px(int fp) {
return AttrHelper.fp2px(fp, this);
}
private int vp2px(int vp) {
return AttrHelper.vp2px(vp, this);
}
/**
* 更新购物车信息
*/
private void updateMenu(){
Text priceTxt = (Text) findComponentById(ResourceTable.Id_buy_info);
String[] info = priceTxt.getText().split("\\+");
priceTxt.setText(info[0]+"+"+temperature+"¥0+"+sweet+"¥0");
}
private void addChartNow(){
Button addChartBtn = (Button) findComponentById(ResourceTable.Id_add_chart);
addChartBtn.setClickedListener(component -> {
Intent intent = new Intent();
intent.setParam("price", price);
intent.setParam("title", title);
intent.setParam("temperature", temperature);
intent.setParam("sweet", sweet);
intent.setParam("totalNum", totalNum);
setResult(intent);
terminate(); // 关闭当前页面
});
}
private List<Integer> initPage() {
List<Integer> imagesArray = new ArrayList<>();
for (int image : images) {
imagesArray.add(image);
}
return imagesArray;
}
}