安卓实现二维码生成和扫描功能,扫描支持直接拍照扫码和相册图片扫码,还加了照明功能
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了安卓实现二维码生成和扫描功能,扫描支持直接拍照扫码和相册图片扫码,还加了照明功能,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含41688字,纯文字阅读大概需要60分钟。
内容图文
![安卓实现二维码生成和扫描功能,扫描支持直接拍照扫码和相册图片扫码,还加了照明功能](/upload/InfoBanner/zyjiaocheng/1329/a466da0281494b1995bf8a4d5615ef1b.jpg)
最近在做二维码的生成和扫描,生成二维码相对而言较为简单,扫描相对复杂,遇到的问题较多,但是在实现二维码的生成和扫描之前最重要的一步
就是讲Zxing包导入,后面的内容大部分是使用包中的内容,
那我就从二维码的生成讲起吧!
二维码生成:
直接贴代码了
1 // 要转换的地址或字符串,可以是中文,输入内容生成二维码 2 public Bitmap createQRImage(String string) { 3 try { 4 Hashtable<EncodeHintType, String> hints = new Hashtable<EncodeHintType, String>(); 5 hints.put(EncodeHintType.CHARACTER_SET, "utf-8"); 6//图像数据转换,使用了矩阵转换 7 BitMatrix bitMatrix = new QRCodeWriter().encode(string, BarcodeFormat.QR_CODE, QR_WIDTH, QR_HEIGHT, hints); 8int[] pixels = newint[QR_WIDTH * QR_HEIGHT]; 9//下面这里按照二维码的算法,逐个生成二维码的图片, 10//两个for循环是图片横列扫描的结果11for (int y = 0; y < QR_HEIGHT; y++) { 12for (int x = 0; x < QR_WIDTH; x++) { 13if (bitMatrix.get(x, y)) { 14 pixels[y * QR_WIDTH + x] = 0xff000000; 15 } else { 16 pixels[y * QR_WIDTH + x] = 0xffffffff; 17 } 18 } 19 } 20//生成二维码图片的格式,使用ARGB_888821 Bitmap bitmap = Bitmap.createBitmap(QR_WIDTH, QR_HEIGHT, Bitmap.Config.ARGB_8888); 22 bitmap.setPixels(pixels, 0, QR_WIDTH, 0, 0, QR_WIDTH, QR_HEIGHT); 23return bitmap; 24 } catch (WriterException e) { 25 e.printStackTrace(); 26 } 272829returnnull; 30 }
使用这个方法即可生成二维码了
接下来是扫描二维码了
扫描二维码:
我百度了一下,哟不少需要我们自己写的,太多了,我就不一一一写了,就贴出我认为比较重要的两个,一个是CameraManager,一个是ViewfinderView
这两个都可以我们根据自己的爱好相对于的修改样式或扫描框的大小,上代码了
ViewfinderView:
1 private static final String TAG = "log"; 2/** 3 * 刷新界面的时间 4*/ 5privatestaticfinallong ANIMATION_DELAY = 30L; 6privatestaticfinalint OPAQUE = 0xFF; 7 8/** 9 * 四个绿色边角对应的长度 10*/ 11privateint ScreenRate; 12 13/** 14 * 四个绿色边角对应的宽度 15*/ 16privatestaticfinalint CORNER_WIDTH = 10; 17/** 18 * 扫描框中的中间线的宽度 19*/ 20privatestaticfinalint MIDDLE_LINE_WIDTH = 6; 21 22/** 23 * 扫描框中的中间线的与扫描框左右的间隙 24*/ 25privatestaticfinalint MIDDLE_LINE_PADDING = 5; 26 27/** 28 * 中间那条线每次刷新移动的距离 29*/ 30privatestaticfinalint SPEEN_DISTANCE = 5; 31 32/** 33 * 手机的屏幕密度 34*/ 35privatestaticfloat density; 36/** 37 * 字体大小 38*/ 39privatestaticfinalint TEXT_SIZE = 16; 40/** 41 * 字体距离扫描框下面的距离 42*/ 43privatestaticfinalint TEXT_PADDING_TOP = 30; 44 45/** 46 * 画笔对象的引用 47*/ 48private Paint paint; 49 50/** 51 * 中间滑动线的最顶端位置 52*/ 53privateint slideTop; 54 55/** 56 * 中间滑动线的最底端位置 57*/ 58privateint slideBottom; 59 60private Bitmap resultBitmap; 61privatefinalint maskColor; 62privatefinalint resultColor; 63privatefinalint frameColor; 64privatefinalint resultPointColor; 65private Collection<ResultPoint> possibleResultPoints; 66private Collection<ResultPoint> lastPossibleResultPoints; 67 68boolean isFirst; 69 70public ViewfinderView(Context context, AttributeSet attrs) { 71super(context, attrs); 72 73 density = context.getResources().getDisplayMetrics().density; 74//将像素转换成dp 75 ScreenRate = (int) (20 * density); 76 77 paint = new Paint(); 78 Resources resources = getResources(); 79 maskColor = resources.getColor(R.color.viewfinder_mask); 80 resultColor = resources.getColor(R.color.result_view); 81 frameColor = resources.getColor(R.color.viewfinder_frame); 82 resultPointColor = resources.getColor(R.color.possible_result_points); 83 possibleResultPoints = new HashSet<ResultPoint>(5); 84 } 85 86 @Override 87publicvoid onDraw(Canvas canvas) { 88//中间的扫描框,你要修改扫描框的大小,去CameraManager里面修改 89 Rect frame = CameraManager.get().getFramingRect(); 90if (frame == null) { 91return; 92 } 93 94//初始化中间线滑动的最上边和最下边 95if (!isFirst) { 96 isFirst = true; 97 slideTop = frame.top; 98 slideBottom = frame.bottom; 99 } 100101//获取屏幕的宽和高102int width = canvas.getWidth(); 103int height = canvas.getHeight(); 104105 paint.setColor(resultBitmap != null ? resultColor : maskColor); 106107//画出扫描框外面的阴影部分,共四个部分,扫描框的上面到屏幕上面,扫描框的下面到屏幕下面 108//扫描框的左边面到屏幕左边,扫描框的右边到屏幕右边109 canvas.drawRect(0, 0, width, frame.top, paint); 110 canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint); 111 canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, 112 paint); 113 canvas.drawRect(0, frame.bottom + 1, width, height, paint); 114115116if (resultBitmap != null) { 117// Draw the opaque result bitmap over the scanning rectangle118 paint.setAlpha(OPAQUE); 119 canvas.drawBitmap(resultBitmap, frame.left, frame.top, paint); 120 } else { 121//这是我自己加的扫描框内部的白线,让扫描框看起来更好看122 paint.setColor(frameColor); 123 canvas.drawRect(frame.left + CORNER_WIDTH, frame.top + CORNER_WIDTH, frame.right + 1 - CORNER_WIDTH, frame.top + 2 + CORNER_WIDTH, paint); 124 canvas.drawRect(frame.left + CORNER_WIDTH, frame.top + 2 + CORNER_WIDTH, frame.left + 2 + CORNER_WIDTH, frame.bottom - 1 - CORNER_WIDTH, paint); 125 canvas.drawRect(frame.right - 1 - CORNER_WIDTH, frame.top + CORNER_WIDTH, frame.right + 1 - CORNER_WIDTH, frame.bottom - 1 - CORNER_WIDTH, paint); 126 canvas.drawRect(frame.left + CORNER_WIDTH, frame.bottom - 1 - CORNER_WIDTH, frame.right + 1 - CORNER_WIDTH, frame.bottom + 1 - CORNER_WIDTH, paint); 127128//画扫描框边上的角,总共8个部分129 paint.setColor(Color.parseColor("#FF038CF7")); 130//左上131 canvas.drawRect(frame.left, frame.top - CORNER_WIDTH, frame.left + ScreenRate, 132 frame.top + CORNER_WIDTH - CORNER_WIDTH, paint); 133 canvas.drawRect(frame.left - CORNER_WIDTH, frame.top - CORNER_WIDTH, frame.left + CORNER_WIDTH - CORNER_WIDTH, frame.top 134 + ScreenRate - CORNER_WIDTH + CORNER_WIDTH, paint); 135//右上136 canvas.drawRect(frame.right - ScreenRate, frame.top - CORNER_WIDTH, frame.right + CORNER_WIDTH, 137 frame.top + CORNER_WIDTH - CORNER_WIDTH, paint); 138 canvas.drawRect(frame.right - CORNER_WIDTH + CORNER_WIDTH, frame.top, frame.right + CORNER_WIDTH, frame.top 139 + ScreenRate, paint); 140//左下141 canvas.drawRect(frame.left - CORNER_WIDTH, frame.bottom - ScreenRate, frame.left + CORNER_WIDTH - CORNER_WIDTH 142 , frame.bottom, paint); 143 canvas.drawRect(frame.left - CORNER_WIDTH, frame.bottom, 144 frame.left + ScreenRate, frame.bottom + CORNER_WIDTH, paint); 145//右下146 canvas.drawRect(frame.right, frame.bottom - ScreenRate, 147 frame.right + CORNER_WIDTH, frame.bottom, paint); 148 canvas.drawRect(frame.right - ScreenRate, frame.bottom, 149 frame.right + CORNER_WIDTH, frame.bottom + CORNER_WIDTH, paint); 150151152//绘制中间的线,每次刷新界面,中间的线往下移动SPEEN_DISTANCE153 slideTop += SPEEN_DISTANCE; 154if (slideTop >= frame.bottom) { 155 slideTop = frame.top; 156 } 157 canvas.drawRect(frame.left + MIDDLE_LINE_PADDING, slideTop - MIDDLE_LINE_WIDTH / 2, frame.right - MIDDLE_LINE_PADDING, slideTop + MIDDLE_LINE_WIDTH / 2, paint); 158159160//画扫描框下面的字161 paint.setColor(Color.WHITE); 162 paint.setTextSize(TEXT_SIZE * density); 163 paint.setAlpha(0x40); 164 paint.setTypeface(Typeface.create("System", Typeface.BOLD)); 165 canvas.drawText(getResources().getString(R.string.scan_text), frame.left, (float) (frame.bottom + (float) TEXT_PADDING_TOP * density), paint); 166167168 Collection<ResultPoint> currentPossible = possibleResultPoints; 169 Collection<ResultPoint> currentLast = lastPossibleResultPoints; 170if (currentPossible.isEmpty()) { 171 lastPossibleResultPoints = null; 172 } else { 173 possibleResultPoints = new HashSet<ResultPoint>(5); 174 lastPossibleResultPoints = currentPossible; 175 paint.setAlpha(OPAQUE); 176 paint.setColor(resultPointColor); 177for (ResultPoint point : currentPossible) { 178 canvas.drawCircle(frame.left + point.getX(), frame.top 179 + point.getY(), 6.0f, paint); 180 } 181 } 182if (currentLast != null) { 183 paint.setAlpha(OPAQUE / 2); 184 paint.setColor(resultPointColor); 185for (ResultPoint point : currentLast) { 186 canvas.drawCircle(frame.left + point.getX(), frame.top 187 + point.getY(), 3.0f, paint); 188 } 189 } 190191192//只刷新扫描框的内容,其他地方不刷新193 postInvalidateDelayed(ANIMATION_DELAY, frame.left, frame.top, 194 frame.right, frame.bottom); 195196 } 197 } 198199publicvoid drawViewfinder() { 200 resultBitmap = null; 201 invalidate(); 202 } 203204/**205 * Draw a bitmap with the result points highlighted instead of the live 206 * scanning display. 207 * 208 * @param barcode An image of the decoded barcode. 209*/210publicvoid drawResultBitmap(Bitmap barcode) { 211 resultBitmap = barcode; 212 invalidate(); 213 } 214215publicvoid addPossibleResultPoint(ResultPoint point) { 216 possibleResultPoints.add(point); 217 }
CameraManager:
1 private static final String TAG = CameraManager.class.getSimpleName(); 2 3privatestaticfinalint MIN_FRAME_WIDTH = 240; 4privatestaticfinalint MIN_FRAME_HEIGHT = 240; 5privatestaticfinalint MAX_FRAME_WIDTH = 720; 6privatestaticfinalint MAX_FRAME_HEIGHT = 480; 7 8privatestatic CameraManager cameraManager; 9 10staticfinalint SDK_INT; // Later we can use Build.VERSION.SDK_INT 11static { 12int sdkInt; 13try { 14 sdkInt = Integer.parseInt(Build.VERSION.SDK); 15 } catch (NumberFormatException nfe) { 16// Just to be safe 17 sdkInt = 10000; 18 } 19 SDK_INT = sdkInt; 20 } 21 22privatefinal Context context; 23privatefinal CameraConfigurationManager configManager; 24private Camera camera; 25private Rect framingRect; 26private Rect framingRectInPreview; 27privateboolean initialized; 28privateboolean previewing; 29privatefinalboolean useOneShotPreviewCallback; 30/** 31 * Preview frames are delivered here, which we pass on to the registered handler. Make sure to 32 * clear the handler so it will only receive one message. 33*/ 34privatefinal PreviewCallback previewCallback; 35/** Autofocus callbacks arrive here, and are dispatched to the Handler which requested them. */ 36privatefinal AutoFocusCallback autoFocusCallback; 37 38/** 39 * Initializes this static object with the Context of the calling Activity. 40 * 41 * @param context The Activity which wants to use the camera. 42*/ 43publicstaticvoid init(Context context) { 44if (cameraManager == null) { 45 cameraManager = new CameraManager(context); 46 } 47 } 48 49/** 50 * Gets the CameraManager singleton instance. 51 * 52 * @return A reference to the CameraManager singleton. 53*/ 54publicstatic CameraManager get() { 55return cameraManager; 56 } 57 58private CameraManager(Context context) { 59 60this.context = context; 61this.configManager = new CameraConfigurationManager(context); 62 63// Camera.setOneShotPreviewCallback() has a race condition in Cupcake, so we use the older 64// Camera.setPreviewCallback() on 1.5 and earlier. For Donut and later, we need to use 65// the more efficient one shot callback, as the older one can swamp the system and cause it 66// to run out of memory. We can‘t use SDK_INT because it was introduced in the Donut SDK. 67//useOneShotPreviewCallback = Integer.parseInt(Build.VERSION.SDK) > Build.VERSION_CODES.CUPCAKE; 68 useOneShotPreviewCallback = Integer.parseInt(Build.VERSION.SDK) > 3; // 3 = Cupcake 69 70 previewCallback = new PreviewCallback(configManager, useOneShotPreviewCallback); 71 autoFocusCallback = new AutoFocusCallback(); 72 } 73//控制开启闪光灯 74publicvoid flashHandler() { 75//camera.startPreview(); 76 Camera.Parameters parameters = camera.getParameters(); 77// 判断闪光灯当前状态來修改 78if (Camera.Parameters.FLASH_MODE_OFF.equals(parameters.getFlashMode())) { 79 turnOn(parameters); 80 } elseif (Camera.Parameters.FLASH_MODE_TORCH.equals(parameters.getFlashMode())) { 81 turnOff(parameters); 82 } 83 } 84//开 85privatevoid turnOn(Camera.Parameters parameters) { 86 parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH); 87 camera.setParameters(parameters); 88 } 89//关 90privatevoid turnOff(Camera.Parameters parameters) { 91 parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); 92 camera.setParameters(parameters); 93 } 94/** 95 * Opens the camera driver and initializes the hardware parameters. 96 * 97 * @param holder The surface object which the camera will draw preview frames into. 98 * @throws IOException Indicates the camera driver failed to open. 99*/100publicvoid openDriver(SurfaceHolder holder) throws IOException { 101102if (camera == null) { 103 System.out.println("wanggsx openDriver camera = null"); 104 camera = Camera.open(); 105if (camera == null) { 106thrownew IOException(); 107 } 108 camera.setPreviewDisplay(holder); 109110if (!initialized) { 111 initialized = true; 112 configManager.initFromCameraParameters(camera); 113 } 114 configManager.setDesiredCameraParameters(camera); 115 FlashlightManager.enableFlashlight(); 116 } else { 117 System.out.println("wangying openDriver camera != null"); 118 camera.setPreviewDisplay(holder);//此处为新增方法119 } 120/*** 121 * 以上内容为更改内容,经实践结果我们发现,viewfinder会出现黑屏的情况,以上内容就是解决的方法, 122 * 我遇到的情况是我从相册中选取图片进行扫描的时候,返回扫描界面的时候就出现viewFinder黑屏,大家复制上面 123 * 的内容,放到这个方法就可以啦! 124*/125126// if (camera == null) { 127// camera = Camera.open(); 128// if (camera == null) { 129// throw new IOException(); 130// } 131// camera.setPreviewDisplay(holder); 132//133// if (!initialized) { 134// initialized = true; 135// configManager.initFromCameraParameters(camera); 136// } 137// configManager.setDesiredCameraParameters(camera); 138139//FIXME 140// SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); 141//????????? 142// if (prefs.getBoolean(PreferencesActivity.KEY_FRONT_LIGHT, false)) { 143// FlashlightManager.enableFlashlight(); 144// } 145// FlashlightManager.enableFlashlight(); 146// }147 } 148149/**150 * Closes the camera driver if still in use. 151*/152publicvoid closeDriver() { 153if (camera != null) { 154 FlashlightManager.disableFlashlight(); 155 camera.release(); 156 camera = null; 157 } 158 } 159160/**161 * Asks the camera hardware to begin drawing preview frames to the screen. 162*/163publicvoid startPreview() { 164if (camera != null && !previewing) { 165 camera.startPreview(); 166 previewing = true; 167 } 168 } 169170/**171 * Tells the camera to stop drawing preview frames. 172*/173publicvoid stopPreview() { 174if (camera != null && previewing) { 175if (!useOneShotPreviewCallback) { 176 camera.setPreviewCallback(null); 177 } 178 camera.stopPreview(); 179 previewCallback.setHandler(null, 0); 180 autoFocusCallback.setHandler(null, 0); 181 previewing = false; 182 } 183 } 184185/**186 * A single preview frame will be returned to the handler supplied. The data will arrive as byte[] 187 * in the message.obj field, with width and height encoded as message.arg1 and message.arg2, 188 * respectively. 189 * 190 * @param handler The handler to send the message to. 191 * @param message The what field of the message to be sent. 192*/193publicvoid requestPreviewFrame(Handler handler, int message) { 194if (camera != null && previewing) { 195 previewCallback.setHandler(handler, message); 196if (useOneShotPreviewCallback) { 197 camera.setOneShotPreviewCallback(previewCallback); 198 } else { 199 camera.setPreviewCallback(previewCallback); 200 } 201 } 202 } 203204/**205 * Asks the camera hardware to perform an autofocus. 206 * 207 * @param handler The Handler to notify when the autofocus completes. 208 * @param message The message to deliver. 209*/210publicvoid requestAutoFocus(Handler handler, int message) { 211if (camera != null && previewing) { 212 autoFocusCallback.setHandler(handler, message); 213//Log.d(TAG, "Requesting auto-focus callback");214 camera.autoFocus(autoFocusCallback); 215 } 216 } 217218/**219 * Calculates the framing rect which the UI should draw to show the user where to place the 220 * barcode. This target helps with alignment as well as forces the user to hold the device 221 * far enough away to ensure the image will be in focus. 222 * 223 * @return The rectangle to draw on screen in window coordinates. 224*/225public Rect getFramingRect() { 226 Point screenResolution = configManager.getScreenResolution(); 227if (framingRect == null) { 228if (camera == null) { 229returnnull; 230 } 231int width = screenResolution.x * 3 / 4; 232if (width < MIN_FRAME_WIDTH) { 233 width = MIN_FRAME_WIDTH; 234 } elseif (width > MAX_FRAME_WIDTH) { 235 width = MAX_FRAME_WIDTH; 236 } 237int height = screenResolution.y * 3 / 6; 238if (height < MIN_FRAME_HEIGHT) { 239 height = MIN_FRAME_HEIGHT; 240 } elseif (height > MAX_FRAME_HEIGHT) { 241 height = MAX_FRAME_HEIGHT; 242 } 243int leftOffset = (screenResolution.x - width) / 2; 244int topOffset = (screenResolution.y - height) / 2; 245 framingRect = new Rect(leftOffset, topOffset, leftOffset + width, topOffset + height); 246 Log.d(TAG, "Calculated framing rect: " + framingRect); 247 } 248return framingRect; 249 } 250251/**252 * Like {@link #getFramingRect} but coordinates are in terms of the preview frame, 253 * not UI / screen. 254*/255public Rect getFramingRectInPreview() { 256if (framingRectInPreview == null) { 257 Rect rect = new Rect(getFramingRect()); 258 Point cameraResolution = configManager.getCameraResolution(); 259 Point screenResolution = configManager.getScreenResolution(); 260//modify here 261// rect.left = rect.left * cameraResolution.x / screenResolution.x; 262// rect.right = rect.right * cameraResolution.x / screenResolution.x; 263// rect.top = rect.top * cameraResolution.y / screenResolution.y; 264// rect.bottom = rect.bottom * cameraResolution.y / screenResolution.y;265 rect.left = rect.left * cameraResolution.y / screenResolution.x; 266 rect.right = rect.right * cameraResolution.y / screenResolution.x; 267 rect.top = rect.top * cameraResolution.x / screenResolution.y; 268 rect.bottom = rect.bottom * cameraResolution.x / screenResolution.y; 269 framingRectInPreview = rect; 270 } 271return framingRectInPreview; 272 } 273274/**275 * Converts the result points from still resolution coordinates to screen coordinates. 276 * 277 * @param points The points returned by the Reader subclass through Result.getResultPoints(). 278 * @return An array of Points scaled to the size of the framing rect and offset appropriately 279 * so they can be drawn in screen coordinates. 280*/281/*282 public Point[] convertResultPoints(ResultPoint[] points) { 283 Rect frame = getFramingRectInPreview(); 284 int count = points.length; 285 Point[] output = new Point[count]; 286 for (int x = 0; x < count; x++) { 287 output[x] = new Point(); 288 output[x].x = frame.left + (int) (points[x].getX() + 0.5f); 289 output[x].y = frame.top + (int) (points[x].getY() + 0.5f); 290 } 291 return output; 292 } 293*/294295/**296 * A factory method to build the appropriate LuminanceSource object based on the format 297 * of the preview buffers, as described by Camera.Parameters. 298 * 299 * @param data A preview frame. 300 * @param width The width of the image. 301 * @param height The height of the image. 302 * @return A PlanarYUVLuminanceSource instance. 303*/304public PlanarYUVLuminanceSource buildLuminanceSource(byte[] data, int width, int height) { 305 Rect rect = getFramingRectInPreview(); 306int previewFormat = configManager.getPreviewFormat(); 307 String previewFormatString = configManager.getPreviewFormatString(); 308switch (previewFormat) { 309// This is the standard Android format which all devices are REQUIRED to support. 310// In theory, it‘s the only one we should ever care about.311case PixelFormat.YCbCr_420_SP: 312// This format has never been seen in the wild, but is compatible as we only care 313// about the Y channel, so allow it.314case PixelFormat.YCbCr_422_SP: 315returnnew PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top, 316 rect.width(), rect.height()); 317default: 318// The Samsung Moment incorrectly uses this variant instead of the ‘sp‘ version. 319// Fortunately, it too has all the Y data up front, so we can read it.320if ("yuv420p".equals(previewFormatString)) { 321returnnew PlanarYUVLuminanceSource(data, width, height, rect.left, rect.top, 322 rect.width(), rect.height()); 323 } 324 } 325thrownew IllegalArgumentException("Unsupported picture format: " + 326 previewFormat + ‘/‘ + previewFormatString); 327 } 328329public Context getContext() { 330return context; 331 }
接下来我们就看看扫描界面的操作了
首先看一下扫描界面,看了之后要做的东西,一目了然了
camera.xml:
1 <?xml version="1.0" encoding="utf-8"?> 2 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="fill_parent" 4 android:layout_height="fill_parent" > 5 6 <SurfaceView 7 android:id="@+id/preview_view" 8 android:layout_width="wrap_content" 9 android:layout_height="wrap_content" 10 android:layout_gravity="center" /> 11 12 <com.wangy.mycode.Zxing.view.ViewfinderView 13 android:id="@+id/viewfinder_view" 14 android:layout_width="wrap_content" 15 android:layout_height="wrap_content" /> 16 <RelativeLayout 17 android:layout_width="fill_parent" 18 android:layout_height="fill_parent" 19 android:layout_gravity="center" 20 android:orientation="vertical" > 21 22 <TextView 23 android:layout_width="fill_parent" 24 android:layout_height="wrap_content" 25 android:layout_alignParentTop="true" 26 android:layout_centerInParent="true" 27 android:background="#038cf7" 28 android:gravity="center" 29 android:paddingBottom="10dp" 30 android:paddingTop="10dp" 31 android:text="二维码扫描" 32 android:textColor="@android:color/white" 33 android:textSize="18sp" 34 android:textStyle="bold" /> 35 <ImageView 36 android:id="@+id/result_back" 37 android:layout_width="wrap_content" 38 android:layout_height="wrap_content" 39 android:src="@drawable/icon_back" 40 android:layout_margin="10dp" 41 android:layout_alignParentLeft="true" 42 /> 43 <TextView 44 android:layout_width="match_parent" 45 android:layout_height="wrap_content" 46 android:minHeight="60dp" 47 android:text="将取景框对准二维码,\n即可自动扫描。" 48 android:textColor="#fff" 49 android:gravity="center" 50 android:textSize="16sp" 51 android:layout_above="@+id/ll_type" 52 /> 53 <LinearLayout 54 android:layout_width="wrap_content" 55 android:layout_height="200dp" 56 android:layout_alignParentRight="true" 57 android:gravity="center" 58 android:orientation="vertical"> 59 <TextView 60 android:id="@+id/btn_shine" 61 android:layout_width="wrap_content" 62 android:layout_height="wrap_content" 63 android:layout_margin="10dp" 64 android:padding="5dp" 65 android:background="@drawable/white" 66 android:text="照明" 67 android:textColor="#fff" 68 android:textSize="15sp" 69 /> 70 </LinearLayout> 71 72 <LinearLayout 73 android:id="@+id/ll_type" 74 android:layout_width="match_parent" 75 android:layout_marginTop="10dp" 76 android:layout_alignParentBottom="true" 77 android:gravity="center" 78 android:layout_height="wrap_content"> 79 <Button 80 android:id="@+id/btn_scan" 81 android:layout_width="70dp" 82 android:layout_height="70dp" 83 android:layout_margin="20dp" 84 android:background="@drawable/blueroll" 85 android:layout_alignParentBottom="true" 86 android:layout_marginBottom="75dp" 87 android:text="扫码" 88 android:textColor="#fff" 89 android:textSize="15sp" 90 /> 91 <Button 92 android:id="@+id/btn_phone" 93 android:layout_width="70dp" 94 android:layout_height="70dp" 95 android:layout_margin="20dp" 96 android:background="@drawable/tranroll" 97 android:layout_alignParentBottom="true" 98 android:layout_marginBottom="75dp" 99 android:text="相册" 100 android:textColor="#fff" 101 android:textSize="15sp" 102 /> 103 </LinearLayout> 104 </RelativeLayout> 105106 </FrameLayout>
看看扫描界面吧!
1 package com.wangy.mycode.Zxing; 2 3 import android.content.Intent; 4 import android.content.res.AssetFileDescriptor; 5 import android.database.Cursor; 6 import android.graphics.Bitmap; 7 import android.graphics.BitmapFactory; 8 import android.graphics.Color; 9 import android.media.AudioManager; 10 import android.media.MediaPlayer; 11 import android.os.Bundle; 12 import android.os.Handler; 13 import android.os.Vibrator; 14 import android.provider.MediaStore; 15 import android.view.KeyEvent; 16 import android.view.SurfaceHolder; 17 import android.view.SurfaceView; 18 import android.view.View; 19 import android.widget.Button; 20 import android.widget.ImageView; 21 import android.widget.TextView; 22 import android.widget.Toast; 23 24 import com.google.zxing.BarcodeFormat; 25 import com.google.zxing.BinaryBitmap; 26 import com.google.zxing.DecodeHintType; 27 import com.google.zxing.Result; 28 import com.google.zxing.common.HybridBinarizer; 29 import com.google.zxing.qrcode.QRCodeReader; 30 import com.wangy.mycode.Base.BaseActivity; 31 import com.wangy.mycode.R; 32 import com.wangy.mycode.RGBLuminanceSource; 33 import com.wangy.mycode.ScanResultActivity; 34 import com.wangy.mycode.Zxing.camera.CameraManager; 35 import com.wangy.mycode.Zxing.decoding.CaptureActivityHandler; 36 import com.wangy.mycode.Zxing.decoding.InactivityTimer; 37 import com.wangy.mycode.Zxing.view.ViewfinderView; 38 import com.wangy.mycode.utils.IntentUtils; 39 40 import java.io.IOException; 41 import java.util.Hashtable; 42 import java.util.Vector; 43 44 /** 45 * Created by xhb on 2016/12/28. 46 */ 47 public class CaptureActivity extends BaseActivity implements SurfaceHolder.Callback, View.OnClickListener { 48private CaptureActivityHandler handler; 49private ViewfinderView viewfinderView; 50privateboolean hasSurface; 51private Vector<BarcodeFormat> decodeFormats; 52private String characterSet; 53private InactivityTimer inactivityTimer; 54private MediaPlayer mediaPlayer; 55privateboolean playBeep; 56privatestaticfinalfloat BEEP_VOLUME = 0.10f; 57privateboolean vibrate; 58private ImageView result_back; 59private Button btn_scan; 60private Button btn_phone; 61privatestaticfinalint CHOOSE_PIC = 0; 62private TextView btn_shine; 63privateboolean isopen; 64 65/** 66 * Called when the activity is first created. 67*/ 68 @Override 69publicvoid onCreate(Bundle savedInstanceState) { 70super.onCreate(savedInstanceState); 71 setContentView(R.layout.camera); 72//ViewUtil.addTopView(getApplicationContext(), this, R.string.scan_card); 73 CameraManager.init(getApplication()); 74 initview(); 75 viewfinderView = (ViewfinderView) findViewById(R.id.viewfinder_view); 76 hasSurface = false; 77 inactivityTimer = new InactivityTimer(this); 78 } 79 80privatevoid initview() { 81 result_back = (ImageView) findViewById(R.id.result_back); 82 btn_scan = (Button) findViewById(R.id.btn_scan); 83 btn_phone = (Button) findViewById(R.id.btn_phone); 84 btn_shine = (TextView)findViewById(R.id.btn_shine); 85 result_back.setOnClickListener(this); 86 btn_scan.setOnClickListener(this); 87 btn_phone.setOnClickListener(this); 88 btn_shine.setOnClickListener(this); 89 } 90 91 @Override 92protectedvoid onResume() { 93super.onResume(); 94 SurfaceView surfaceView = (SurfaceView) findViewById(R.id.preview_view); 95 SurfaceHolder surfaceHolder = surfaceView.getHolder(); 96if (hasSurface) { 97 initCamera(surfaceHolder); 98 } else { 99 surfaceHolder.addCallback(this); 100 surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 101 } 102 decodeFormats = null; 103 characterSet = null; 104105 playBeep = true; 106 AudioManager audioService = (AudioManager) getSystemService(AUDIO_SERVICE); 107if (audioService.getRingerMode() != AudioManager.RINGER_MODE_NORMAL) { 108 playBeep = false; 109 } 110 initBeepSound(); 111 vibrate = true; 112113 } 114115 @Override 116protectedvoid onPause() { 117super.onPause(); 118if (handler != null) { 119 handler.quitSynchronously(); 120 handler = null; 121 } 122 CameraManager.get().closeDriver(); 123 } 124125 @Override 126protectedvoid onDestroy() { 127 inactivityTimer.shutdown(); 128super.onDestroy(); 129 } 130131/**132 * Handler scan result 133 * @param result 134 * @param barcode 135*/136publicvoid handleDecode(Result result, Bitmap barcode) { 137 inactivityTimer.onActivity(); 138 playBeepSoundAndVibrate(); 139 String resultString = result.getText(); 140//FIXME141if (resultString.equals("")) { 142 Toast.makeText(CaptureActivity.this, "扫描失败!", Toast.LENGTH_SHORT).show(); 143 } else { 144 Intent intent = new Intent(CaptureActivity.this, ScanResultActivity.class); 145 intent.putExtra("result", resultString); 146 IntentUtils.enterIntent(CaptureActivity.this, intent); 147 } 148// CaptureActivity.this.finish();149 } 150151privatevoid initCamera(SurfaceHolder surfaceHolder) { 152try { 153 CameraManager.get().openDriver(surfaceHolder); 154 } catch (IOException ioe) { 155return; 156 } catch (RuntimeException e) { 157return; 158 } 159if (handler == null) { 160 handler = new CaptureActivityHandler(this, decodeFormats, 161 characterSet); 162 } 163 } 164165 @Override 166publicvoid surfaceChanged(SurfaceHolder holder, int format, int width, 167int height) { 168169 } 170171 @Override 172publicvoid surfaceCreated(SurfaceHolder holder) { 173if (!hasSurface) { 174 hasSurface = true; 175 initCamera(holder); 176 } 177 } 178179 @Override 180publicvoid surfaceDestroyed(SurfaceHolder holder) { 181 hasSurface = false; 182 } 183184public ViewfinderView getViewfinderView() { 185return viewfinderView; 186 } 187188public Handler getHandler() { 189return handler; 190 } 191192publicvoid drawViewfinder() { 193 viewfinderView.drawViewfinder(); 194 } 195196privatevoid initBeepSound() { 197if (playBeep && mediaPlayer == null) { 198// The volume on STREAM_SYSTEM is not adjustable, and users found it 199// too loud, 200// so we now play on the music stream.201 setVolumeControlStream(AudioManager.STREAM_MUSIC); 202 mediaPlayer = new MediaPlayer(); 203 mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); 204 mediaPlayer.setOnCompletionListener(beepListener); 205206 AssetFileDescriptor file = getResources().openRawResourceFd( 207 R.raw.beep); 208try { 209 mediaPlayer.setDataSource(file.getFileDescriptor(), 210 file.getStartOffset(), file.getLength()); 211 file.close(); 212 mediaPlayer.setVolume(BEEP_VOLUME, BEEP_VOLUME); 213 mediaPlayer.prepare(); 214 } catch (IOException e) { 215 mediaPlayer = null; 216 } 217 } 218 } 219220privatestaticfinallong VIBRATE_DURATION = 200L; 221222privatevoid playBeepSoundAndVibrate() { 223if (playBeep && mediaPlayer != null) { 224 mediaPlayer.start(); 225 } 226if (vibrate) { 227 Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE); 228 vibrator.vibrate(VIBRATE_DURATION); 229 } 230 } 231232/**233 * When the beep has finished playing, rewind to queue up another one. 234*/235privatefinal MediaPlayer.OnCompletionListener beepListener = new MediaPlayer.OnCompletionListener() { 236publicvoid onCompletion(MediaPlayer mediaPlayer) { 237 mediaPlayer.seekTo(0); 238 } 239 }; 240241 @Override 242publicvoid onClick(View v) { 243switch (v.getId()) { 244case R.id.btn_scan: { 245 btn_scan.setBackgroundResource(R.drawable.blueroll); 246 btn_phone.setBackgroundResource(R.drawable.tranroll); 247break; 248 } 249case R.id.btn_phone: { 250 btn_phone.setBackgroundResource(R.drawable.blueroll); 251 btn_scan.setBackgroundResource(R.drawable.tranroll); 252//跳转到图片选择界面去选择一张二维码图片253 Intent intent1 = new Intent(); 254 intent1.setAction(Intent.ACTION_PICK); 255256 intent1.setType("image/*"); 257258 Intent intent2 = Intent.createChooser(intent1, "选择二维码图片"); 259 startActivityForResult(intent2, CHOOSE_PIC); 260break; 261 } 262case R.id.result_back: { 263 overridePendingTransition(R.anim.in_from_left, R.anim.out_to_right); 264 finish(); 265break; 266 } 267case R.id.btn_shine:{ 268if (isopen){ 269 btn_shine.setTextColor(Color.WHITE); 270 btn_shine.setBackgroundResource(R.drawable.white); 271 }else { 272 btn_shine.setTextColor(Color.parseColor("#038cf7")); 273 btn_shine.setBackgroundResource(R.drawable.blue); 274 } 275 isopen=!isopen; 276//控制开启和关闭闪光灯277 CameraManager.get().flashHandler(); 278 } 279default: { 280break; 281 } 282 } 283 } 284285 @Override 286protectedvoid onActivityResult(int requestCode, int resultCode, Intent data) { 287super.onActivityResult(requestCode, resultCode, data); 288 String imgPath = null; 289if (resultCode == RESULT_OK) { 290switch (requestCode) { 291case CHOOSE_PIC: 292try { 293 String[] proj = new String[]{MediaStore.Images.Media.DATA}; 294 Cursor cursor = CaptureActivity.this.getContentResolver().query(data.getData(), proj, null, null, null); 295296if (cursor.moveToFirst()) { 297int columnIndex = cursor.getColumnIndex(MediaStore.Images.Media.DATA); 298 System.out.println(columnIndex); 299//获取到用户选择的二维码图片的绝对路径300 imgPath = cursor.getString(columnIndex); 301 } 302 cursor.close(); 303//获取解析结果304final String finalImgPath = imgPath; 305new Thread(new Runnable() { 306 @Override 307publicvoid run() { 308 Result ret = parseQRcodeBitmap(finalImgPath); 309 Intent intent = new Intent(CaptureActivity.this, ScanResultActivity.class); 310 intent.putExtra("result", ret.toString()); 311 IntentUtils.enterIntent(CaptureActivity.this, intent); 312 } 313 }).start(); 314315 } catch (Exception e) { 316 Toast.makeText(CaptureActivity.this, "扫描失败", Toast.LENGTH_LONG).show(); 317 } 318319break; 320 } 321 } 322 } 323//解析二维码图片,返回结果封装在Result对象中324private com.google.zxing.Result parseQRcodeBitmap(String bitmapPath){ 325//解析转换类型UTF-8326 Hashtable<DecodeHintType, String> hints = new Hashtable<DecodeHintType, String>(); 327 hints.put(DecodeHintType.CHARACTER_SET, "utf-8"); 328//获取到待解析的图片329 BitmapFactory.Options options = new BitmapFactory.Options(); 330//如果我们把inJustDecodeBounds设为true,那么BitmapFactory.decodeFile(String path, Options opt) 331//并不会真的返回一个Bitmap给你,它仅仅会把它的宽,高取回来给你332 options.inJustDecodeBounds = true; 333//此时的bitmap是null,这段代码之后,options.outWidth 和 options.outHeight就是我们想要的宽和高了334 Bitmap bitmap = BitmapFactory.decodeFile(bitmapPath,options); 335//我们现在想取出来的图片的边长(二维码图片是正方形的)设置为400像素336/**337 options.outHeight = 400; 338 options.outWidth = 400; 339 options.inJustDecodeBounds = false; 340 bitmap = BitmapFactory.decodeFile(bitmapPath, options); 341*/342//以上这种做法,虽然把bitmap限定到了我们要的大小,但是并没有节约内存,如果要节约内存,我们还需要使用inSimpleSize这个属性343 options.inSampleSize = options.outHeight / 400; 344if(options.inSampleSize <= 0){ 345 options.inSampleSize = 1; //防止其值小于或等于0346 } 347/**348 * 辅助节约内存设置 349 * 350 * options.inPreferredConfig = Bitmap.Config.ARGB_4444; // 默认是Bitmap.Config.ARGB_8888 351 * options.inPurgeable = true; 352 * options.inInputShareable = true; 353*/354 options.inJustDecodeBounds = false; 355 bitmap = BitmapFactory.decodeFile(bitmapPath, options); 356//新建一个RGBLuminanceSource对象,将bitmap图片传给此对象357 RGBLuminanceSource rgbLuminanceSource = new RGBLuminanceSource(bitmap); 358//将图片转换成二进制图片359 BinaryBitmap binaryBitmap = new BinaryBitmap(new HybridBinarizer(rgbLuminanceSource)); 360//初始化解析对象361 QRCodeReader reader = new QRCodeReader(); 362//开始解析363 Result result = null; 364try { 365 result = reader.decode(binaryBitmap, hints); 366 } catch (Exception e) { 367// TODO: handle exception368 } 369370return result; 371 } 372373 @Override 374publicboolean onKeyDown(int keyCode, KeyEvent event) { 375if (keyCode == KeyEvent.KEYCODE_BACK) { 376 overridePendingTransition(R.anim.in_from_left, R.anim.out_to_right); 377 finish(); 378returnfalse; 379 } else { 380returnsuper.onKeyDown(keyCode, event); 381 } 382 } 383 }
好了,扫描之后,肯定也要对扫描结果进行处理,那就看看ScanResultActivity吧
结果的处理,我是参照qq做的,也没啥难的地方,大家可以看看
1 package com.wangy.mycode; 2 3 import android.content.Intent; 4 import android.os.Bundle; 5 import android.view.Gravity; 6 import android.view.KeyEvent; 7 import android.view.View; 8 import android.webkit.WebChromeClient; 9 import android.webkit.WebSettings; 10 import android.webkit.WebView; 11 import android.webkit.WebViewClient; 12 import android.widget.ImageView; 13 import android.widget.LinearLayout; 14 import android.widget.TextView; 15 import android.widget.Toast; 16 17 import com.wangy.mycode.Base.BaseActivity; 18 import com.wangy.mycode.Zxing.CaptureActivity; 19 20 /** 21 * Created by xhb on 2016/12/28. 22 */ 23 public class ScanResultActivity extends BaseActivity { 24 25private ImageView result_back; 26private TextView scanresult_word; 27private WebView scanresult_webview; 28private String result; 29private LinearLayout ll_result_word; 30 31 @Override 32protectedvoid onCreate(Bundle savedInstanceState) { 33super.onCreate(savedInstanceState); 34 setContentView(R.layout.scanresultlayout); 35 Intent intent = getIntent(); 36if (intent != null) { 37 result = intent.getStringExtra("result"); 38 } 39 initView(); 40 } 41 42privatevoid initView() { 43 result_back = (ImageView) findViewById(R.id.result_back); 44 result_back.setOnClickListener(new View.OnClickListener() { 45 @Override 46publicvoid onClick(View v) { 47// startActivity(new Intent(ScanResultActivity.this,CaptureActivity.class)); 48// overridePendingTransition(R.anim.in_from_left, R.anim.out_to_right); 49 finish(); 50 } 51 }); 52 ll_result_word = (LinearLayout)findViewById(R.id.ll_result_word); 53 scanresult_word = (TextView) findViewById(R.id.scanresult_word); 54 scanresult_webview = (WebView) findViewById(R.id.scanresult_webview); 55if ((result.contains("http://") || result.contains("https://"))) { 56 scanresult_webview.setVisibility(View.VISIBLE); 57 ll_result_word.setVisibility(View.GONE); 58 setScanresult_webview(); 59 }else { 60 scanresult_webview.setVisibility(View.GONE); 61 ll_result_word.setVisibility(View.VISIBLE); 62 scanresult_word.setText(result); 63 } 64 65 } 66privatevoid setScanresult_webview(){ 67if ((result.contains("http://") || result.contains("https://"))) { 68//加载需要显示的网页 69 scanresult_webview.loadUrl(result); 70 } 71 72//覆盖WebView默认使用第三方或系统默认浏览器打开网页的行为,使网页用WebView打开 73 scanresult_webview.setWebViewClient(new WebViewClient() { 74 @Override 75publicboolean shouldOverrideUrlLoading(WebView view, String url) { 76// TODO Auto-generated method stub 77//返回值是true的时候控制去WebView打开,为false调用系统浏览器或第三方浏览器 78 view.loadUrl(url); 79returntrue; 80 } 81 }); 82 WebSettings webSettings = scanresult_webview.getSettings(); 83//设置可以访问文件 84 webSettings.setAllowFileAccess(true); 85 webSettings.setJavaScriptEnabled(true);//支持js 86 webSettings.setJavaScriptCanOpenWindowsAutomatically(true); 87 webSettings.setDomStorageEnabled(true); 88//设置支持缩放 89 webSettings.setBuiltInZoomControls(true); 90// 优先使用缓存 91 scanresult_webview.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); 92 scanresult_webview.setWebChromeClient(new WebChromeClient() { 93 @Override 94publicvoid onProgressChanged(WebView view, int newProgress) { 95// TODO Auto-generated method stub 96if (newProgress == 100) { 97// 网页加载完成 98 showCustomToast("网页加载完成"); 99 } else { 100// 加载中 101// showCustomToast("网页加载中...");102 } 103104 } 105 }); 106// scanresult_webview.setDownloadListener(new DownloadListener() { 107// @Override 108// public void onDownloadStart(String s, String s1, String s2, String s3, long l) { 109// String html = "<a href=‘" + s + "‘>" + s + "</a>"; 110// scanresult_webview.loadData(html, "text/html", "UTF-8"); 111// } 112// });113114115} 116//弹出警告框117publicvoid showCustomToast(String text) { 118 Toast toast = Toast.makeText(ScanResultActivity.this, 119 text, Toast.LENGTH_SHORT); 120 toast.setGravity(Gravity.CENTER, 20, 20); 121 LinearLayout toastView = (LinearLayout) toast.getView(); 122 ImageView imageCodeProject = new ImageView(ScanResultActivity.this); 123 imageCodeProject.setImageResource(R.drawable.ico_warning); 124 toastView.addView(imageCodeProject, 0); 125 toastView.setPadding(100, 85, 100, 85); 126 toast.show(); 127 } 128129// 返回上一次浏览的页面 130131//改写物理按键——返回的逻辑132 @Override 133publicboolean onKeyDown(int keyCode, KeyEvent event) { 134// TODO Auto-generated method stub135if(keyCode==KeyEvent.KEYCODE_BACK) 136 { 137if(scanresult_webview.canGoBack()) 138 { 139 scanresult_webview.goBack();//返回上一页面140returntrue; 141 } 142else143 { 144// startActivity(new Intent(ScanResultActivity.this,CaptureActivity.class)); 145// overridePendingTransition(R.anim.in_from_left, R.anim.out_to_right);146 finish(); 147returnfalse; 148 } 149 } 150returnsuper.onKeyDown(keyCode, event); 151 } 152 }
界面也给大家看看
scanresultlayout
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical"> 6 <RelativeLayout 7 android:layout_width="match_parent" 8 android:layout_height="wrap_content" 9 android:minHeight="50dp" 10 android:background="#038cf7" 11 > 12 <TextView 13 android:layout_width="wrap_content" 14 android:layout_height="wrap_content" 15 android:layout_centerInParent="true" 16 android:text="二维码扫描结果" 17 android:textSize="18sp" 18 android:textColor="#fff" 19 /> 20 <ImageView 21 android:id="@+id/result_back" 22 android:layout_width="wrap_content" 23 android:layout_height="wrap_content" 24 android:src="@drawable/icon_back" 25 android:layout_margin="10dp" 26 android:layout_centerVertical="true" 27 android:layout_alignParentLeft="true" 28 /> 29 </RelativeLayout> 30 <LinearLayout 31 android:id="@+id/ll_result_word" 32 android:layout_width="match_parent" 33 android:orientation="vertical" 34 android:visibility="gone" 35 android:layout_height="wrap_content"> 36 <TextView 37 android:layout_width="match_parent" 38 android:layout_height="wrap_content" 39 android:layout_marginTop="30dp" 40 android:textColor="#e78727" 41 android:text="以下内容非本app提供,请谨慎使用" 42 android:gravity="center" 43 /> 44 <TextView 45 android:layout_width="match_parent" 46 android:layout_height="wrap_content" 47 android:layout_marginTop="5dp" 48 android:text="如需使用请复制" 49 android:textColor="#e78727" 50 android:gravity="center" 51 /> 5253 <TextView 54 android:id="@+id/scanresult_word" 55 android:layout_width="wrap_content" 56 android:layout_height="wrap_content" 57 android:minWidth="300dp" 58 android:minHeight="100dp" 59 android:background="@drawable/yellow" 60 android:layout_marginTop="50dp" 61 android:layout_gravity="center_horizontal" 62 android:text="如需使用请复制" 63 android:textColor="#f5262121" 64 android:textStyle="normal" 65 android:gravity="center" 66 /> 67 </LinearLayout> 6869 <WebView 70 android:id="@+id/scanresult_webview" 71 android:layout_width="match_parent" 72 android:visibility="gone" 73 android:layout_height="match_parent"> 7475 </WebView> 76 </LinearLayout>
就简单介绍到这里吧!我做的app源码地址,有需要的可以看看,参照写一下
下载地址: http://download.csdn.net/detail/sinat_32804317/9725715
原文:http://www.cnblogs.com/wangying222/p/6237470.html
内容总结
以上是互联网集市为您收集整理的安卓实现二维码生成和扫描功能,扫描支持直接拍照扫码和相册图片扫码,还加了照明功能全部内容,希望文章能够帮你解决安卓实现二维码生成和扫描功能,扫描支持直接拍照扫码和相册图片扫码,还加了照明功能所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。