Commit e82b2c21 by 王宇航

添加打印模塊

parent 49bd5ef8
......@@ -113,7 +113,8 @@ ext {
// QMUI
"qmui" : "com.qmuiteam:qmui:1.2.0",
"arms" : "me.jessyan:arms:2.5.2",
"fastjson" : "com.alibaba:fastjson:1.2.46"
"fastjson" : "com.alibaba:fastjson:1.2.46",
"zxing" : "cn.yipianfengye.android:zxing-library:2.2"
]
}
apply from: rootProject.file("cc-settings.gradle")
android {
compileSdkVersion rootProject.ext.android["compileSdkVersion"]
compileOptions {
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
minSdkVersion rootProject.ext.android["minSdkVersion"]
targetSdkVersion rootProject.ext.android["targetSdkVersion"]
if (project.ext.runAsApp) {
applicationId 'com.gingersoft.gsa.cloud.print'
}
versionCode rootProject.ext.android["versionCode"]
versionName rootProject.ext.android["versionName"]
multiDexEnabled true
}
resourcePrefix "print"
buildTypes {
release {
postprocessing {
removeUnusedCode false
removeUnusedResources false
obfuscate false
optimizeCode false
proguardFiles 'proguard.cfg'
}
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.2.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation rootProject.ext.dependencies["zxing"]
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.46'
implementation 'am.util:printer:2.1.0'
}
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
package com.joe.print;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.joe.print.test", appContext.getPackageName());
}
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.joe.print">
<application>
<activity android:name=".PrintActivity"/>
</application>
</manifest>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.joe.print" >
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:name=".MyApp"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/user_register_AppTheme">
<activity android:name=".PrintActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000"
android:orientation="vertical">
<Button
android:id="@+id/btn_print"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="打印"
android:layout_marginTop="50dp"
android:textColor="#333"
android:textSize="16sp" />
<ImageView
android:id="@+id/iv_print"
android:layout_width="match_parent"
android:layout_gravity="center"
android:layout_height="wrap_content"/>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Base application theme. -->
<style name="user_register_AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimary</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>
\ No newline at end of file
package com.joe.print;
import com.billy.cc.core.component.CC;
import com.jess.arms.base.BaseApplication;
/**
* Created by Wyh on 2020/1/7.
*/
public class MyApp extends BaseApplication {
@Override
public void onCreate() {
super.onCreate();
CC.enableVerboseLog(true);
CC.enableDebug(true);
CC.enableRemoteCC(true);
}
}
package com.joe.print;
import android.app.Activity;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.widget.ImageView;
import com.joe.print.adapter.BillAdapter;
import com.joe.print.adapter.FoodAdapter;
import com.joe.print.bean.BillingBean;
import com.joe.print.bean.FoodBean;
import com.joe.print.print.SendPrint;
import java.util.ArrayList;
import java.util.List;
import am.util.printer.PrintExecutor;
import am.util.printer.PrintSocketHolder;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
/**
* Created by Wyh on 2020/1/7.
*/
public class PrintActivity extends Activity implements PrintSocketHolder.OnStateChangedListener, PrintExecutor.OnPrintResultListener{
private ImageView view;
private PrintExecutor executor;
private SendPrint maker;
private RecyclerView rvFood;
private RecyclerView rvBill;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// setContentView(R.layout.activity_print);
setContentView(R.layout.print_layout_print);
rvFood = findViewById(R.id.rv_food);
rvBill = findViewById(R.id.rv_bill_amount);
List<FoodBean> data = new ArrayList<>();
data.add(new FoodBean("包子(主項)",1,13.54));
data.add(new FoodBean("番薯爸爸",2,8.0));
data.add(new FoodBean("包子(主項)",3,37.34));
data.add(new FoodBean("測卡很快就酸辣粉十大減肥和思考",33,1334.2254));
FoodAdapter foodAdapter = new FoodAdapter(data);
rvFood.setLayoutManager(new LinearLayoutManager(this));
rvFood.setAdapter(foodAdapter);
List<BillingBean> billingBeans = new ArrayList<>();
billingBeans.add(new BillingBean("合計", 58.88));
billingBeans.add(new BillingBean("10%服務費", 5.08));
billingBeans.add(new BillingBean("賬單小數", -0.06));
billingBeans.add(new BillingBean("上課交電話費扣水電費可接受的咖啡機", 837248.8829372));
BillAdapter billAdapter = new BillAdapter(billingBeans);
rvBill.setLayoutManager(new LinearLayoutManager(this));
rvBill.setAdapter(billAdapter);
// findViewById(R.id.btn_print).setOnClickListener(v -> {
// if (executor == null) {
// executor = new PrintExecutor("192.168.1.217", 9100, PrinterWriter58mm.TYPE_58);
// executor.setOnStateChangedListener(PrintActivity.this::onResult);
// executor.setOnPrintResultListener(PrintActivity.this);
// }
// executor.setIp("192.168.1.217", 9100);
// executor.doPrinterRequestAsync(maker);
// });
// view = findViewById(R.id.iv_print);
}
public void loadImage(Bitmap bitmap){
runOnUiThread(() -> view.setImageBitmap(bitmap));
}
@Override
public void onResult(int errorCode) {
switch (errorCode) {
case PrintSocketHolder.ERROR_0:
break;
case PrintSocketHolder.ERROR_1:
break;
case PrintSocketHolder.ERROR_2:
break;
case PrintSocketHolder.ERROR_3:
break;
case PrintSocketHolder.ERROR_4:
break;
case PrintSocketHolder.ERROR_5:
break;
}
}
@Override
public void onStateChanged(int state) {
switch (state) {
case PrintSocketHolder.STATE_0:
break;
case PrintSocketHolder.STATE_1:
break;
case PrintSocketHolder.STATE_2:
break;
case PrintSocketHolder.STATE_3:
break;
case PrintSocketHolder.STATE_4:
break;
}
}
}
package com.joe.print;
import com.billy.cc.core.component.CC;
import com.billy.cc.core.component.CCResult;
import com.billy.cc.core.component.CCUtil;
import com.billy.cc.core.component.IComponent;
public class PrintComponent implements IComponent {
@Override
public String getName() {
//组件的名称,调用此组件的方式:
// CC.obtainBuilder("ComponentA")...build().callAsync()
return "Component.Register";
}
/**
* 组件被调用时的入口
* 要确保每个逻辑分支都会调用到CC.sendCCResult,
* 包括try-catch,if-else,switch-case-default,startActivity
* @param cc 组件调用对象,可从此对象中获取相关信息
* @return true:将异步调用CC.sendCCResult(...),用于异步实现相关功能,例如:文件加载、网络请求等
* false:会同步调用CC.sendCCResult(...),即在onCall方法return之前调用,否则将被视为不合法的实现
*/
@Override
public boolean onCall(CC cc) {
String actionName = cc.getActionName();
switch (actionName) {
case "showRegisterActivity":
openActivity(cc);
break;
case "getLifecycleFragment":
//demo for provide fragment object to other component
getLifecycleFragment(cc);
break;
case "lifecycleFragment.addText":
lifecycleFragmentDoubleText(cc);
break;
case "getInfo":
getInfo(cc);
break;
default:
//这个逻辑分支上没有调用CC.sendCCResult(...),是一种错误的示例
//并且方法的返回值为false,代表不会异步调用CC.sendCCResult(...)
//在LocalCCInterceptor中将会返回错误码为-10的CCResult
break;
}
return false;
}
private void lifecycleFragmentDoubleText(CC cc) {
// LifecycleFragment lifecycleFragment = cc.getParamItem("fragment");
// if (lifecycleFragment != null) {
// String text = cc.getParamItem("text", "");
// lifecycleFragment.addText(text);
// CC.sendCCResult(cc.getCallId(), CCResult.success());
// } else {
// CC.sendCCResult(cc.getCallId(), CCResult.error("no fragment params"));
// }
}
private void getLifecycleFragment(CC cc) {
// CC.sendCCResult(cc.getCallId(), CCResult.successWithNoKey(new LifecycleFragment()));
}
private void getInfo(CC cc) {
String userName = "billy";
CC.sendCCResult(cc.getCallId(), CCResult.success("userName", userName));
}
private void openActivity(CC cc) {
CCUtil.navigateTo(cc, PrintActivity.class);
CC.sendCCResult(cc.getCallId(), CCResult.success());
}
}
package com.joe.print.adapter;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.joe.print.R;
import com.joe.print.bean.BillingBean;
import java.util.List;
import androidx.annotation.Nullable;
/**
* Created by Wyh on 2020/1/9.
*/
public class BillAdapter extends BaseQuickAdapter<BillingBean, BaseViewHolder> {
public BillAdapter(@Nullable List<BillingBean> data) {
super(R.layout.print_item_bill, data);
}
@Override
protected void convert(BaseViewHolder helper, BillingBean item) {
helper.setText(R.id.tv_total_text, item.getOptionName());
helper.setText(R.id.tv_total, "$" + item.getTotalAmount());
}
}
package com.joe.print.adapter;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import com.joe.print.R;
import com.joe.print.bean.FoodBean;
import java.util.List;
import androidx.annotation.Nullable;
/**
* Created by Wyh on 2020/1/9.
*/
public class FoodAdapter extends BaseQuickAdapter<FoodBean, BaseViewHolder> {
public FoodAdapter(@Nullable List<FoodBean> data) {
super(R.layout.print_item_food, data);
}
@Override
protected void convert(BaseViewHolder helper, FoodBean item) {
helper.setText(R.id.tv_food_name, item.getFoodName());
helper.setText(R.id.tv_food_quantity, String.valueOf(item.getFoodQuantity()));
helper.setText(R.id.tv_food_price, "$" + item.getPrice());
}
}
package com.joe.print.bean;
/**
* Created by Wyh on 2020/1/9.
* 結賬信息
*/
public class BillingBean {
private String optionName;
private double totalAmount;
public BillingBean(String optionName, double totalAmount) {
this.optionName = optionName;
this.totalAmount = totalAmount;
}
public String getOptionName() {
return optionName;
}
public void setOptionName(String optionName) {
this.optionName = optionName;
}
public double getTotalAmount() {
return totalAmount;
}
public void setTotalAmount(double totalAmount) {
this.totalAmount = totalAmount;
}
}
package com.joe.print.bean;
/**
* Created by Wyh on 2020/1/9.
* 食品信息
*/
public class FoodBean {
private String foodName;
private int foodQuantity;
private double price;
public FoodBean(String foodName, int foodQuantity, double price) {
this.foodName = foodName;
this.foodQuantity = foodQuantity;
this.price = price;
}
public String getFoodName() {
return foodName;
}
public void setFoodName(String foodName) {
this.foodName = foodName;
}
public int getFoodQuantity() {
return foodQuantity;
}
public void setFoodQuantity(int foodQuantity) {
this.foodQuantity = foodQuantity;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
package com.joe.print.print;
import android.content.Context;
import android.graphics.Bitmap;
import android.view.View;
import android.widget.LinearLayout;
import com.joe.print.LayoutToBitmapUtils;
import com.joe.print.R;
import com.joe.print.utils.ImageUtils;
import java.util.ArrayList;
import java.util.List;
import am.util.printer.PrintDataMaker;
import am.util.printer.PrinterUtils;
import am.util.printer.PrinterWriter;
import am.util.printer.PrinterWriter58mm;
import am.util.printer.PrinterWriter80mm;
/**
* Created by Wyh on 2020/1/9.
* 送單打印
*/
public class SendPrint implements PrintDataMaker {
private Context context;
private int parting = 255;//高度分割值,
private int width; // 打印的圖片寬度,紙張寬度
public SendPrint(Context context, int parting, int width) {
this.context = context;
this.parting = parting;
this.width = width;
}
@Override
public List<byte[]> getPrintData(int type) {
ArrayList<byte[]> data = new ArrayList<>();
try {
PrinterWriter printer;
printer = type == PrinterWriter58mm.TYPE_58 ? new PrinterWriter58mm(parting, width) : new PrinterWriter80mm(parting, width);
printer.setAlignCenter();
data.add(printer.getDataAndReset());
View view = LinearLayout.inflate(context, R.layout.print_layout_print, null);
LayoutToBitmapUtils.layoutView(context, view);//先测量
Bitmap bitmap = LayoutToBitmapUtils.loadBitmapFromView(view);//轉bitmap
ArrayList<byte[]> image1 = PrinterUtils.decodeBitmapToDataList(ImageUtils.zoomDrawable(bitmap, width, bitmap.getHeight()), parting);
data.addAll(image1);
printer.printLineFeed();
printer.printLineFeed();
printer.printLineFeed();
printer.printLineFeed();
printer.printLineFeed();
printer.feedPaperCutPartial();
data.add(printer.getDataAndClose());
return data;
} catch (Exception e) {
return new ArrayList<>();
}
}
}
package com.joe.print.utils;
import android.graphics.Bitmap;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import java.util.HashMap;
import java.util.Map;
/**
* Created by Administrator on 2017/5/3.
*/
public class BitmapUtil {
/**
* 生成条码bitmap
* @param content
* @param format
* @param width
* @param height
* @return
*/
public static Bitmap generateBitmap(String content, int format, int width, int height) {
if(content == null || content.equals(""))
return null;
BarcodeFormat barcodeFormat;
switch (format){
case 0:
barcodeFormat = BarcodeFormat.UPC_A;
break;
case 1:
barcodeFormat = BarcodeFormat.UPC_E;
break;
case 2:
barcodeFormat = BarcodeFormat.EAN_13;
break;
case 3:
barcodeFormat = BarcodeFormat.EAN_8;
break;
case 4:
barcodeFormat = BarcodeFormat.CODE_39;
break;
case 5:
barcodeFormat = BarcodeFormat.ITF;
break;
case 6:
barcodeFormat = BarcodeFormat.CODABAR;
break;
case 7:
barcodeFormat = BarcodeFormat.CODE_93;
break;
case 8:
barcodeFormat = BarcodeFormat.CODE_128;
break;
case 9:
barcodeFormat = BarcodeFormat.QR_CODE;
break;
default:
barcodeFormat = BarcodeFormat.QR_CODE;
height = width;
break;
}
MultiFormatWriter qrCodeWriter = new MultiFormatWriter();
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, "GBK");
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
try {
BitMatrix encode = qrCodeWriter.encode(content, barcodeFormat, width, height, hints);
int[] pixels = new int[width * height];
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
if (encode.get(j, i)) {
pixels[i * width + j] = 0x00000000;
} else {
pixels[i * width + j] = 0xffffffff;
}
}
}
return Bitmap.createBitmap(pixels, 0, width, width, height, Bitmap.Config.RGB_565);
} catch (WriterException e) {
e.printStackTrace();
} catch (IllegalArgumentException e){
e.printStackTrace();
}
return null;
}
}
package com.joe.print.utils;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Rect;
/**
* ImageUtils
* 图片处理功能,主要功能是进行黑白化
*
* @author cq
* @create by chen in 2016年8月19日11:43:59
* @modify,
* @modifytime
*/
public class ImageUtils {
/**
* 对图片进行压缩(去除透明度)
*
* @param
*/
private static int errorcode;
public static Bitmap compressPic(Bitmap bitmap, int newWidth, int newHeight) {
// 获取这个图片的宽和高
int width = bitmap.getWidth();
int height = bitmap.getHeight();
// 指定调整后的宽度和高度
// int newWidth = 240;
// int newHeight = 240;
if (newWidth <= 0) {
newWidth = 240;
//setStatus(PrintErrorCode.IMAGE_WIDTH_ERROR);
}
if (newHeight <= 0) {
newHeight = 240;
//setStatus(PrintErrorCode.IMAGE_HEIGHT_ERROR);
}
Bitmap targetBmp = Bitmap.createBitmap(newWidth, newHeight, Bitmap.Config.ARGB_8888);
Canvas targetCanvas = new Canvas(targetBmp);
targetCanvas.drawColor(0xffffffff);
targetCanvas.drawBitmap(bitmap, new Rect(0, 0, width, height), new Rect(0, 0, newWidth, newHeight), null);
return targetBmp;
}
/**
* 灰度图片黑白化,黑色是1,白色是0
*
* @param x 横坐标
* @param y 纵坐标
* @param bit 位图
* @return
*/
public static byte px2Byte(int x, int y, Bitmap bit) {
if (x < bit.getWidth() && y < bit.getHeight()) {
byte b;
int pixel = bit.getPixel(x, y);
int red = (pixel & 0x00ff0000) >> 16; // 取高两位
int green = (pixel & 0x0000ff00) >> 8; // 取中两位
int blue = pixel & 0x000000ff; // 取低两位
int gray = RGB2Gray(red, green, blue);
if (gray < 128) {
b = 1;
} else {
b = 0;
}
return b;
}
return 0;
}
/**
* 图片灰度的转化
*/
private static int RGB2Gray(int r, int g, int b) {
int gray = (int) (0.29900 * r + 0.58700 * g + 0.11400 * b); //灰度转化公式
return gray;
}
/* *************************************************************************
* 假设一个240*240的图片,分辨率设为24, 共分10行打印
* 每一行,是一个 240*24 的点阵, 每一列有24个点,存储在3个byte里面。
* 每个byte存储8个像素点信息。因为只有黑白两色,所以对应为1的位是黑色,对应为0的位是白色
**************************************************************************/
/**
* 把一张Bitmap图片转化为打印机可以打印的字节流
*
* @param bmp
* @return
*/
public static byte[] draw2PxPoint(Bitmap bmp) {
//用来存储转换后的 bitmap 数据。为什么要再加1000,这是为了应对当图片高度无法
//整除24时的情况。比如bitmap 分辨率为 240 * 250,占用 7500 byte,5:5455,3,5447,4,5427
//但是实际上要存储11行数据,每一行需要 24 * 240 / 8 =720byte 的空间。再加上一些指令存储的开销,
//所以多申请 1000byte 的空间是稳妥的,不然运行时会抛出数组访问越界的异常。
int extra = bmp.getWidth() * 24 / 8;
int size = bmp.getWidth() * bmp.getHeight() / 8 + extra;
byte[] data = new byte[size];
int k = 0;
//设置行距为0的指令
data[k++] = 0x1B;
data[k++] = 0x33;
data[k++] = 0x00;
// 逐行打印
for (int j = 0; j < bmp.getHeight() / 24f; j++) {
//打印图片的指令
data[k++] = 0x1B;
data[k++] = 0x2A;
data[k++] = 33;
data[k++] = (byte) (bmp.getWidth() % 256); //nL
data[k++] = (byte) (bmp.getWidth() / 256); //nH
//对于每一行,逐列打印
for (int i = 0; i < bmp.getWidth(); i++) {
//每一列24个像素点,分为3个字节存储
for (int m = 0; m < 3; m++) {
//每个字节表示8个像素点,0表示白色,1表示黑色
for (int n = 0; n < 8; n++) {
byte b = px2Byte(i, j * 24 + m * 8 + n, bmp);
data[k] += data[k] + b;
}
k++;
}
}
data[k++] = 10;//换行
}
// long a=System.currentTimeMillis();
// byte[] data1 = new byte[k];
// System.arraycopy(data, 0, data1, 0, k);
// long b=System.currentTimeMillis();
// System.out.println("结束字节:"+k+"---"+data.length+"耗时:"+(b-a));
return data;
}
public int getStatus() {
return errorcode;
}
private void setStatus(int errorcode) {
this.errorcode = errorcode;
}
/**
* 根據打印紙的寬度縮放圖片
*
* @param oldbmp
* @param w
* @param h
* @return
*/
public static Bitmap zoomDrawable(Bitmap oldbmp, int w, int h) {
int width = oldbmp.getWidth();
int height = oldbmp.getHeight();
Matrix matrix = new Matrix();
float scaleWidth = ((float) w / width);
float scaleHeight = ((float) h / height);
matrix.postScale(scaleWidth, scaleWidth);
return Bitmap.createBitmap(oldbmp, 0, 0, width, height,
matrix, true);
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_total_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.7"
android:gravity="right"
android:text="合计"
android:textColor="#333"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_total"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.3"
android:gravity="right"
android:text="$13.54"
android:textColor="#333"
android:textSize="16sp" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_food_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.5"
android:text="包子撒會計分錄"
android:textColor="#333"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_food_quantity"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.2"
android:gravity="right"
android:text="000013"
android:textColor="#333"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_food_price"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="0.3"
android:gravity="right"
android:text="$000013"
android:textColor="#333"
android:textSize="16sp" />
</LinearLayout>
\ No newline at end of file
<resources>
<string name="app_name">print-Module</string>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Print_text_style">
<item name="android:textColor">#333</item>
<item name="android:textSize">16sp</item>
</style>
</resources>
\ No newline at end of file
package com.joe.print;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}
\ No newline at end of file
......@@ -8,6 +8,7 @@
<!--App主色调-->
<color name="theme_color">#BF1C42</color>
<color name="theme_white_color">#FFFFFFFF</color>
<color name="theme_333_color">#333</color>
<color name="theme_grey_color">#747879</color> <!--灰色tag、字体 -->
<color name="theme_red_color">#ff2500</color> <!--红色强调 -->
<color name="theme_background_color">#EEEDEB</color> <!--页面背景色 -->
......
......@@ -13,6 +13,6 @@ include 'cc-register',
'order-detail',
'order-list',
'table-mode',
'mealstand-mode',
'mealstand-mode'
include ':demo_interceptors', ':print-module'
rootProject.name = 'GSA-Cloud'
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment