xamarin android自定义标题栏(自定义属性、回调事件)

简介: 自定义控件的基本要求这篇文章就当是自定义控件入门,看了几篇android关于自定义控件的文章,了解了一下,android自定义控件主要有3种方式:自绘控件:继承View类,所展示的内容在OnDraw方法中绘制出来组合控件:不需要绘制视图显示的内容,只用系统原生的控件,将几个控件组合起来,(这就是这篇文章要写的自定义标题栏)继承控件:继承原生的控件类,在原生的属性上增加新的功能。

自定义控件的基本要求

这篇文章就当是自定义控件入门,看了几篇android关于自定义控件的文章,了解了一下,android自定义控件主要有3种方式:

  1. 自绘控件:继承View类,所展示的内容在OnDraw方法中绘制出来
  2. 组合控件:不需要绘制视图显示的内容,只用系统原生的控件,将几个控件组合起来,(这就是这篇文章要写的自定义标题栏)
  3. 继承控件:继承原生的控件类,在原生的属性上增加新的功能。

这篇文章所要写的是第二种方式组合控件,来实现自定义标题栏。总结这4点实现一个组合控件的基本要求:
1.在XML布局中可设置组合控件自定义的属性。
2.在代码总可设置属性和方法。
3.UI交互:布局美观,按下,点击等效果。
4.自定义回调事件
先来看看最终实现的效果图:
这里写图片描述

自定义标题栏的实现(使用的是include标签)

自定义标题栏的好处:

  • 提高布局效率
  • 降低布局文件的维护成本
  • 方便使用,容易扩展
  • 降低标题栏和Activity代码逻辑的耦合

我们先来看看布局文件:TitleBar.axml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="56dp">
    <Button
        android:id="@+id/titleBar_left_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:layout_marginLeft="5dp"
        android:text="返回"
        android:drawableLeft="@drawable/icon_white_arrow_left"
        android:background="@android:color/transparent"
        android:textSize="14sp" />
    <TextView
        android:id="@+id/title_bar_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="测试标题"
        android:singleLine="true"
        android:textSize="17sp" />
    <Button
        android:id="@+id/titleBar_right_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginLeft="5dp"
        android:text="提交"
        android:textSize="14sp"
        android:background="@android:color/transparent"/>
</RelativeLayout>

然后在需要的地方通过include标签引用

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <include  layout="@layout/TitleBar" />
</LinearLayout>

在MainActivity中添加单击事件,或者设置属性

    [Activity(Label = "CustomeTitleBar", MainLauncher = true, Icon = "@drawable/icon")]
    public class MainActivity : Activity
    {
        private TextView title_bar_title;
        private Button title_bar_left_btn;
        private Button title_bar_right_btn;
        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);
            SetContentView (Resource.Layout.Main);
            title_bar_left_btn = FindViewById<Button>(Resource.Id.titleBar_left_btn);
            title_bar_right_btn = FindViewById<Button>(Resource.Id.titleBar_right_btn);
            title_bar_title = FindViewById<TextView>(Resource.Id.title_bar_title);
            title_bar_title.Text = "新的标题";
            title_bar_left_btn.Click += (s, e) => {
                Finish();
            };
            title_bar_right_btn.Click += (s, e) =>
            {
                Toast.MakeText(this,"提交",ToastLength.Short).Show();
            };
        }
    }

上面的这种方式与我们自定义控件的要求相差较远,不能自定义属性,不能事件的回调。并不推荐这种方式。如果说一直用include标签的话,这个自定义标题栏好像是写给自己用的似的。

自定义标题栏的实现(自定义属性、回调事件)

(1)定义标题栏的组合布局
我们还是写来自定义一个布局,还是用上面的那个布局,不过最外层的根布局RelativeLayout就不要了,使用merge标签,避免这种嵌套布局

<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
    <Button
        android:id="@+id/titleBar_left_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:layout_marginLeft="5dp"
        android:gravity="left|center_vertical"
        android:background="@android:color/transparent"
        android:textSize="14sp" />
    <TextView
        android:id="@+id/title_bar_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:singleLine="true"
        android:textSize="17sp" />
    <Button
        android:id="@+id/titleBar_right_btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        android:layout_marginRight="5dp"
        android:background="@android:color/transparent"
        android:gravity="right|center_vertical"
        android:textSize="14sp" />
</merge>

(2)自定标题栏相关的自定义属性
在values文件夹新建一个xml文件attrs.xml,关于android中自定义属性format的取值类型有以下这些:

  1. reference:如android:background = “@drawable/图片ID”
  2. color:如android:textColor = “#000000”
  3. boolean:如android:focusable = “false”
  4. dimenion:如android:layout_width = “10dp”
  5. float :如android:fromAlpha = “1.0”
  6. integer:如android:background = “@drawable/图片ID”
  7. string:如android:text=”123”
  8. fraction:百分数如:android:pivotY = “300%”
  9. enum:如android:orientation=”vertical”
<?xml version="1.0" encoding="utf-8" ?>
<resources>
  <declare-styleable name="CustomeTitleBar">
    <attr name="title_background_color" format="color"/>
    <attr name="title_text" format="string"/>
    <attr name="title_text_color" format="color"/>

    <attr name="right_button_text" format="string"/>
    <attr name="right_button_text_color" format="color"/>
    <attr name="right_button_drawable" format="reference|integer"/>
    <attr name="right_button_visible" format="boolean"/>

    <attr name="left_button_text" format="string"/>
    <attr name="left_button_text_color" format="color"/>
    <attr name="left_button_drawable" format="reference|integer"/>
    <attr name="left_button_visible" format="boolean"/>
  </declare-styleable>
</resources>

(3)自定义标题栏代码的实现,根据不同的需求继承不同的原生ViewGroup类,这里继承的是RelativeLayout,也可以LinearLayout、EditText。

    public class MyTitleBar : RelativeLayout
    {
        private TextView title_bar_title;
        private Button title_bar_left_btn;
        private Button title_bar_right_btn;
        public MyTitleBar(Context context, IAttributeSet attrs) : base(context, attrs)
        {
            //base(context, attrs);
            LayoutInflater.From(context).Inflate(Resource.Layout.TitleBar, this, true);
            title_bar_left_btn = FindViewById<Button>(Resource.Id.titleBar_left_btn);
            title_bar_right_btn = FindViewById<Button>(Resource.Id.titleBar_right_btn);
            title_bar_title = FindViewById<TextView>(Resource.Id.title_bar_title);

            try
            {
                TypedArray attributes = context.ObtainStyledAttributes(attrs, Resource.Styleable.CustomeTitleBar);
                if (attributes != null)
                {
                    //titlebar 背景颜色

                    int titleBarBackground = attributes.GetResourceId(Resource.Styleable.CustomeTitleBar_title_background_color,Resource.Color.color_primary);
                    SetBackgroundResource(titleBarBackground);

                    //左边按钮
                    //是否显示
                    bool leftButtonVisible = attributes.GetBoolean(Resource.Styleable.CustomeTitleBar_left_button_visible, true);
                    if (leftButtonVisible)
                    {
                        title_bar_left_btn.Visibility = ViewStates.Visible;
                    }
                    else
                    {
                        title_bar_left_btn.Visibility = ViewStates.Gone;
                    }

                    //设置左边按钮的文字和图标(二者只能选其一)
                    string leftButtonText = attributes.GetString(Resource.Styleable.CustomeTitleBar_left_button_text);
                    if (!string.IsNullOrEmpty(leftButtonText))
                    {
                        title_bar_left_btn.Text = leftButtonText;
                        //设置左边按钮的文字颜色
                        Color leftButtonTextColor = attributes.GetColor(Resource.Styleable.CustomeTitleBar_left_button_text_color, Color.White);
                        title_bar_left_btn.SetTextColor(leftButtonTextColor);
                    }
                    else //(不设置文本,就只能设置图标)
                    {
                        int leftButtonDrawable = attributes.GetResourceId(Resource.Styleable.CustomeTitleBar_left_button_drawable, Resource.Drawable.icon_white_arrow_left);
                        if (leftButtonDrawable != -1)
                        {
                            Drawable drawable = Resources.GetDrawable(leftButtonDrawable);
                            drawable.SetBounds(0, 0, drawable.MinimumWidth,drawable.MinimumHeight);//不设置这句图标显示不出来
                            title_bar_left_btn.SetCompoundDrawables(drawable,null,null,null);
                        }
                    }

                    //右边按钮
                    //是否显示
                    bool rightButtonVisible = attributes.GetBoolean(Resource.Styleable.CustomeTitleBar_right_button_visible, true);
                    if (rightButtonVisible)
                    {
                        title_bar_right_btn.Visibility = ViewStates.Visible;
                    }
                    else
                    {
                        title_bar_right_btn.Visibility = ViewStates.Gone;
                    }

                    //设置左边按钮的文字和图标(二者只能选其一)
                    string rightButtonText = attributes.GetString(Resource.Styleable.CustomeTitleBar_right_button_text);
                    if (!string.IsNullOrEmpty(rightButtonText))
                    {
                        title_bar_right_btn.Text = rightButtonText;
                        //设置左边按钮的文字颜色
                        Color leftButtonTextColor = attributes.GetColor(Resource.Styleable.CustomeTitleBar_right_button_text_color, Color.White);
                        title_bar_right_btn.SetTextColor(leftButtonTextColor);
                    }
                    else //(不设置文本,就只能设置图标)
                    {
                        int rightButtonDrawable = attributes.GetResourceId(Resource.Styleable.CustomeTitleBar_right_button_drawable, Resource.Drawable.icon_white_arrow_left);
                        if (rightButtonDrawable != -1)
                        {
                            Drawable drawable = Resources.GetDrawable(rightButtonDrawable);
                            drawable.SetBounds(0,0,drawable.MinimumHeight,drawable.MinimumHeight);
                            title_bar_right_btn.SetCompoundDrawables(null, null,drawable, null);
                        }
                    }
                    //处理标题
                    string titleText = attributes.GetString(Resource.Styleable.CustomeTitleBar_title_text);
                    if (!string.IsNullOrEmpty(titleText))
                    {
                        title_bar_title.Text = titleText;
                    }
                    Color color = attributes.GetColor(Resource.Styleable.CustomeTitleBar_title_text_color,Color.White);
                    title_bar_title.SetTextColor(color);
                    attributes.Recycle();
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.Write(ex.ToString());
            }
        }

        //设置事件的监听
        public void SetTitleClickListener(IOnClickListener onClickListener)
        {
            if (onClickListener != null)
            {
                title_bar_left_btn.SetOnClickListener(onClickListener);
                title_bar_right_btn.SetOnClickListener(onClickListener);
            }
        }
        //获取左边的Button
        public Button GetTitleBarLeftBtn()
        {
            return title_bar_left_btn;
        }
        //获取右边的Button
        public Button GetTitleRightBtn()
        {
            return title_bar_right_btn;
        }
        //获取标题
        public TextView GetTitleBarTitle()
        {
            return title_bar_title;
        }
    }

(4)使用自定义标题栏,并且自定义属性

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:mview="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
  <CustomeTitleBar.MyTitleBar
    android:id="@+id/myTitleBar"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:layout_marginTop="10dp"
    mview:title_text="测试标题"
    mview:right_button_text=""
    mview:right_button_text_color="@color/color_white"
    mview:right_button_visible="true" 
    mview:left_button_text="返回"/>
  <CustomeTitleBar.MyTitleBar
   android:id="@+id/myTitleBar"
   android:layout_width="match_parent"
   android:layout_height="50dp"
   android:layout_marginTop="10dp"
   mview:title_text="标题2"
   mview:right_button_text="提交"
   mview:right_button_text_color="@color/color_white"
   mview:left_button_text="返回"
   mview:left_button_text_color="@color/color_white"/>
  <CustomeTitleBar.MyTitleBar
 android:id="@+id/myTitleBar"
 android:layout_width="match_parent"
 android:layout_height="50dp"
 android:layout_marginTop="10dp"
 mview:title_text="标题2"
 mview:right_button_visible="false"
 mview:left_button_text="返回"
 mview:left_button_text_color="@color/color_white"/>
  <CustomeTitleBar.MyTitleBar
 android:id="@+id/myTitleBar"
 android:layout_width="match_parent"
 android:layout_height="50dp"
 android:layout_marginTop="10dp"
 mview:title_text="标题2"
 mview:title_background_color="@color/color_red"
 mview:right_button_text_color="@color/color_white"
 mview:left_button_text="返回"
 mview:left_button_text_color="@color/color_red"/>
</LinearLayout>

上面的代码基本实现了与activity逻辑代码的分离、UI界面要求、可配置自定义属性的要求,可最关键的事件的回调还没写,的确这是最核心的地方,这个自定义标题栏的两个按钮的单击事件最终还是要在activity中去调用。
这个就留着下次再写吧。
如果觉得还有点懵逼的话,看看github:https://github.com/MaChuZhang/Xamarin-Android-Custom-View/tree/master/CustomeTitleBar
作者:张林
标题:xamarin android自定义标题栏(自定义属性、回调事件)
原文地址:http://blog.csdn.net/kebi007/article/details/75365917
转载随意注明出处

目录
相关文章
|
2月前
|
Android开发 开发者
安卓应用开发中的自定义视图
【9月更文挑战第37天】在安卓开发的海洋中,自定义视图犹如一座座小岛,等待着勇敢的探索者去发现其独特之处。本文将带领你踏上这段旅程,从浅滩走向深海,逐步揭开自定义视图的神秘面纱。
42 3
|
2月前
|
数据可视化 Android开发 开发者
安卓应用开发中的自定义View组件
【10月更文挑战第5天】在安卓应用开发中,自定义View组件是提升用户交互体验的利器。本篇将深入探讨如何从零开始创建自定义View,包括设计理念、实现步骤以及性能优化技巧,帮助开发者打造流畅且富有创意的用户界面。
93 0
|
1月前
|
搜索推荐 前端开发 Android开发
安卓应用开发中的自定义视图实现
【10月更文挑战第30天】在安卓开发的海洋中,自定义视图是那抹不可或缺的亮色,它为应用界面的个性化和交互体验的提升提供了无限可能。本文将深入探讨如何在安卓平台创建自定义视图,并展示如何通过代码实现这一过程。我们将从基础出发,逐步引导你理解自定义视图的核心概念,然后通过一个实际的代码示例,详细讲解如何将理论应用于实践,最终实现一个美观且具有良好用户体验的自定义控件。无论你是想提高自己的开发技能,还是仅仅出于对安卓开发的兴趣,这篇文章都将为你提供价值。
|
1月前
|
Android开发 开发者 UED
安卓开发中自定义View的实现与性能优化
【10月更文挑战第28天】在安卓开发领域,自定义View是提升应用界面独特性和用户体验的重要手段。本文将深入探讨如何高效地创建和管理自定义View,以及如何通过代码和性能调优来确保流畅的交互体验。我们将一起学习自定义View的生命周期、绘图基础和事件处理,进而探索内存和布局优化技巧,最终实现既美观又高效的安卓界面。
33 5
|
2月前
|
Android开发
Android面试高频知识点(1) 图解Android事件分发机制
Android面试高频知识点(1) 图解Android事件分发机制
|
2月前
|
Android开发
Android面试高频知识点(1) 图解 Android 事件分发机制
Android面试高频知识点(1) 图解 Android 事件分发机制
40 1
|
2月前
|
XML 前端开发 Android开发
Android面试高频知识点(1) 图解Android事件分发机制
Android面试高频知识点(1) 图解Android事件分发机制
Android面试高频知识点(1) 图解Android事件分发机制
|
2月前
|
Android开发
Android 事件分发机制详细解读
Android 事件分发机制详细解读
42 5
|
2月前
|
XML 前端开发 Java
安卓应用开发中的自定义View组件
【10月更文挑战第5天】自定义View是安卓应用开发的一块基石,它为开发者提供了无限的可能。通过掌握其原理和实现方法,可以创造出既美观又实用的用户界面。本文将引导你了解自定义View的创建过程,包括绘制技巧、事件处理以及性能优化等关键步骤。
|
3月前
|
Android开发 开发者
安卓开发中的自定义视图:从入门到精通
【9月更文挑战第19天】在安卓开发的广阔天地中,自定义视图是一块充满魔力的土地。它不仅仅是代码的堆砌,更是艺术与科技的完美结合。通过掌握自定义视图,开发者能够打破常规,创造出独一无二的用户界面。本文将带你走进自定义视图的世界,从基础概念到实战应用,一步步展示如何用代码绘出心中的蓝图。无论你是初学者还是有经验的开发者,这篇文章都将为你打开一扇通往创意和效率的大门。让我们一起探索自定义视图的秘密,将你的应用打造成一件艺术品吧!
67 10