You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 00:25:26