Unity實(shí)現(xiàn)多平臺(tái)二維碼掃描
在unity里做掃二維碼的功能,雖然有插件,但是移動(dòng)端UI一般不能自定義,所以后來自已做了一個(gè),直接在c#層掃描解析,UI上就可以自己發(fā)揮了。
上代碼:
這個(gè)是調(diào)用zxing的腳本。
using UnityEngine;
using System.Collections;
using ZXing;
using ZXing.QrCode;
public class QR {
/// <summary>
/// 解析二維碼
/// </summary>
/// <param name="tex"></param>
/// <returns></returns>
public static string Decode(Texture2D tex) {
return DecodeColData(tex.GetPixels32(), tex.width, tex.height); //通過reader解碼
}
public static string DecodeColData(Color32[] data, int w, int h) {
BarcodeReader reader = new BarcodeReader();
Result result = reader.Decode(data, w, h); //通過reader解碼
//GC.Collect();
if (result == null)
return "";
else {
return result.Text;
}
}
/// <summary>
/// 生成二維碼
/// </summary>
/// <param name="content"></param>
/// <param name="len"></param>
/// <returns></returns>
public static Texture2D GetQRTexture(string content, int len = 256) {
var bw = new BarcodeWriter();
bw.Format = BarcodeFormat.QR_CODE;
bw.Options = new ZXing.Common.EncodingOptions() {
Height = len,
Width = len
};
var cols = bw.Write(content);
Texture2D t = new Texture2D(len, len);
t.SetPixels32(cols);
t.Apply();
return t;
}
}
然后是封裝:
using UnityEngine;
using System.Collections;
using System;
using UnityEngine.UI;
using System.Timers;
/// <summary>
/// 二維碼解析工具
/// 關(guān)鍵函數(shù):
/// public static QRHelper GetInst() --得到單例
/// public event Action<string> OnQRScanned; --掃描回調(diào)
/// public void StartCamera(int index) --啟動(dòng)攝像頭
/// public void StopCamera() --停止攝像頭
/// public void SetToUI(RawImage raw,int UILayoutW,int UILayoutH) --把攝像機(jī)畫面設(shè)置到一個(gè)rawimage上并使它全屏顯示
/// </summary>
public class QRHelper {
public event Action<string> OnQRScanned;
private static QRHelper _inst;
public static QRHelper GetInst() {
if (_inst == null) {
_inst = new QRHelper();
}
return _inst;
}
private int reqW = 640;
private int reqH = 480;
private WebCamTexture webcam;
Timer timer_in, timer_out;
/// <summary>
/// 啟動(dòng)攝像頭
/// </summary>
/// <param name="index">手機(jī)后置為0,前置為1</param>
public void StartCamera(int index) {
StopCamera();
lock (mutex) {
buffer = null;
tbuffer = null;
}
var dev = WebCamTexture.devices;
webcam = new WebCamTexture(dev[index].name);
webcam.requestedWidth = reqW;
webcam.requestedHeight = reqH;
webcam.Play();
stopAnalysis = false;
InitTimer();
timer_in.Start();
timer_out.Start();
}
/// <summary>
/// 停止
/// </summary>
public void StopCamera() {
if (webcam!=null) {
webcam.Stop();
UnityEngine.Object.Destroy(webcam);
Resources.UnloadUnusedAssets();
webcam = null;
stopAnalysis = true;
timer_in.Stop();
timer_out.Start();
timer_in = null;
timer_out = null;
}
}
/// <summary>
/// 把攝像機(jī)畫面設(shè)置到一個(gè)rawimage上并使它全屏顯示
/// </summary>
/// <param name="raw">rawimage</param>
/// <param name="UILayoutW">UI布局時(shí)的寬度</param>
/// <param name="UILayoutH">UI布局時(shí)的高度</param>
public void SetToUI(RawImage raw,int UILayoutW,int UILayoutH){
raw.GetComponent<RectTransform>().sizeDelta = GetWH(UILayoutW,UILayoutH);
int d = -1;
if (webcam.videoVerticallyMirrored) {
d = 1;
}
raw.GetComponent<RectTransform>().localRotation *= Quaternion.AngleAxis(webcam.videoRotationAngle, Vector3.back);
float scaleY = webcam.videoVerticallyMirrored ? -1.0f : 1.0f;
raw.transform.localScale = new Vector3(1, scaleY * 1, 0.0f);
raw.texture = webcam;
raw.color = Color.white;
}
//在考慮可能旋轉(zhuǎn)的情況下計(jì)算UI的寬高
private Vector2 GetWH(int UILayoutW, int UILayoutH) {
int Angle = webcam.videoRotationAngle;
Vector2 init = new Vector2(reqW, reqH);
if ( Angle == 90 || Angle == 270 ) {
var tar = init.ScaleToContain(new Vector2(UILayoutH,UILayoutW));
return tar;
}
else {
var tar = init.ScaleToContain(new Vector2(UILayoutW, UILayoutH));
return tar;
}
}
private void InitTimer() {
timer_in = new Timer(500);
timer_in.AutoReset = true;
timer_in.Elapsed += (a,b) => {
ThreadWrapper.Invoke(WriteDataBuffer);
};
timer_out = new Timer(900);
timer_out.AutoReset = true;
timer_out.Elapsed += (a,b)=>{
Analysis();
};
}
private Color32[] buffer = null;
private Color32[] tbuffer = null;
private object mutex = new object();
private bool stopAnalysis = false;
int dw, dh;
private void WriteDataBuffer() {
lock (mutex) {
if (buffer == null && webcam!=null) {
buffer = webcam.GetPixels32();
dw = webcam.width;
dh = webcam.height;
}
}
}
//解析二維碼
private void Analysis() {
if (!stopAnalysis) {
lock (mutex) {
tbuffer = buffer;
buffer = null;
}
if (tbuffer == null) {
;
}
else {
string str = QR.DecodeColData(tbuffer, dw, dh);
tbuffer = null;
if (!str.IsNullOrEmpty() && OnQRScanned != null) {
ThreadWrapper.Invoke(() => {
if (OnQRScanned!=null)
OnQRScanned(str);
});
}
}
}
tbuffer = null;
}
}
調(diào)用方式如下,用了pureMVC,可能理解起來有點(diǎn)亂,也不能直接用于你的工程,主要看OnRegister和OnRemove里是怎么啟動(dòng)和停止的,以及RegQRCB、RemoveQRCB、OnQRSCcanned如何注冊、移除以及響應(yīng)掃描到二維碼的事件的。在onregister中,由于ios上畫面有鏡象,所以把rawimage的scale的y置為了-1以消除鏡像:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using PureMVC.Patterns;
using PureMVC.Interfaces;
/// <summary>
/// 掃描二維碼界面邏輯
/// </summary>
public class ScanQRMediator : Mediator {
AudioProxy audio;
public QRView TarView {
get {
return base.ViewComponent as QRView;
}
}
public ScanQRMediator()
: base("ScanQRMediator") {
}
string NextView = "";
bool isInitOver = false;
int cameraDelay = 1;
public override void OnRegister() {
base.OnRegister();
if (Application.platform == RuntimePlatform.IPhonePlayer) {
cameraDelay = 5;
}
else {
cameraDelay = 15;
}
audio = AppFacade.Inst.RetrieveProxy<AudioProxy>("AudioProxy");
TarView.BtnBack.onClick.AddListener(BtnEscClick);
QRHelper.GetInst().StartCamera(0);
TarView.WebcamContent.rectTransform.localEulerAngles = Vector3.zero;
CoroutineWrapper.EXEF(cameraDelay, () => {
RegQRCB();
QRHelper.GetInst().SetToUI(TarView.WebcamContent, 1536, 2048);
if (Application.platform == RuntimePlatform.IPhonePlayer) {
TarView.WebcamContent.rectTransform.localScale = new Vector3(1, -1, 0);
}
isInitOver = true;
});
UmengStatistics.PV(TarView);
//暫停背景音樂
audio.SetBGActive(false);
}
public override void OnRemove() {
base.OnRemove();
TarView.BtnBack.onClick.RemoveListener(BtnEscClick);
if (NextView != "UnlockView") {
audio.SetBGActive(true);
}
NextView = "";
isInitOver = false;
}
bool isEsc = false;
void BtnEscClick() {
if (isEsc || !isInitOver) {
return;
}
isEsc = true;
TarView.WebcamContent.texture = null;
TarView.WebcamContent.color = Color.black;
RemoveQRCB();
QRHelper.GetInst().StopCamera();
CoroutineWrapper.EXEF(cameraDelay, () => {
isEsc = false;
if (Application.platform == RuntimePlatform.IPhonePlayer) {
ToUserInfoView();
}
else {
string origin = TarView.LastArg.SGet<string>("origin");
if (origin == "ARView") {
ToARView();
}
else if (origin == "UserInfoView") {
ToUserInfoView();
}
else {
ToARView();
}
}
});
}
void ToARView() {
AppFacade.Inst.RemoveMediator(this.MediatorName);
ViewMgr.GetInst().ShowView(TarView, "ARView", null);
}
void ToUserInfoView() {
AppFacade.Inst.RemoveMediator(this.MediatorName);
ViewMgr.GetInst().ShowView(TarView, "UserInfoView", null);
var v = ViewMgr.GetInst().PeekTop();
var vc = new UserInfoMediator();
vc.ViewComponent = v;
AppFacade.Inst.RegisterMediator(vc);
}
int reg = 0;
void RegQRCB() {
if (reg == 0) {
QRHelper.GetInst().OnQRScanned += OnQRScanned;
reg = 1;
}
}
void RemoveQRCB() {
if (reg == 1) {
QRHelper.GetInst().OnQRScanned -= OnQRScanned;
reg = 0;
}
}
bool isQRJump = false;
void OnQRScanned(string qrStr) {
if (isQRJump) {
return;
}
isQRJump = true;
TarView.WebcamContent.texture = null;
TarView.WebcamContent.color = Color.black;
RemoveQRCB();
QRHelper.GetInst().StopCamera();
NextView = "UnlockView";
CoroutineWrapper.EXEF(cameraDelay, () => {
isQRJump = false;
AppFacade.Inst.RemoveMediator(this.MediatorName);
audio.PlayScanedEffect();
#if YX_DEBUG
Debug.Log("qr is :"+qrStr);
Toast.ShowText(qrStr,1.5f);
#endif
ViewMgr.GetInst().ShowView(TarView, "UnlockView", HashtableEX.Construct("QRCode", qrStr, "origin", TarView.LastArg.SGet<string>("origin")));
var v = ViewMgr.GetInst().PeekTop();
var vc = new UnlockMediator();
vc.ViewComponent = v;
AppFacade.Inst.RegisterMediator(vc);
});
}
}
最后,放上zxing.unity.dll,放在plugins里就可以了。
以上代碼5.1.2測試可用。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
C# 動(dòng)態(tài)調(diào)用WebService的示例
這篇文章主要介紹了C# 動(dòng)態(tài)調(diào)用WebService的示例,幫助大家更好的理解和使用c#,感興趣的朋友可以了解下2020-11-11
C#實(shí)現(xiàn)將json轉(zhuǎn)換為DataTable的方法
這篇文章主要介紹了C#實(shí)現(xiàn)將json轉(zhuǎn)換為DataTable的方法,涉及C#操作json及DataTable的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-03-03
C#?DataSet結(jié)合FlyTreeView實(shí)現(xiàn)顯示樹狀模型數(shù)據(jù)
NineRays.WebControls.FlyTreeView?是?9rays.net?推出的一款功能強(qiáng)大的樹狀模型數(shù)據(jù)顯示控件,本文主要介紹了如何使用其并結(jié)合?DataSet對象進(jìn)行數(shù)據(jù)顯示,感興趣的可以了解下2024-04-04
C#實(shí)現(xiàn)炫酷啟動(dòng)圖-動(dòng)態(tài)進(jìn)度條效果
這篇文章主要介紹了基于C#實(shí)現(xiàn)炫酷啟動(dòng)圖-動(dòng)態(tài)進(jìn)度條 效果,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-05-05
C#實(shí)現(xiàn)子窗體與父窗體通信方法實(shí)例總結(jié)
這篇文章主要介紹了C#實(shí)現(xiàn)子窗體與父窗體通信方法,實(shí)例總結(jié)了常用的四種窗體通信方法,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-09-09
C#實(shí)現(xiàn)向數(shù)組指定索引位置插入新的元素值
這篇文章給大家介紹了利用C#實(shí)現(xiàn)向數(shù)組指定索引位置插入新的元素值,首先需要定義一個(gè)一維數(shù)組,然后修改數(shù)組的長度,從而在其中增加一個(gè)元素,需要的朋友可以參考下2024-02-02
C# Web應(yīng)用調(diào)試開啟外部訪問步驟解析
本文主要介紹了C# Web應(yīng)用調(diào)試開啟外部訪問的實(shí)現(xiàn)過程與方法。具有一定的參考價(jià)值,下面跟著小編一起來看下吧2017-01-01

