案例效果图:
项目清单文件权限:
build.gradle添加依赖compile 'com.journeyapps:zxing-android-embedded:3.3.0'
要求:
实现如图所示效果,标题栏通过组合View的方式进行实现,统一对外暴露左侧按钮和右侧按钮点击
的方法,在点击右侧的回调方法中跳转到图二所示页面,图二的页面标题栏显示上一个页面组合View
的视图,通过自定义ViewGroup的方式实现梯形布局(下一个视图的起始位置是上一个视图的结束位置)。
图一中间的进度条使用继承自View的方式进行实现,并使用自定义属性的方式来设置进度条中间的颜色。
点击扫描二维码按钮之后,进度条开始以每秒10%的进度进行,当进度条走到100%后,跳转到图三的扫
描二维码页面,实现扫描二维码的功能。
通过组合View的方式实现标题栏
package com.bwie.tixing;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class Header extends RelativeLayout {
private TextView mTextView;
private ImageView ib_right;
private ImageView ib_left;
private String titleText;
private int titleTextColor;
private float titleTextSize;
public Header(Context context) {
super(context);
}
public Header(Context context, AttributeSet attrs) {
super(context, attrs);
//加载视图的布局
LayoutInflater.from(context).inflate(R.layout.header,this,true);
//加载自定义的属性
TypedArray a=context.obtainStyledAttributes(attrs,R.styleable.Header);
titleText=a.getString(R.styleable.Header_titleText);
titleTextColor=a.getColor(R.styleable.Header_titleTextColor, Color.WHITE);
titleTextSize=a.getDimension(R.styleable.Header_titleTextSize,20f);
//回收资源,这一句必须调用
a.recycle();
}
/**
* 此方法会在所有的控件都从xml文件中加载完成后调用
*/
@Override
protected void onFinishInflate() {
super.onFinishInflate();
//获取子控件
mTextView= (TextView) findViewById(R.id.tv_header);
ib_right= (ImageView) findViewById(R.id.ib_right);
ib_left = findViewById(R.id.ib_left);
//将从资源文件中加载的属性设置给子控件
if (!TextUtils.isEmpty(titleText))
setPageTitleText(titleText);
setPageTitleTextColor(titleTextColor);
setPageTitleTextSize(titleTextSize);
}
/**
* 设置标题文字
* @param text
*/
public void setPageTitleText(String text) {
mTextView.setText(text);
}
/**
* 设置标题文字颜色
* @param color
*/
public void setPageTitleTextColor(int color) {
mTextView.setTextColor(color);
}
/**
* 设置标题文字大小
* @param size
*/
public void setPageTitleTextSize(float size) {
mTextView.setTextSize(size);
}
/**
* 设置按钮点击事件监听器
* @param listener
*/
public void setOnRightClickListener(OnClickListener listener) {
ib_right.setOnClickListener(listener);
}
public void setOnLeftClickListener(OnClickListener listener) {
ib_left.setOnClickListener(listener);
}
}
attrs.xml
package com.bwie.tixing;
import android.content.Context;
import android.util.TypedValue;
public class PxUtils {
public static int dpToPx(int dp, Context context) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());
}
public static int spToPx(int sp, Context context) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, context.getResources().getDisplayMetrics());
}
}
package com.bwie.tixing;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
public class CirclePercentView extends View {
//圆的半径
private float mRadius;
//色带的宽度
private float mStripeWidth;
//总体大小
private int mHeight;
private int mWidth;
//动画位置百分比进度
private int mCurPercent;
//实际百分比进度
private int mPercent;
//圆心坐标
private float x;
private float y;
//要画的弧度
private int mEndAngle;
//小圆的颜色
private int mSmallColor;
//大圆颜色
private int mBigColor;
//中心百分比文字大小
private float mCenterTextSize;
public CirclePercentView(Context context) {
this(context, null);
}
public CirclePercentView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CirclePercentView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CirclePercentView, defStyleAttr, 0);
mStripeWidth = a.getDimension(R.styleable.CirclePercentView_stripeWidth, PxUtils.dpToPx(30, context));
mCurPercent = a.getInteger(R.styleable.CirclePercentView_percent, 0);
mSmallColor = a.getColor(R.styleable.CirclePercentView_smallColor,0xffafb4db);
mBigColor = a.getColor(R.styleable.CirclePercentView_bigColor,0xff6950a1);
mCenterTextSize = a.getDimensionPixelSize(R.styleable.CirclePercentView_centerTextSize,PxUtils.spToPx(20,context));
mRadius = a.getDimensionPixelSize(R.styleable.CirclePercentView_radius,PxUtils.dpToPx(100,context));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//获取测量模式
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
//获取测量大小
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY) {
mRadius = widthSize / 2;
x = widthSize / 2;
y = heightSize / 2;
mWidth = widthSize;
mHeight = heightSize;
}
if(widthMode == MeasureSpec.AT_MOST&&heightMode ==MeasureSpec.AT_MOST){
mWidth = (int) (mRadius*2);
mHeight = (int) (mRadius*2);
x = mRadius;
y = mRadius;
}
setMeasuredDimension(mWidth,mHeight);
}
@Override
protected void onDraw(Canvas canvas) {
mEndAngle = (int) (mCurPercent * 3.6);
//绘制大圆
Paint bigCirclePaint = new Paint();
bigCirclePaint.setAntiAlias(true);
bigCirclePaint.setColor(mBigColor);
canvas.drawCircle(x, y, mRadius, bigCirclePaint);
//饼状图
Paint sectorPaint = new Paint();
sectorPaint.setColor(mSmallColor);
sectorPaint.setAntiAlias(true);
RectF rect = new RectF(0, 0, mWidth, mHeight);
canvas.drawArc(rect, 270, mEndAngle, true, sectorPaint);
//绘制小圆,颜色透明
Paint smallCirclePaint = new Paint();
smallCirclePaint.setAntiAlias(true);
smallCirclePaint.setColor(mBigColor);
canvas.drawCircle(x, y, mRadius - mStripeWidth, smallCirclePaint);
//绘制文本
Paint textPaint = new Paint();
String text = mCurPercent + "%";
textPaint.setTextSize(mCenterTextSize);
float textLength = textPaint.measureText(text);
textPaint.setColor(Color.WHITE);
canvas.drawText(text, x - textLength/2, y, textPaint);
}
//外部设置百分比数
public void setPercent(int percent) {
if (percent > 100) {
throw new IllegalArgumentException("percent must less than 100!");
}
setCurPercent(percent);
}
//内部设置百分比 用于动画效果
private void setCurPercent(int percent) {
mCurPercent = percent;
CirclePercentView.this.postInvalidate();
}
}
自定义ViewGroup的方式实现梯形布局
MyViewGroup.java
package com.bwie.tixing;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
public class MyViewGroup extends ViewGroup {
public MyViewGroup(Context context) {
super(context);
}
public MyViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
measureChildren(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
int count = getChildCount();
int startWidth = 0;
int startHeight = 0;
for (int l = 0; l < count; l++) {
View v = getChildAt(l);
v.layout(startWidth, startHeight, startWidth + v.getMeasuredWidth(), startHeight + v.getMeasuredHeight());
startWidth += v.getMeasuredWidth();
startHeight += v.getMeasuredHeight();
}
}
}
实现二维码扫描
自定义zxing二维码扫描页面
CustomViewfinderView.java
package com.bwie.tixing;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Rect;
import android.graphics.Shader;
import android.util.AttributeSet;
import com.google.zxing.ResultPoint;
import com.journeyapps.barcodescanner.ViewfinderView;
import java.util.ArrayList;
import java.util.List;
public class CustomViewfinderView extends ViewfinderView {
public int laserLinePosition=0;
public float[] position=new float[]{0f,0.5f,1f};
public int[] colors=new int[]{0x00ffffff,0xffffffff,0x00ffffff};
public LinearGradient linearGradient ;
public CustomViewfinderView(Context context, AttributeSet attrs) {
super(context, attrs);
}
/**
* 重写draw方法绘制自己的扫描框
* @param canvas
*/
@Override
public void onDraw(Canvas canvas) {
refreshSizes();
if (framingRect == null || previewFramingRect == null) {
return;
}
Rect frame = framingRect;
Rect previewFrame = previewFramingRect;
int width = canvas.getWidth();
int height = canvas.getHeight();
//绘制4个角
paint.setColor(0xFFFFFFFF);//定义画笔的颜色
canvas.drawRect(frame.left, frame.top, frame.left+70, frame.top+10, paint);
canvas.drawRect(frame.left, frame.top, frame.left + 10, frame.top + 70, paint);
canvas.drawRect(frame.right-70, frame.top, frame.right, frame.top+10, paint);
canvas.drawRect(frame.right-10, frame.top, frame.right, frame.top+70, paint);
canvas.drawRect(frame.left, frame.bottom-10, frame.left+70, frame.bottom, paint);
canvas.drawRect(frame.left, frame.bottom-70, frame.left+10, frame.bottom, paint);
canvas.drawRect(frame.right-70, frame.bottom-10, frame.right, frame.bottom, paint);
canvas.drawRect(frame.right-10, frame.bottom-70, frame.right, frame.bottom, paint);
// Draw the exterior (i.e. outside the framing rect) darkened
paint.setColor(resultBitmap != null ? resultColor : maskColor);
canvas.drawRect(0, 0, width, frame.top, paint);
canvas.drawRect(0, frame.top, frame.left, frame.bottom + 1, paint);
canvas.drawRect(frame.right + 1, frame.top, width, frame.bottom + 1, paint);
canvas.drawRect(0, frame.bottom + 1, width, height, paint);
if (resultBitmap != null) {
// Draw the opaque result bitmap over the scanning rectangle
paint.setAlpha(CURRENT_POINT_OPACITY);
canvas.drawBitmap(resultBitmap, null, frame, paint);
} else {
// paint.setAlpha(SCANNER_ALPHA[scannerAlpha]);
// scannerAlpha = (scannerAlpha + 1) % SCANNER_ALPHA.length;
int middle = frame.height() / 2 + frame.top;
laserLinePosition=laserLinePosition+5;
if(laserLinePosition>frame.height())
{
laserLinePosition=0;
}
linearGradient= new LinearGradient(frame.left + 1, frame.top+laserLinePosition , frame.right -1 , frame.top +10+laserLinePosition, colors, position, Shader.TileMode.CLAMP);
// Draw a red "laser scanner" line through the middle to show decoding is active
// paint.setColor(laserColor);
paint.setShader(linearGradient);
//绘制扫描线
canvas.drawRect(frame.left + 1, frame.top+laserLinePosition , frame.right -1 , frame.top +10+laserLinePosition, paint);
paint.setShader(null);
float scaleX = frame.width() / (float) previewFrame.width();
float scaleY = frame.height() / (float) previewFrame.height();
List currentPossible = possibleResultPoints;
List currentLast = lastPossibleResultPoints;
int frameLeft = frame.left;
int frameTop = frame.top;
if (currentPossible.isEmpty()) {
lastPossibleResultPoints = null;
} else {
possibleResultPoints = new ArrayList<>(5);
lastPossibleResultPoints = currentPossible;
paint.setAlpha(CURRENT_POINT_OPACITY);
paint.setColor(resultPointColor);
for (ResultPoint point : currentPossible) {
canvas.drawCircle(frameLeft + (int) (point.getX() * scaleX),
frameTop + (int) (point.getY() * scaleY),
POINT_SIZE, paint);
}
}
if (currentLast != null) {
paint.setAlpha(CURRENT_POINT_OPACITY / 2);
paint.setColor(resultPointColor);
float radius = POINT_SIZE / 2.0f;
for (ResultPoint point : currentLast) {
canvas.drawCircle(frameLeft + (int) (point.getX() * scaleX),
frameTop + (int) (point.getY() * scaleY),
radius, paint);
}
}
postInvalidateDelayed(16,
frame.left ,
frame.top ,
frame.right ,
frame.bottom);
// postInvalidate();
}
}
}
CustomScanAct.java
package com.bwie.tixing;
import android.app.Activity;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.journeyapps.barcodescanner.CaptureManager;
import com.journeyapps.barcodescanner.DecoratedBarcodeView;
public class CustomScanAct extends Activity implements DecoratedBarcodeView.TorchListener { // 实现相关接口
// 添加一个按钮用来控制闪光灯,同时添加两个按钮表示其他功能,先用Toast表示
Button swichLight;
DecoratedBarcodeView mDBV;
private CaptureManager captureManager;
private boolean isLightOn = false;
@Override
protected void onPause() {
super.onPause();
captureManager.onPause();
}
@Override
protected void onResume() {
super.onResume();
captureManager.onResume();
}
@Override
protected void onDestroy() {
super.onDestroy();
captureManager.onDestroy();
}
@Override
public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {
super.onSaveInstanceState(outState, outPersistentState);
captureManager.onSaveInstanceState(outState);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return mDBV.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.act_customscan);
swichLight = (Button) findViewById(R.id.btn_switch);
mDBV= (DecoratedBarcodeView) findViewById(R.id.dbv_custom);
mDBV.setTorchListener(this);
// 如果没有闪光灯功能,就去掉相关按钮
if (!hasFlash()) {
swichLight.setVisibility(View.GONE);
}
//重要代码,初始化捕获
captureManager = new CaptureManager(this, mDBV);
captureManager.initializeFromIntent(getIntent(), savedInstanceState);
captureManager.decode();
//选择闪关灯
swichLight.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (isLightOn) {
mDBV.setTorchOff();
} else {
mDBV.setTorchOn();
}
}
});
}
// torch 手电筒
@Override
public void onTorchOn() {
Toast.makeText(this, "torch on", Toast.LENGTH_LONG).show();
isLightOn = true;
}
@Override
public void onTorchOff() {
Toast.makeText(this, "torch off", Toast.LENGTH_LONG).show();
isLightOn = false;
}
// 判断是否有闪光灯功能
private boolean hasFlash() {
return getApplicationContext().getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
}
}
act_customscan.xml
MainActivity.java
package com.bwie.tixing;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
public class MainActivity extends AppCompatActivity {
private int count = 0;
private CirclePercentView circlePercentView;
private Header header;
private TextView tvResult;
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (count<100){
count+=10;
circlePercentView.setPercent(count);
handler.sendEmptyMessageDelayed(0,1000);
}else {
Intent intent = new Intent(MainActivity.this, CustomScanAct.class);
startActivity(intent);
initEvent();
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
header = (Header) findViewById(R.id.header);
circlePercentView = (CirclePercentView) findViewById(R.id.circleView);
Button button = (Button) findViewById(R.id.button);
tvResult = (TextView) findViewById(R.id.tvResult);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
handler.sendEmptyMessageDelayed(0,1000);
}
});
header.setOnRightClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(MainActivity.this,Main2Activity.class);
startActivity(intent);
}
});
}
private void initEvent() {
//假如你要用的是fragment进行界面的跳转
//IntentIntegrator intentIntegrator = IntentIntegrator.forSupportFragment(ShopFragment.this).setCaptureActivity(CustomScanAct.class);
IntentIntegrator intentIntegrator = new IntentIntegrator(MainActivity.this);
intentIntegrator
.setDesiredBarcodeFormats(IntentIntegrator.ALL_CODE_TYPES)
.setPrompt("将二维码/条码放入框内,即可自动扫描")//写那句提示的话
.setOrientationLocked(false)//扫描方向固定
.setCaptureActivity(CustomScanAct.class) // 设置自定义的activity是CustomActivity
.initiateScan(); // 初始化扫描
}
//获取扫描的结果
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
IntentResult intentResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
if (intentResult != null) {
if (intentResult.getContents() == null) {
} else {
// ScanResult 为获取到的字符串
String ScanResult = intentResult.getContents();
Log.d("zzz", "onActivityResult: "+ScanResult);
tvResult.setText(ScanResult);
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
}
activity_main.xml
Main2Activity.java
package com.bwie.tixing;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
public class Main2Activity extends AppCompatActivity {
private Header header;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
header = (Header) findViewById(R.id.header);
header.setOnLeftClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
});
}
}
activity_main2.xml