From 839a9e2054cfb0532c14f222c3aaaf750cb40033 Mon Sep 17 00:00:00 2001 From: ZhanGSKen Date: Mon, 22 Sep 2025 08:07:42 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=B1=BB=E5=BA=93=E3=80=82?= =?UTF-8?q?=E5=A4=84=E7=90=86=E4=BB=8EAPPBase=E8=BD=AC=E7=A7=BB=E8=BF=87?= =?UTF-8?q?=E6=9D=A5=E7=9A=84=E6=A8=A1=E5=9D=97=EF=BC=8C=E4=BF=AE=E6=95=B4?= =?UTF-8?q?=E4=B8=80=E4=B8=8B=E4=BA=8C=E7=BB=B4=E7=A0=81=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E7=AA=97=E5=8F=A3=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apputils/build.properties | 4 +- apputils/src/main/AndroidManifest.xml | 16 +- .../studio/apputils/AssetsHtmlActivity.java | 13 +- .../winboll/studio/apputils/MainActivity.java | 18 +- .../studio/apputils/QRCodeDecodeActivity.java | 429 ++++++++++++++++-- .../studio/apputils/QRGeneratorActivity.java | 97 ++++ .../studio/apputils/WinBoLLActivity.java | 12 +- .../main/res/layout/activity_qrcodedecode.xml | 43 +- .../main/res/layout/activity_qrgenerator.xml | 45 ++ apputils/src/main/res/menu/toolbar_main.xml | 4 +- libapputils/build.gradle | 2 +- libapputils/build.properties | 4 +- .../libapputils/models/ResponseData.java | 53 +++ .../libapputils/models/UserInfoModel.java | 92 ++++ .../studio/libapputils/utils/YunUtils.java | 6 +- 15 files changed, 729 insertions(+), 109 deletions(-) create mode 100644 apputils/src/main/java/cc/winboll/studio/apputils/QRGeneratorActivity.java create mode 100644 apputils/src/main/res/layout/activity_qrgenerator.xml create mode 100644 libapputils/src/main/java/cc/winboll/studio/libapputils/models/ResponseData.java create mode 100644 libapputils/src/main/java/cc/winboll/studio/libapputils/models/UserInfoModel.java diff --git a/apputils/build.properties b/apputils/build.properties index 83cf439..8dbeb8c 100644 --- a/apputils/build.properties +++ b/apputils/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Sun Sep 21 22:28:28 GMT 2025 +#Mon Sep 22 00:04:26 GMT 2025 stageCount=0 libraryProject=libapputils baseVersion=15.9 publishVersion=15.9.0 -buildCount=2 +buildCount=23 baseBetaVersion=15.9.1 diff --git a/apputils/src/main/AndroidManifest.xml b/apputils/src/main/AndroidManifest.xml index 41176ff..3f5b35f 100644 --- a/apputils/src/main/AndroidManifest.xml +++ b/apputils/src/main/AndroidManifest.xml @@ -2,20 +2,26 @@ - + + + + + android:supportsRtl="true" + android:resizeableActivity="true" + android:requestLegacyExternalStorage="true"> + android:exported="true" + android:resizeableActivity="true"> @@ -35,6 +41,8 @@ + + - \ No newline at end of file + diff --git a/apputils/src/main/java/cc/winboll/studio/apputils/AssetsHtmlActivity.java b/apputils/src/main/java/cc/winboll/studio/apputils/AssetsHtmlActivity.java index 822af56..2480eea 100644 --- a/apputils/src/main/java/cc/winboll/studio/apputils/AssetsHtmlActivity.java +++ b/apputils/src/main/java/cc/winboll/studio/apputils/AssetsHtmlActivity.java @@ -15,12 +15,11 @@ import android.view.MenuItem; import android.widget.Toolbar; import cc.winboll.studio.apputils.R; import cc.winboll.studio.libappbase.LogUtils; -import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity; import cc.winboll.studio.libapputils.views.SimpleWebView; import java.io.IOException; import java.io.InputStream; -public class AssetsHtmlActivity extends WinBoLLActivity implements IWinBoLLActivity { +public class AssetsHtmlActivity extends Activity { public static final String TAG = "AssetsHtmlActivity"; @@ -32,16 +31,6 @@ public class AssetsHtmlActivity extends WinBoLLActivity implements IWinBoLLActiv // Assets 文件夹里的 Html 文件的名称 String mszHtmlFileName; - - @Override - public Activity getActivity() { - return this; - } - - @Override - public String getTag() { - return TAG; - } @Override public boolean onCreateOptionsMenu(Menu menu) { diff --git a/apputils/src/main/java/cc/winboll/studio/apputils/MainActivity.java b/apputils/src/main/java/cc/winboll/studio/apputils/MainActivity.java index 20eb17e..ae43fb4 100644 --- a/apputils/src/main/java/cc/winboll/studio/apputils/MainActivity.java +++ b/apputils/src/main/java/cc/winboll/studio/apputils/MainActivity.java @@ -15,9 +15,10 @@ import android.widget.Toolbar; import cc.winboll.studio.apputils.R; import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogView; -import cc.winboll.studio.libappbase.utils.ToastUtils; +import cc.winboll.studio.libappbase.ToastUtils; import java.util.List; import java.util.Set; +import cc.winboll.studio.libappbase.LogActivity; final public class MainActivity extends Activity { @@ -145,13 +146,7 @@ final public class MainActivity extends Activity { } public void onTestLogActivity(View view) { -// Intent intent = new Intent(this, LogActivity.class); -// intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); -// intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); -// startActivity(intent); - - //WinBoLLActivityManager.getInstance().printAvtivityListInfo(); - //WinBoLLActivityManager.getInstance(this).startWinBoLLActivity(this, LogActivity.class); + LogActivity.startLogActivity(this); } // @@ -217,10 +212,9 @@ final public class MainActivity extends Activity { if (item.getItemId() == R.id.item_exit) { //exit(); return true; -// } else if (item.getItemId() == R.id.item_teststringtoqrcodeview) { -// Intent intent = new Intent(this, TestStringToQRCodeViewActivity.class); -// startActivityForResult(intent, REQUEST_QRCODEDECODE_ACTIVITY); -// //WinBoLLActivityManager.getInstance(this).startWinBoLLActivity(this, TestStringToQrCodeViewActivity.class); + } else if (item.getItemId() == R.id.item_testqrgeneratoractivity) { + Intent intent = new Intent(this, QRGeneratorActivity.class); + startActivity(intent); } else if (item.getItemId() == R.id.item_testqrcodedecodeactivity) { Intent intent = new Intent(this, QRCodeDecodeActivity.class); startActivityForResult(intent, REQUEST_QRCODEDECODE_ACTIVITY); diff --git a/apputils/src/main/java/cc/winboll/studio/apputils/QRCodeDecodeActivity.java b/apputils/src/main/java/cc/winboll/studio/apputils/QRCodeDecodeActivity.java index 8561e18..50fa432 100644 --- a/apputils/src/main/java/cc/winboll/studio/apputils/QRCodeDecodeActivity.java +++ b/apputils/src/main/java/cc/winboll/studio/apputils/QRCodeDecodeActivity.java @@ -1,89 +1,323 @@ package cc.winboll.studio.apputils; /** - * @Author ZhanGSKen + * @Author ZhanGSKen&豆包大模型 * @Date 2025/01/18 10:32:21 - * @Describe 二维码扫码解码窗口 + * @Describe 二维码解码窗口 */ import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; +import android.graphics.Paint; +import android.net.Uri; import android.os.Bundle; +import android.provider.MediaStore; +import android.view.View; +import android.widget.Button; +import android.widget.ScrollView; import android.widget.TextView; import android.widget.Toolbar; import cc.winboll.studio.apputils.R; +import com.google.zxing.BarcodeFormat; +import com.google.zxing.BinaryBitmap; +import com.google.zxing.DecodeHintType; +import com.google.zxing.LuminanceSource; +import com.google.zxing.MultiFormatReader; +import com.google.zxing.NotFoundException; +import com.google.zxing.RGBLuminanceSource; +import com.google.zxing.Result; import com.google.zxing.ResultPoint; +import com.google.zxing.common.HybridBinarizer; import com.journeyapps.barcodescanner.BarcodeCallback; import com.journeyapps.barcodescanner.BarcodeResult; import com.journeyapps.barcodescanner.DecoratedBarcodeView; +import com.journeyapps.barcodescanner.DefaultDecoderFactory; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Hashtable; import java.util.List; public class QRCodeDecodeActivity extends Activity { public static final String TAG = "QRCodeDecodeActivity"; - public static final String EXTRA_RESULT = "EXTRA_RESULT"; private static final int REQUEST_CAMERA_PERMISSION = 1; + private static final int REQUEST_PICK_IMAGE = 2; + private static final int REQUEST_READ_STORAGE_PERMISSION = 3; + // 图片压缩阈值:超过1000px时压缩,避免内存溢出和解码效率低 + private static final int MAX_BITMAP_SIZE = 1000; - TextView resultTextView; - DecoratedBarcodeView barcodeView; - -// @Override -// public Activity getActivity() { -// return this; -// } + private TextView resultTextView; + private DecoratedBarcodeView barcodeView; + private Button btnDecodeFromAlbum; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_qrcodedecode); - - // 初始化工具栏 -// Toolbar mToolbar = findViewById(R.id.toolbar); -// setActionBar(mToolbar); - - //resultTextView = findViewById(R.id.activityqrcodedecodeTextView1); - barcodeView = findViewById(R.id.activityqrcodedecodeDecoratedBarcodeView1); - // 请求相机权限 -// if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.CAMERA) -// != PackageManager.PERMISSION_GRANTED) { -// ActivityCompat.requestPermissions(this, -// new String[]{android.Manifest.permission.CAMERA}, -// REQUEST_CAMERA_PERMISSION); -// } else { -// startScanning(); -// } - startScanning(); + initToolbar(); + initViews(); + checkCameraPermission(); + setAlbumDecodeClickListener(); } - private void startScanning() { - barcodeView.getBarcodeView().setDecoderFactory(null); - barcodeView.decodeContinuous(barcodeCallback); - } - - @Override - public void onRequestPermissionsResult(int requestCode, - String[] permissions, int[] grantResults) { - if (requestCode == REQUEST_CAMERA_PERMISSION) { - if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - startScanning(); - } else { - // 权限被拒绝的处理 + private void initToolbar() { + Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar); + if (mToolbar != null) { + setActionBar(mToolbar); + if (getActionBar() != null) { + getActionBar().setDisplayHomeAsUpEnabled(true); + mToolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); } } } - BarcodeCallback barcodeCallback = new BarcodeCallback(){ + private void initViews() { + resultTextView = (TextView) findViewById(R.id.activityqrcodedecodeTextView1); + barcodeView = (DecoratedBarcodeView) findViewById(R.id.activityqrcodedecodeDecoratedBarcodeView1); + btnDecodeFromAlbum = (Button) findViewById(R.id.btn_decode_from_album); + // 初始化扫码解码器(支持所有常见码制,避免仅支持QR_CODE的局限) + List formats = new ArrayList(); + formats.add(BarcodeFormat.QR_CODE); + formats.add(BarcodeFormat.CODE_128); + formats.add(BarcodeFormat.EAN_13); + barcodeView.getBarcodeView().setDecoderFactory(new DefaultDecoderFactory(formats)); + } + + private void setAlbumDecodeClickListener() { + btnDecodeFromAlbum.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) + != PackageManager.PERMISSION_GRANTED) { + requestPermissions(new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE}, + REQUEST_READ_STORAGE_PERMISSION); + } else { + openAlbum(); + } + } + }); + } + + private void openAlbum() { + Intent pickImageIntent = new Intent(Intent.ACTION_PICK); + pickImageIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*"); + startActivityForResult(pickImageIntent, REQUEST_PICK_IMAGE); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == REQUEST_PICK_IMAGE && resultCode == RESULT_OK && data != null) { + Uri selectedImageUri = data.getData(); + if (selectedImageUri != null) { + try { + // 1. 读取图片并压缩(关键优化:避免大图片解码失败) + InputStream imageStream = getContentResolver().openInputStream(selectedImageUri); + BitmapFactory.Options options = new BitmapFactory.Options(); + options.inJustDecodeBounds = true; // 先获取图片尺寸,不加载像素 + BitmapFactory.decodeStream(imageStream, null, options); + imageStream.close(); // 关闭流,重新读取 + + // 计算压缩比例:超过MAX_BITMAP_SIZE时按比例压缩 + options.inSampleSize = calculateInSampleSize(options, MAX_BITMAP_SIZE, MAX_BITMAP_SIZE); + options.inJustDecodeBounds = false; // 开始加载压缩后的像素 + imageStream = getContentResolver().openInputStream(selectedImageUri); + Bitmap originalBitmap = BitmapFactory.decodeStream(imageStream, null, options); + imageStream.close(); + + if (originalBitmap == null) { + showToast("图片损坏,无法解析"); + return; + } + + // 2. 图片预处理:转为灰度图+提高对比度(解决模糊/低对比度图片识别问题) + Bitmap processedBitmap = processBitmap(originalBitmap); + + // 3. 解码预处理后的图片 + String decodeResult = decodeQrFromBitmap(processedBitmap); + + // 4. 结果处理 + if (decodeResult != null && !decodeResult.isEmpty()) { + resultTextView.setText("图片解码结果:" + decodeResult); + showDecodeResultDialog(decodeResult); + returnResultToPreviousPage(decodeResult); + } else { + // 尝试直接解码原图(防止预处理过度导致识别失败) + String originalResult = decodeQrFromBitmap(originalBitmap); + if (originalResult != null && !originalResult.isEmpty()) { + resultTextView.setText("图片解码结果:" + originalResult); + showDecodeResultDialog(originalResult); + returnResultToPreviousPage(originalResult); + } else { + new AlertDialog.Builder(this) + .setTitle("解码失败") + .setMessage("图片中未识别到二维码/条码,建议选择清晰、完整的图片") + .setPositiveButton("确定", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }) + .show(); + } + } + + // 回收Bitmap,避免内存泄漏 + if (!originalBitmap.isRecycled()) originalBitmap.recycle(); + if (!processedBitmap.isRecycled() && processedBitmap != originalBitmap) { + processedBitmap.recycle(); + } + + } catch (Exception e) { + e.printStackTrace(); + showToast("图片处理失败:" + e.getMessage()); + } + } else { + showToast("未选择图片"); + } + } + } + + /** + * 核心优化1:计算图片压缩比例 + */ + private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { + final int height = options.outHeight; + final int width = options.outWidth; + int inSampleSize = 1; + + if (height > reqHeight || width > reqWidth) { + final int halfHeight = height / 2; + final int halfWidth = width / 2; + // 找到最接近reqWidth/reqHeight的压缩比例(2的倍数,保证图片质量) + while ((halfHeight / inSampleSize) >= reqHeight + && (halfWidth / inSampleSize) >= reqWidth) { + inSampleSize *= 2; + } + } + return inSampleSize; + } + + /** + * 核心优化2:图片预处理(灰度化+提高对比度) + * 解决模糊、低亮度、低对比度图片识别率低的问题 + */ + private Bitmap processBitmap(Bitmap bitmap) { + int width = bitmap.getWidth(); + int height = bitmap.getHeight(); + + // 创建灰度图 + Bitmap grayBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(grayBitmap); + Paint paint = new Paint(); + + // 1. 灰度化矩阵 + ColorMatrix grayMatrix = new ColorMatrix(); + grayMatrix.setSaturation(0); // 饱和度设为0,转为灰度 + + // 2. 提高对比度矩阵(alpha=1.5,亮度=0,可根据需求调整) + ColorMatrix contrastMatrix = new ColorMatrix(); + contrastMatrix.set(new float[]{ + 1.5f, 0, 0, 0, 0, // 红通道对比度 + 0, 1.5f, 0, 0, 0, // 绿通道对比度 + 0, 0, 1.5f, 0, 0, // 蓝通道对比度 + 0, 0, 0, 1f, 0 // alpha通道不变 + }); + + // 合并灰度+对比度矩阵 + ColorMatrix combinedMatrix = new ColorMatrix(); + combinedMatrix.postConcat(grayMatrix); + combinedMatrix.postConcat(contrastMatrix); + + paint.setColorFilter(new ColorMatrixColorFilter(combinedMatrix)); + canvas.drawBitmap(bitmap, 0, 0, paint); + + return grayBitmap; + } + + /** + * 核心优化3:修复解码参数,支持更多场景 + */ + private String decodeQrFromBitmap(Bitmap bitmap) { + if (bitmap == null) return null; + + try { + int width = bitmap.getWidth(); + int height = bitmap.getHeight(); + int[] pixels = new int[width * height]; + bitmap.getPixels(pixels, 0, width, 0, 0, width, height); + + // 修复1:使用RGBLuminanceSource,避免YUV格式导致的颜色偏差 + LuminanceSource source = new RGBLuminanceSource(width, height, pixels); + BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(source)); + + // 修复2:完善解码参数,解决模糊、变形二维码识别问题 + Hashtable hints = new Hashtable(); + // 支持所有常见码制(不仅限于QR_CODE) + List formats = new ArrayList(); + formats.add(BarcodeFormat.QR_CODE); + formats.add(BarcodeFormat.CODE_128); + formats.add(BarcodeFormat.EAN_8); + formats.add(BarcodeFormat.EAN_13); + hints.put(DecodeHintType.POSSIBLE_FORMATS, formats); + // 字符编码:支持中文等多语言 + hints.put(DecodeHintType.CHARACTER_SET, "UTF-8"); + // 容错模式:允许二维码有一定损坏(关键!解决轻微变形/污染的二维码) + hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE); + // 不使用纯条码模式,兼容带logo的二维码 + hints.put(DecodeHintType.PURE_BARCODE, Boolean.FALSE); + + MultiFormatReader reader = new MultiFormatReader(); + reader.setHints(hints); + Result result = reader.decode(binaryBitmap); + return result.getText(); + + } catch (NotFoundException e) { + // 正常未识别到,不打印异常(避免日志冗余) + return null; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + // ==================== 原有逻辑(不变) ==================== + private void checkCameraPermission() { + if (checkSelfPermission(android.Manifest.permission.CAMERA) + != PackageManager.PERMISSION_GRANTED) { + requestPermissions(new String[]{android.Manifest.permission.CAMERA}, + REQUEST_CAMERA_PERMISSION); + } else { + startScanning(); + } + } + + private void startScanning() { + barcodeView.decodeContinuous(barcodeCallback); + } + + private BarcodeCallback barcodeCallback = new BarcodeCallback() { @Override public void barcodeResult(BarcodeResult result) { - if (result.getText() != null) { - //Toast.makeText(MainActivity.this, "Scanned: " + result.getText(), Toast.LENGTH_SHORT).show(); - //ToastUtils.show("Scanned: " + result.getText()); + if (result != null && result.getText() != null) { barcodeView.pause(); - Intent intent = new Intent(); - intent.putExtra(EXTRA_RESULT, result.getText()); - setResult(RESULT_OK, intent); - finish(); + String decodeResult = result.getText(); + resultTextView.setText("扫码结果:" + decodeResult); + showDecodeResultDialog(decodeResult); + returnResultToPreviousPage(decodeResult); } } @@ -92,16 +326,111 @@ public class QRCodeDecodeActivity extends Activity { } }; + private void showDecodeResultDialog(String result) { + ScrollView scrollView = new ScrollView(this); + scrollView.setPadding(dip2px(16), dip2px(16), dip2px(16), dip2px(16)); + + TextView dialogTv = new TextView(this); + dialogTv.setTextSize(16); + dialogTv.setTextColor(getResources().getColor(android.R.color.black)); + dialogTv.setText(result); + scrollView.addView(dialogTv); + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setTitle("解码结果"); + builder.setView(scrollView); + builder.setPositiveButton("确定", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + barcodeView.resume(); + } + }); + builder.setCancelable(false); + builder.show(); + } + + private void returnResultToPreviousPage(String result) { + Intent intent = new Intent(); + intent.putExtra(EXTRA_RESULT, result); + setResult(RESULT_OK, intent); + } + + @Override + public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + if (requestCode == REQUEST_CAMERA_PERMISSION) { + if (grantResults != null && grantResults.length > 0) { + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { + startScanning(); + } else { + new AlertDialog.Builder(this) + .setTitle("权限申请") + .setMessage("扫码需要相机权限,请在设置中开启") + .setPositiveButton("确定", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + finish(); + } + }) + .setCancelable(false) + .show(); + } + } + } else if (requestCode == REQUEST_READ_STORAGE_PERMISSION) { + if (grantResults != null && grantResults.length > 0) { + if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { + openAlbum(); + } else { + new AlertDialog.Builder(this) + .setTitle("权限申请") + .setMessage("从相册解码需要存储权限,请在设置中开启") + .setPositiveButton("确定", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }) + .setCancelable(false) + .show(); + } + } + } + } + @Override protected void onResume() { super.onResume(); - barcodeView.resume(); + if (barcodeView != null) { + barcodeView.resume(); + } } @Override protected void onPause() { super.onPause(); - barcodeView.pause(); + if (barcodeView != null) { + barcodeView.pause(); + } + } + + private int dip2px(float dpValue) { + final float scale = getResources().getDisplayMetrics().density; + return (int) (dpValue * scale + 0.5f); + } + + @Override + public boolean onOptionsItemSelected(android.view.MenuItem item) { + if (item.getItemId() == android.R.id.home) { + finish(); + return true; + } + return super.onOptionsItemSelected(item); + } + + private void showToast(String message) { + android.widget.Toast.makeText(this, message, android.widget.Toast.LENGTH_SHORT).show(); } } diff --git a/apputils/src/main/java/cc/winboll/studio/apputils/QRGeneratorActivity.java b/apputils/src/main/java/cc/winboll/studio/apputils/QRGeneratorActivity.java new file mode 100644 index 0000000..87c2f2f --- /dev/null +++ b/apputils/src/main/java/cc/winboll/studio/apputils/QRGeneratorActivity.java @@ -0,0 +1,97 @@ +package cc.winboll.studio.apputils; + +/** + * @Author ZhanGSKen&豆包大模型 + * @Date 2025/09/22 07:09 + * @Describe 二维码生成窗口 + */ +import android.app.Activity; +import android.graphics.Bitmap; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.Toast; +import com.google.zxing.BarcodeFormat; +import com.google.zxing.WriterException; +import com.journeyapps.barcodescanner.BarcodeEncoder; + +public class QRGeneratorActivity extends Activity { + public static final String TAG = "QrGeneratorActivity"; + + // 控件引用 + private EditText etInputText; + private ImageView ivQrPreview; + private Button btnGenerateQr; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_qrgenerator); + + // 初始化控件 + initViews(); + // 设置按钮点击事件 + setGenerateClickListener(); + } + + /** + * 初始化布局控件 + */ + private void initViews() { + etInputText = findViewById(R.id.et_input_text); + ivQrPreview = findViewById(R.id.iv_qr_preview); + btnGenerateQr = findViewById(R.id.btn_generate_qr); + } + + /** + * 设置生成按钮点击事件:获取输入文字 → 生成二维码 → 显示到 ImageView + */ + private void setGenerateClickListener() { + btnGenerateQr.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // 1. 获取输入框文字(去除前后空格) + String inputText = etInputText.getText().toString().trim(); + + // 2. 空输入判断 + if (inputText.isEmpty()) { + Toast.makeText(QRGeneratorActivity.this, "请先输入要生成二维码的文字", Toast.LENGTH_SHORT).show(); + return; + } + + // 3. 生成二维码 Bitmap(宽高 500px,可调整) + Bitmap qrBitmap = generateQrCodeBitmap(inputText, 500, 500); + + // 4. 显示二维码到 ImageView + if (qrBitmap != null) { + ivQrPreview.setImageBitmap(qrBitmap); + } else { + Toast.makeText(QRGeneratorActivity.this, "二维码生成失败,请重试", Toast.LENGTH_SHORT).show(); + } + } + }); + } + + /** + * 核心方法:生成二维码 Bitmap + * @param content 二维码内容(输入的文字) + * @param width 二维码宽度(px) + * @param height 二维码高度(px) + * @return 生成的二维码 Bitmap,失败返回 null + */ + private Bitmap generateQrCodeBitmap(String content, int width, int height) { + try { + // 初始化二维码编码器(指定格式为 QR_CODE) + BarcodeEncoder encoder = new BarcodeEncoder(); + // 生成二维码 Bitmap(参数:内容、格式、宽、高) + return encoder.encodeBitmap(content, BarcodeFormat.QR_CODE, width, height); + } catch (WriterException e) { + // 生成失败(如内容过长、宽高非法),打印异常信息 + e.printStackTrace(); + return null; + } + } +} + diff --git a/apputils/src/main/java/cc/winboll/studio/apputils/WinBoLLActivity.java b/apputils/src/main/java/cc/winboll/studio/apputils/WinBoLLActivity.java index f57a867..1d67048 100644 --- a/apputils/src/main/java/cc/winboll/studio/apputils/WinBoLLActivity.java +++ b/apputils/src/main/java/cc/winboll/studio/apputils/WinBoLLActivity.java @@ -6,19 +6,9 @@ package cc.winboll.studio.apputils; * @Describe WinBoLLActivity */ import android.app.Activity; -import cc.winboll.studio.libappbase.winboll.IWinBoLLActivity; -public class WinBoLLActivity extends Activity implements IWinBoLLActivity { +public class WinBoLLActivity extends Activity { public static final String TAG = "WinBoLLActivity"; - @Override - public Activity getActivity() { - return this; - } - - @Override - public String getTag() { - return TAG; - } } diff --git a/apputils/src/main/res/layout/activity_qrcodedecode.xml b/apputils/src/main/res/layout/activity_qrcodedecode.xml index ba7ff27..1f28ad5 100644 --- a/apputils/src/main/res/layout/activity_qrcodedecode.xml +++ b/apputils/src/main/res/layout/activity_qrcodedecode.xml @@ -1,20 +1,43 @@ - + android:layout_height="match_parent" + android:orientation="vertical"> - + + + + + +