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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.08 23:51:01