ZXing扫描Overlay中按钮可点击但不可见的问题排查
ZXing扫描自定义Overlay按钮可见性异常问题
问题描述
使用ZXing插件实现条形码扫描,通过自定义Overlay展示验证信息,按需控制Ok按钮的显示/隐藏(点击按钮时设置标记并隐藏按钮)。当前异常情况:Ok按钮始终不可见,但点击其预期位置时,点击逻辑可正常执行。怀疑是UI线程问题,但尝试过的线程处理方案无效,寻求解决思路。
相关代码
扫描插件初始化代码
MyButton_Scan.Click += async (sender, e) => { var selectedEvent = string.Format("{0}", MyEventsSpinner.GetItemAtPosition(MyEventsSpinner.SelectedItemPosition)); if (selectedEvent.ToUpper() != "SELECT EVENT") { MobileBarcodeScanner.Initialize(Application); scanner = new MobileBarcodeScanner(); scanner.UseCustomOverlay = true; zxingOverlay = LayoutInflater.FromContext(this).Inflate(Resource.Layout.scanner, null); MyScanScreenButton = zxingOverlay.FindViewById<Android.Widget.Button>(Resource.Id.okButton); MyScanScreenButton.Click += btnOk_Click; MyScanScreenButton.Visibility = Android.Views.ViewStates.Invisible; scanner.CustomOverlay = zxingOverlay; var opt = new MobileBarcodeScanningOptions(); opt.DelayBetweenContinuousScans = 5000; //Start scanning scanner.ScanContinuously(this, opt, HandleScanResult); } else { Utils.showMessage("Please select an event from the drop down list"); } };
扫描结果与按钮点击处理代码
void btnOk_Click(object sender, System.EventArgs e) { popUpOpen = false; MyScanScreenButton.Visibility = Android.Views.ViewStates.Invisible; } void HandleScanResult(ZXing.Result result) { if (!popUpOpen) { Boolean ConversionGood = true; TextView MyTextView = zxingOverlay.FindViewById<TextView>(Resource.Id.ticketInfo); Int32 convertedResult = 0; Stream successbeepStream = GetType().Assembly.GetManifestResourceStream("eTicket_Scanner.beep.wav"); Stream failbeepStream = GetType().Assembly.GetManifestResourceStream("eTicket_Scanner.buzzer.wav"); MyTextView.SetBackgroundColor(Color.White); try { convertedResult = Convert.ToInt32(result.Text); } catch (Exception ex) { ConversionGood = false; bool isSuccess = _simpleAudioPlayer.Load(failbeepStream); _simpleAudioPlayer.Play(); popUpOpen = true; MyScanScreenButton.Visibility = Android.Views.ViewStates.Visible; MyTextView.SetBackgroundColor(Color.Red ); MyTextView.Text = "Not a valid ticket for this event.\nError(if applicable): " + ex.Message; } string scanResult = ""; if (ConversionGood) { scanResult = MyEventsService.VerifyScannedCode(MyUser.Username, MyUser.Password, currentEventID, convertedResult); if (scanResult == "Y") { MyTextView.SetBackgroundColor(Color.Green); bool isSuccess = _simpleAudioPlayer.Load(successbeepStream); popUpOpen = true; MyTextView.SetBackgroundColor(Color.Green); MyTextView.Text = MyEventsService.GetTicketInfo(MyUser.Username, MyUser.Password, currentEventID, convertedResult); _simpleAudioPlayer.Play(); MyScanScreenButton.Visibility = Android.Views.ViewStates.Visible; } else { bool isSuccess = _simpleAudioPlayer.Load(failbeepStream); popUpOpen = true; MyTextView.SetBackgroundColor(Color.Red); MyTextView.Text = MyEventsService.GetFailedScanTicketInfo(MyUser.Username, MyUser.Password, currentEventID, convertedResult); _simpleAudioPlayer.Play(); MyScanScreenButton.Visibility = Android.Views.ViewStates.Visible; } } } }
解决思路
强制UI线程执行控件状态更新
ZXing的HandleScanResult回调默认在非UI线程运行,所有控件的可见性、文本、背景色修改都必须在UI线程执行。用RunOnUiThread包裹相关操作:RunOnUiThread(() => { MyScanScreenButton.Visibility = Android.Views.ViewStates.Visible; MyTicketInfoTextView.SetBackgroundColor(Color.Green); MyTicketInfoTextView.Text = "验证通过的信息"; });确保所有UI操作都在主线程执行,避免控件状态不同步。
检查自定义Overlay布局层级
打开Resource.Layout.scanner布局文件,确认:- 按钮的
android:elevation或android:layout_z属性是否低于其他控件,导致被遮挡 - 按钮的宽高、位置设置是否正确,有没有超出父控件范围或被裁剪
- 按钮的默认
visibility是否与代码初始化设置一致,避免布局和代码冲突
- 按钮的
优化控件引用方式
不要在HandleScanResult里重复查找TextView,在初始化Overlay时就获取引用并保存:// 初始化Overlay时 MyTicketInfoTextView = zxingOverlay.FindViewById<TextView>(Resource.Id.ticketInfo);后续直接使用该引用操作控件,避免重复查找可能引发的引用失效问题。
验证按钮引用有效性
若ZXing的CustomOverlay存在重新创建的情况,会导致按钮引用失效。可以在修改可见性前检查引用是否有效,无效则重新获取:if (MyScanScreenButton == null) { MyScanScreenButton = zxingOverlay.FindViewById<Android.Widget.Button>(Resource.Id.okButton); MyScanScreenButton.Click += btnOk_Click; }
内容的提问来源于stack exchange,提问作者Prescott Chartier
相关产品推荐
相关产品推荐

