Xamarin.Forms自定义渲染器如何关联Material搜索栏的Android资源xml
实现方案
1. 共享项目层创建自定义SearchBar控件
先在共享项目中定义继承自SearchBar的自定义控件,方便后续渲染器关联,可按需扩展自定义属性:
namespace YourAppName.Controls { public class MaterialSearchBar : SearchBar { // 示例自定义属性:控制搜索图标显示状态 public static readonly BindableProperty IsSearchIconVisibleProperty = BindableProperty.Create(nameof(IsSearchIconVisible), typeof(bool), typeof(MaterialSearchBar), true); public bool IsSearchIconVisible { get => (bool)GetValue(IsSearchIconVisibleProperty); set => SetValue(IsSearchIconVisibleProperty, value); } } }
2. Android项目添加布局XML资源
把你需要的Material风格搜索栏布局文件放到Android项目的Resources/layout目录下,例如命名为MaterialSearchBar.axml,确认布局文件的生成操作设置为AndroidResource:
<?xml version="1.0" encoding="utf-8"?> <androidx.appcompat.widget.SearchView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/materialSearchView" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/search_bar_rounded_bg" android:iconifiedByDefault="false" android:queryHint="输入搜索内容" android:theme="@style/Theme.MaterialComponents"> </androidx.appcompat.widget.SearchView>
3. 实现Android端自定义渲染器
在OnElementChanged方法中直接加载本地XML布局,替换默认原生控件,同时绑定双向属性和事件:
using Android.Content; using Android.Widget; using Android.Views; using AndroidX.AppCompat.Widget; using Xamarin.Forms; using Xamarin.Forms.Platform.Android; using YourAppName.Controls; using YourAppName.Droid.Renderers; [assembly: ExportRenderer(typeof(MaterialSearchBar), typeof(MaterialSearchBarRenderer))] namespace YourAppName.Droid.Renderers { public class MaterialSearchBarRenderer : ViewRenderer<MaterialSearchBar, Android.Views.View> { private SearchView _nativeSearchView; public MaterialSearchBarRenderer(Context context) : base(context) { } protected override void OnElementChanged(ElementChangedEventArgs<MaterialSearchBar> e) { base.OnElementChanged(e); if (e.OldElement != null || Element == null) return; // 加载自定义XML布局 var inflater = Context.GetSystemService(Context.LayoutInflaterService) as LayoutInflater; var nativeView = inflater.Inflate(Resource.Layout.MaterialSearchBar, null, false); _nativeSearchView = nativeView.FindViewById<SearchView>(Resource.Id.materialSearchView); // 同步初始属性 _nativeSearchView.QueryHint = Element.Placeholder; _nativeSearchView.SetQuery(Element.Text, false); _nativeSearchView.SetIconifiedByDefault(!Element.IsSearchIconVisible); // 绑定双向事件 _nativeSearchView.QueryTextChange += (s, args) => { Element.Text = args.NewText; Element.SearchCommand?.Execute(args.NewText); }; _nativeSearchView.QueryTextSubmit += (s, args) => { Element.SearchCommand?.Execute(args.Query); }; // 将加载的布局设置为原生控件 SetNativeControl(nativeView); } // 同步共享层属性变更到原生控件 protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) { base.OnElementPropertyChanged(sender, e); if (_nativeSearchView == null || Element == null) return; if (e.PropertyName == nameof(Element.Placeholder)) { _nativeSearchView.QueryHint = Element.Placeholder; } else if (e.PropertyName == nameof(Element.Text)) { if (_nativeSearchView.Query != Element.Text) { _nativeSearchView.SetQuery(Element.Text, false); } } else if (e.PropertyName == nameof(Element.IsSearchIconVisible)) { _nativeSearchView.SetIconifiedByDefault(!Element.IsSearchIconVisible); } } } }
4. 页面调用
在XAML页面直接使用自定义控件即可:
<ContentPage xmlns:local="clr-namespace:YourAppName.Controls" x:Class="YourAppName.SearchPage"> <StackLayout Padding="16"> <local:MaterialSearchBar Placeholder="搜索商品" IsSearchIconVisible="True" SearchCommand="{Binding DoSearchCommand}" HorizontalOptions="FillAndExpand"/> </StackLayout> </ContentPage>
- 注意如果用到Material样式需要依赖AndroidX AppCompat包,确保你的Android项目已经安装对应NuGet包并配置了AppCompat主题。
- 如果你需要直接复用第三方组件的逻辑,也可以直接在渲染器中实例化第三方组件的原生控件,无需自行实现属性绑定逻辑。
内容的提问来源于stack exchange,提问作者Dorian Olarescu
相关产品推荐
相关产品推荐

