• [置顶] xamarin android自定义标题栏(自定义属性、回调事件)


    自定义控件的基本要求

    这篇文章就当是自定义控件入门,看了几篇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中去调用。
    这个就留着下次再写吧。

  • 相关阅读:
    常用等价无穷小
    高等数学: #n阶线性微分方程 #伯努利方程
    基本积分表
    复杂度计算
    多重链表
    vminsert到vmstorage链路上的配置说明
    vmstorage在全部都是旧metric情况下的写入性能测试
    【解决了一个小问题】alert manager要怎么样才能触发告警到企业微信上?
    vmstorage在新metric占整体1%情况下的写入性能测试
    vmstorage在全部都是新metric情况下的写入性能测试
  • 原文地址:https://www.cnblogs.com/zhangmumu/p/7374763.html
Copyright © 2020-2023  润新知