一、说明
在打印小票的时候,商品名称一行显示不下需要折行打印,但是这个折行又不是放在末尾,到头后再折回来接着打印,该怎么办呢 ?
二、思路
大体的思路就是将商品名称切割成最大不超过一定长度的若干个字符串,在第一行打印商品名的第一个字符串,然后再打印单价、数量、金额等信息,打印完第一行后再在下面打印名称没打印完成的部分。
三、问题
切割的时候又会有个问题,商品信息里面有汉字,有字母,还会有数字和特殊符号,如果切割不好,很有可能会切出乱码。
一般一个汉字占2个字节,一个英文字母是占1个字节;平常在占位上一个汉字是占2个英文字母的位置,平常开发的时候我们一般是以UTF-8格式的,如果想计算好宽度又需要将其转为gbk 或 gb2312,总体来说需要考虑的面还是比较多的。
四、解决方案
/**
* 按字节截取字符串
*/
public class SubByteString {
public static String subStr(String str, int subSLength) throws UnsupportedEncodingException{
if (str == null)
return "";
else{
int tempSubLength = subSLength;
String subStr = str.substring(0, str.length()<subSLength ? str.length() : subSLength);
int subStrByetsL = subStr.getBytes("GBK").length;
while (subStrByetsL > tempSubLength){
int subSLengthTemp = --subSLength;
subStr = str.substring(0, subSLengthTemp>str.length() ? str.length() : subSLengthTemp);
subStrByetsL = subStr.getBytes("GBK").length;
}
return subStr;
}
}
public static String[] getSubedStrings(String string, int unitLength) {
if (TextUtils.isEmpty(string)) {
return null;
}
String str = new String(string);
int arraySize = 0;
try {
arraySize = str.getBytes("GBK").length / unitLength;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if (str.getBytes().length % unitLength > 0) {
arraySize++;
}
String[] result = new String[arraySize];
for (int i = 0; i < arraySize; i++) {
try {
result[i] = subStr(str, unitLength);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
str = str.replace(result[i], "");
}
return result;
}
}
用以上代码可以将一个字符串切割成一个字符数组,这样将第一行显示不下的再多打印几行即可完成商品名称换行问题。最后,我将格式化整个商品信息小票打印的代码贴出来,以供参考:
public class PrintSplitUtil {
private static final String PRINT_LINE = "------------------------------------------------\n"
public static final int PRINT_TOTAL_LENGTH = 48 * 3
public static final short PRINT_POSITION_0 = 0
public static final short PRINT_POSITION_1 = 26 * 3
public static final short PRINT_POSITION_2 = 32 * 3
public static final short PRINT_POSITION_3 = 42 * 3
public static final int MAX_GOODS_NAME_LENGTH = 22 * 3
public static final short PRINT_UNIT = 43
public static PrinterSplitInfo getPrintText(Context context, GoodsListInfo goodsInfo, String store, String userMobile, String qrCode) {
PrinterSplitInfo printerSplitInfo = new PrinterSplitInfo()
EscCommand esc = new EscCommand()
esc.addInitializePrinter()
// 顶部图片
esc.addSelectJustification(JUSTIFICATION.CENTER)
Bitmap b = BitmapFactory.decodeResource(context.getResources(), R.mipmap.printer_logo)
esc.addRastBitImage(b, 200, 0)
esc.addPrintAndLineFeed()
esc.addText(PRINT_LINE)
// 订单信息
if (!TextUtils.isEmpty(store)) {
esc.addSelectJustification(JUSTIFICATION.LEFT)
esc.addSelectPrintModes(FONT.FONTA, ENABLE.ON, ENABLE.OFF, ENABLE.OFF, ENABLE.OFF)
esc.addText(store + "\n")
}
esc.addSelectJustification(JUSTIFICATION.LEFT)
esc.addSelectPrintModes(FONT.FONTA, ENABLE.OFF, ENABLE.OFF, ENABLE.OFF, ENABLE.OFF)
// 头部信息
esc.addText("打印编号:" + goodsInfo.express_sn)
esc.addPrintAndLineFeed()
esc.addText("操作时间:" + DateTimeUtil.getCurrentDateTime())
esc.addPrintAndLineFeed()
esc.addText("操作员:" + userMobile)
esc.addPrintAndLineFeed()
esc.addText(PRINT_LINE)
// 商品头信息
esc.addSetHorAndVerMotionUnits((byte) PRINT_UNIT, (byte) 0)
esc.addText("商品名")
esc.addSetAbsolutePrintPosition(PRINT_POSITION_1)
esc.addText("单价")
esc.addSetAbsolutePrintPosition(PRINT_POSITION_2)
esc.addText("数量")
esc.addSetAbsolutePrintPosition(PRINT_POSITION_3)
esc.addText("金额")
esc.addPrintAndLineFeed()
// 商品信息
if (goodsInfo.goods_list != null && goodsInfo.goods_list.size() > 0) {
esc.addSelectPrintModes(FONT.FONTA, ENABLE.OFF, ENABLE.ON, ENABLE.OFF, ENABLE.OFF)
for (int i = 0
GoodsListInfo.GoodsListBean goods = goodsInfo.goods_list.get(i)
String[] goodsNames = SubByteString.getSubedStrings(goods.goods_name, 20)
printerSplitInfo.dataRow += goodsNames.length
// 商品名称
if (goodsNames != null && goodsNames.length > 0) {
esc.addText((i + 1) + "." + goodsNames[0])
} else {
esc.addText((i + 1) + "." + goods.goods_name)
}
esc.addSetHorAndVerMotionUnits((byte) PRINT_UNIT, (byte) 0)
// 单价
short priceLength = (short) goods.goods_price.length()
short pricePosition = (short) (PRINT_POSITION_1 + 12 - priceLength * 3)
esc.addSetAbsolutePrintPosition(pricePosition)
esc.addText(goods.goods_price)
// 数量
short numLength = (short) (goods.goods_num + goods.goods_unit).getBytes().length
short numPosition = (short) (PRINT_POSITION_2 + 14 - numLength * 3)
esc.addSetAbsolutePrintPosition(numPosition)
esc.addText(goods.goods_num + goods.goods_unit)
// 金额
short amountLength = (short) goods.goods_amount.replace(" ", "").getBytes().length
short amountPosition = (short) (PRINT_POSITION_3 + 11 - amountLength * 3)
esc.addSetAbsolutePrintPosition(amountPosition)
esc.addText(goods.goods_amount)
if (goodsNames == null || goodsNames.length == 0) {
esc.addPrintAndLineFeed()
} else if (goodsNames != null && goodsNames.length > 1) {
for (int j = 1
esc.addText(goodsNames[j])
esc.addPrintAndLineFeed()
}
}
}
esc.addSelectPrintModes(FONT.FONTA, ENABLE.OFF, ENABLE.OFF, ENABLE.OFF, ENABLE.OFF)
esc.addText(PRINT_LINE)
}
// 总计信息
esc.addSelectJustification(JUSTIFICATION.RIGHT)
if (!TextUtils.isEmpty(goodsInfo.subsidy)) {
esc.addText("优惠补贴:" + goodsInfo.subsidy + "元\n")
}
if (!TextUtils.isEmpty(goodsInfo.goods_amount)) {
esc.addText("金额总计:" + goodsInfo.goods_amount + "元\n")
}
if (!TextUtils.isEmpty(goodsInfo.order_amount)) {
esc.addText("还需支付:" + goodsInfo.order_amount + "元\n")
}
esc.addText(PRINT_LINE)
// 打印二维码
if (!TextUtils.isEmpty(qrCode)) {
esc.addPrintAndLineFeed()
esc.addSelectJustification(JUSTIFICATION.CENTER)
esc.addText("请打开微信,扫码付款\n")
esc.addPrintAndLineFeed()
// 48 49 50 51
esc.addSelectErrorCorrectionLevelForQRCode((byte) 0x31)
esc.addSelectSizeOfModuleForQRCode((byte) 7)
esc.addStoreQRCodeData(qrCode)
esc.addPrintQRCode()
esc.addPrintAndLineFeed()
esc.addText("请将二维码放平整后再扫码\n")
}
esc.addPrintAndFeedLines((byte) 3)
// 加入查询打印机状态,打印完成后,此时会接收到GpCom.ACTION_DEVICE_STATUS广播
esc.addQueryPrinterStatus()
// 最终数据
Vector<Byte> datas = esc.getCommand()
byte[] bytes = GpUtils.ByteTo_byte(datas)
String result = Base64.encodeToString(bytes, Base64.DEFAULT)
printerSplitInfo.data = result
return printerSplitInfo
}
}
五、小票展示
这是最后完成后打印出来的小票样式,以供参考: