前言:
非常多应用需要集成二维码扫描功能,需要自定义样式的话目前只有自己手动绘制,这里只简单做个例子,个性化需求需要自己再根据需求绘制
compile'com.journeyapps:zxing-android-embedded:3.6.0'
compile'com.google.zxing:core:3.3.0'
eg:
代码:
直接上代码,重点在onDraw方法中,注释比较详细了,没有封装,有兴趣的小伙伴可以封装一下,偷懒的同学可以直接使用。
/**
* Created by Administrator on 2018/3/8.
*/
internal class CustomViewfinderView(context:Context, attrs: AttributeSet) : ViewfinderView(context, attrs) {
/* ****************************************** 边角线相关属性 ************************************************/
/**
* "边角线长度/扫描边框长度"的占比 (比例越大,线越长)
*/
var mLineRate =0.05f
/**
* 边角线厚度 (建议使用dp)
*/
var mLineDepth =TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2f, resources.displayMetrics)
/**
* 边角线颜色
*/
var mLineColor = getContext().resources.getColor(R.color.colorAccent)
/* ******************************************* 扫描线相关属性 ************************************************/
/**
* 扫描线起始位置
*/
var mScanLinePosition =0
/**
* 扫描线厚度
*/
var mScanLineDepth =TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2f, resources.displayMetrics)
/**
* 扫描线每次重绘的移动距离
*/
var mScanLineDy =TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 3f, resources.displayMetrics)
/**
* 线性梯度
*/
lateinit var mLinearGradient:LinearGradient
/**
* 线性梯度位置
*/
var mPositions =floatArrayOf(0f, 0.5f, 1f)
/**
* 线性梯度各个位置对应的颜色值
*/
lateinit var nowScanRect:Rect
var buttonRect:RectF? =null
var laserColor_center = getContext().resources.getColor(R.color.colorAccent)
var laserColor_light = getContext().resources.getColor(R.color.colorAccent_light)
var tip = "tip"
var text_btn = "个性化需求"
var screenWidth =0
var screenHeight =0
//扫描线渐变色
var mScanLineColor =intArrayOf(laserColor_light, laserColor_center, laserColor_light)
init {
val manager = (getContext()as Activity).windowManager
val outMetrics = DisplayMetrics()
manager.defaultDisplay.getMetrics(outMetrics)
screenWidth = outMetrics.widthPixels
screenHeight = outMetrics.heightPixels
var w =screenWidth *3 /5
var marginL =screenWidth /5
var marginT =screenHeight /4
nowScanRect = Rect(marginL, marginT, w + marginL, w + marginT)
}
fun drawText(canvas:Canvas, mScanRect:Rect) {
val mTxetPaint = Paint()
mTxetPaint.apply {
color =context.resources.getColor(R.color.common_white)
textSize =DisplayUtils.dp2px(context, 14f).toFloat()
style =Paint.Style.FILL
textAlign =Paint.Align.CENTER
}
canvas.drawText(tip, (screenWidth /2).toFloat(), (mScanRect.top -DisplayUtils.dp2px(context, 22f)).toFloat(), mTxetPaint)
}
fun drawButton(canvas:Canvas, mScanRect:Rect) {
val buttonPaint = Paint()
buttonPaint.apply {
isAntiAlias =true
color =context.resources.getColor(R.color.common_white)
strokeWidth =1f
style =Paint.Style.STROKE
}
var height =DisplayUtils.dp2px(context, 40f)
var left = mScanRect.left + (mScanRect.right - mScanRect.left) /6
var top = mScanRect.bottom +DisplayUtils.dp2px(context, 48f)
var right = mScanRect.right - (mScanRect.right - mScanRect.left) /6
var bottom = mScanRect.bottom +DisplayUtils.dp2px(context, 48f) + height
buttonRect = RectF(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat())
buttonRect?.let {
canvas.drawRoundRect(it, DisplayUtils.dp2px(context, 20f).toFloat(), DisplayUtils.dp2px(context, 20f).toFloat(), buttonPaint)
}
buttonPaint.apply {
color =context.resources.getColor(R.color.common_white)
textSize =DisplayUtils.dp2px(context, 14f).toFloat()
style =Paint.Style.FILL
textAlign =Paint.Align.CENTER
}
var fontMetrics = buttonPaint.fontMetricsInt
// var baseLine = buttonRect.centerY() + (fontMetrics.descent - fontMetrics.ascent) / 2 - fontMetrics.descent
buttonRect?.let {
val baseLine = (it.top +it.bottom - fontMetrics.top - fontMetrics.bottom) /2
canvas.drawText(text_btn, it.centerX(), baseLine, buttonPaint)
}
}
@SuppressLint("DrawAllocation")
override fun onDraw(canvas:Canvas) {
refreshSizes()
if (framingRect ==null ||previewFramingRect ==null) {
return
}
// framingRect = nowScanRect
val frame =nowScanRect
val previewFrame =previewFramingRect
val width = canvas.width
val height = canvas.height
// Draw the exterior (i.e. outside the framing rect) darkened
paint.color =if (resultBitmap !=null)resultColor else maskColor
canvas.drawRect(0f, 0f, width.toFloat(), frame.top.toFloat(), paint)
canvas.drawRect(0f, frame.top.toFloat(), frame.left.toFloat(), (frame.bottom +1).toFloat(), paint)
canvas.drawRect((frame.right +1).toFloat(), frame.top.toFloat(), width.toFloat(), (frame.bottom +1).toFloat(), paint)
canvas.drawRect(0f, (frame.bottom +1).toFloat(), width.toFloat(), height.toFloat(), paint)
// drawText(canvas, frame)
drawButton(canvas, frame)
//绘制4个角
paint.color =mLineColor
// 定义画笔的颜色
//左上-横线
canvas.drawRect(frame.left.toFloat() -mLineDepth,
frame.top.toFloat() -mLineDepth,
frame.left + frame.width() *mLineRate,
frame.top.toFloat(), paint)
//左上-纵线
canvas.drawRect(frame.left.toFloat() -mLineDepth, frame.top.toFloat(), frame.left.toFloat(), frame.top + frame.height() *mLineRate, paint)
//右上-横线
canvas.drawRect(frame.right - frame.width() *mLineRate, frame.top.toFloat() -mLineDepth, frame.right.toFloat() +mLineDepth, frame.top.toFloat(), paint)
//右上-纵线
canvas.drawRect(frame.right.toFloat(), frame.top.toFloat() -mLineDepth, frame.right.toFloat() +mLineDepth, frame.top + frame.height() *mLineRate, paint)
//左下-横线
canvas.drawRect(frame.left.toFloat() -mLineDepth, frame.bottom.toFloat(), frame.left + frame.width() *mLineRate, frame.bottom.toFloat() +mLineDepth, paint)
//左下-纵线
canvas.drawRect(frame.left.toFloat() -mLineDepth, frame.bottom - frame.height() *mLineRate, frame.left.toFloat(), frame.bottom.toFloat(), paint)
//右下-横线
canvas.drawRect(frame.right - frame.width() *mLineRate, frame.bottom.toFloat(), frame.right.toFloat() +mLineDepth, frame.bottom.toFloat() +mLineDepth, paint)
//右下-纵线
canvas.drawRect(frame.right.toFloat(), frame.bottom - frame.height() *mLineRate, frame.right.toFloat() +mLineDepth, frame.bottom.toFloat() +mLineDepth, paint)
if (resultBitmap !=null) {
// Draw the opaque result bitmap over the scanning rectangle
paint.alpha =ViewfinderView.CURRENT_POINT_OPACITY
canvas.drawBitmap(resultBitmap, null, frame, paint)
}else {
// drawLaserLine(canvas,frame)
// 绘制扫描线
mScanLinePosition +=mScanLineDy.toInt()
if (mScanLinePosition > frame.height()) {
mScanLinePosition =0
}
mLinearGradient = LinearGradient(frame.left.toFloat(), (frame.top +mScanLinePosition).toFloat(), frame.right.toFloat(), (frame.top +mScanLinePosition).toFloat(), mScanLineColor, mPositions, Shader.TileMode.CLAMP)
paint.shader =mLinearGradient
canvas.drawRect(frame.left.toFloat(), (frame.top +mScanLinePosition).toFloat(), frame.right.toFloat(), frame.top.toFloat() +mScanLinePosition.toFloat() +mScanLineDepth, paint)
paint.shader =null
val scaleX = frame.width() / previewFrame.width().toFloat()
val scaleY = frame.height() / previewFrame.height().toFloat()
val currentPossible =possibleResultPoints
val currentLast =lastPossibleResultPoints
val frameLeft = frame.left
val frameTop = frame.top
if (currentPossible.isEmpty()) {
lastPossibleResultPoints =null
}else {
possibleResultPoints = ArrayList(5)
lastPossibleResultPoints = currentPossible
paint.alpha =ViewfinderView.CURRENT_POINT_OPACITY
paint.color =resultPointColor
for (pointin currentPossible) {
canvas.drawCircle((frameLeft + (point.x * scaleX).toInt()).toFloat(), (frameTop + (point.y * scaleY).toInt()).toFloat(), ViewfinderView.POINT_SIZE.toFloat(), paint)
}
}
if (currentLast !=null) {
paint.alpha =ViewfinderView.CURRENT_POINT_OPACITY /2
paint.color =resultPointColor
val radius =ViewfinderView.POINT_SIZE /2.0f
for (pointin currentLast) {
canvas.drawCircle((frameLeft + (point.x * scaleX).toInt()).toFloat(), (frameTop + (point.y * scaleY).toInt()).toFloat(), radius, paint)
}
}
}// Request another update at the animation interval, but only repaint the laser line, // not the entire viewfinde
// rmask.
postInvalidateDelayed(CUSTOME_ANIMATION_DELAY, frame.left, frame.top, frame.right, frame.bottom)
}
interface InputView {
fun inputClick()
}
var inputView: InputView? =null
fun setInputView(doInput: () ->Unit) {
this.inputView =object : InputView {
override fun inputClick() {
doInput()
}
}
}
override fun onTouchEvent(event:MotionEvent?):Boolean {
when (event?.action) {
MotionEvent.ACTION_DOWN -> {
val x = event?.x
val y = event?.y
buttonRect?.let {
if (it.contains(x, y)) {
inputView?.inputClick()
}
}
}
}
return super.onTouchEvent(event)
}
companion object {
/**
* 重绘时间间隔
*/
val CUSTOME_ANIMATION_DELAY:Long =16
}
}
使用:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.journeyapps.barcodescanner.BarcodeView
android:id="@+id/zxing_barcode_surface"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.young.demo.CustomViewfinderView
android:id="@+id/zxing_viewfinder_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</FrameLayout>
so easy!