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>
问题原因及修复方案
- 左上角空按钮:
Snackbar.Make传入空字符串时仍保留默认操作按钮容器,需替换Snackbar默认布局彻底移除占位 - 超时不消失:自定义View直接Inflate到Activity根布局,未关联Snackbar生命周期,需将自定义View作为Snackbar内容视图
- 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
相关产品推荐
相关产品推荐

