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

Xamarin Forms自定义Snackbar异常:控件值、按钮、消失问题

Xamarin Forms自定义Snackbar异常问题修复

问题现象

首次调用自定义Snackbar时:

  • TextView显示正确文本,但屏幕左上角出现空按钮(推测是Snackbar默认操作按钮)
  • Snackbar超时后自定义TextView不消失
  • 点击TextView时,OnSnackClick中v.Tag为null

二次及后续调用时,除上述问题外:

  • TextView无法设置自定义文本,仅显示XML默认内容

现有代码

依赖服务实现代码

public void MySnackBar(string argument, string title, string message, string action_text, string action, MySnackBarPosition position)
{
    Activity activity = Xamarin.Essentials.Platform.CurrentActivity;
    Android.Views.View view = activity.FindViewById(Android.Resource.Id.Content);
    var snack_view = activity.LayoutInflater.Inflate(Droid.Resource.Layout.my_snackbar, (ViewGroup)view);

    FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
        FrameLayout.LayoutParams.WrapContent,
        FrameLayout.LayoutParams.WrapContent
    );

    snack_view.LayoutParameters = lp;

    var snack_label = snack_view.FindViewById<TextView>(Droid.Resource.Id.my_snack_text);
    snack_label.Text = "You're doing something wrong";
    snack_label.Tag = $"{argument}:{action}";
    snack_label.Click += OnSnackClick;

    var snack = Snackbar.Make(activity, snack_view, "", Snackbar.LengthLong);            
    snack.Show();
}

private void OnSnackClick(object sender, EventArgs args)
{
    var v = (View)sender;

    var tag = v.Tag;
    var data = tag.ToString().Split(':');
    //var argument = data[0];
    //var action = data[1];

    MyApp.App.Instance.HandleSnackbarAction("","");
}

布局文件(my_snackbar.axml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="250dp"
android:layout_gravity="end"
android:orientation="horizontal"
android:layout_height="wrap_content"
android:padding="20dp"
android:background="@android:color/transparent">

<TextView
    android:id = "@+id/my_snack_text"
    android:elevation="8px"
    android:background="#fff"
    android:layout_marginEnd="20dip"
    android:layout_marginTop="20dip"
    android:padding = "20dip"
    android:gravity="center"
    android:text="hello hsdkfhdskjh dsfhsdjkh fjsdkfh sdjkhf dskj hfjkdshfjkdshfjkdsh"
    android:layout_width="0dp"
    android:layout_weight="1"
    android:layout_height="wrap_content"/>

</LinearLayout>

问题原因及修复方案

  1. 左上角空按钮:Snackbar.Make传入空字符串时仍保留默认操作按钮容器,需替换Snackbar默认布局彻底移除占位
  2. 超时不消失:自定义View直接Inflate到Activity根布局,未关联Snackbar生命周期,需将自定义View作为Snackbar内容视图
  3. Tag为空+文本不更新:多次调用时视图缓存导致事件重复绑定、数据未重置,需手动管理视图复用与事件解绑

修改后的代码

依赖服务实现代码

private Snackbar _currentSnackbar; // 保存当前实例,避免重复显示

public void MySnackBar(string argument, string title, string message, string action_text, string action, MySnackBarPosition position)
{
    Activity activity = Xamarin.Essentials.Platform.CurrentActivity;
    Android.Views.View rootView = activity.FindViewById(Android.Resource.Id.Content);

    // 先关闭旧的Snackbar
    _currentSnackbar?.Dismiss();

    // Inflate时不附加到根布局,避免直接加入Activity布局
    var snack_view = activity.LayoutInflater.Inflate(Droid.Resource.Layout.my_snackbar, null);

    var snack_label = snack_view.FindViewById<TextView>(Droid.Resource.Id.my_snack_text);
    // 先解绑旧事件,避免重复绑定
    snack_label.Click -= OnSnackClick;
    
    // 设置自定义文本与Tag
    snack_label.Text = "You're doing something wrong";
    snack_label.Tag = $"{argument}:{action}";
    // 重新绑定点击事件
    snack_label.Click += OnSnackClick;

    // 创建Snackbar并替换内容视图
    _currentSnackbar = Snackbar.Make(rootView, "", Snackbar.LengthLong);
    var snackbarLayout = (Snackbar.SnackbarLayout)_currentSnackbar.View;
    snackbarLayout.RemoveAllViews(); // 清空默认内容
    snackbarLayout.AddView(snack_view, new ViewGroup.LayoutParams(
        ViewGroup.LayoutParams.WrapContent,
        ViewGroup.LayoutParams.WrapContent));
    
    // 控制Snackbar位置(示例:右上角)
    if(position == MySnackBarPosition.End)
    {
        snackbarLayout.SetGravity(GravityFlags.End | GravityFlags.Top, 0, 20);
    }

    _currentSnackbar.Show();
}

private void OnSnackClick(object sender, EventArgs args)
{
    var v = (View)sender;
    if(v.Tag != null)
    {
        var data = v.Tag.ToString().Split(':');
        if(data.Length == 2)
        {
            MyApp.App.Instance.HandleSnackbarAction(data[0], data[1]);
        }
    }
}

布局文件优化(可选)

移除android:layout_gravity="end",由代码统一控制位置:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="250dp"
android:orientation="horizontal"
android:layout_height="wrap_content"
android:padding="20dp"
android:background="@android:color/transparent">

<TextView
    android:id = "@+id/my_snack_text"
    android:elevation="8dp"
    android:background="#fff"
    android:layout_marginEnd="20dp"
    android:layout_marginTop="20dp"
    android:padding = "20dp"
    android:gravity="center"
    android:text="hello hsdkfhdskjh dsfhsdjkh fjsdkfh sdjkhf dskj hfjkdshfjkdshfjkdsh"
    android:layout_width="0dp"
    android:layout_weight="1"
    android:layout_height="wrap_content"/>

</LinearLayout>

关键修复点说明

  • 实例管理:用_currentSnackbar控制显示状态,避免重复叠加
  • 视图关联:将自定义View添加到Snackbar布局内,确保随Snackbar销毁而消失
  • 数据重置:每次调用先解绑旧事件,再设置新文本、Tag和事件,解决缓存导致的异常
  • 默认布局清空:移除Snackbar默认视图,彻底消除空按钮占位

内容的提问来源于stack exchange,提问作者LairdPleng

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 23:05:20