[Xamarin.Android] 自定义控件

前言

软件项目开发的过程中,免不了遇到一些无法使用内建控件就能满足的客户需求,例如:时速表、折线图...等等。这时开发人员可以透过自定义控件的方式,为项目量身打造控件,来提供更加贴近用户需求的使用界面。本篇文章介绍在开发Xamarin.Android项目的时候,如何建立自定义控件,为自己留个纪录也希望能帮助到有需要的开发人员。

建立自定义控件

在Xamarin.Android项目中,有许多种方式可以建立自定义控件,本篇文章的范例采用继承View、覆写OnDraw的方式来实作自定义控件。

  1. 首先在Xamarin.Android项目中,加入一个类别:「CountMeter」,并且让CountMeter继承Android.Views.View以及实作对应Android.Views.View的建构子。

    public sealed class CountMeter : View
    {
    // Constructors
    public CountMeter(Context context) : base(context) { } public CountMeter(Context context, IAttributeSet attributeSet) : base(context, attributeSet) { } public CountMeter(Context context, IAttributeSet attributeSet, int defaultStyle) : base(context, attributeSet, defaultStyle) { } // ......
    }
  2. 接着在CountMeter类别中,覆写Android.Views.View的OnMeasure方法,让自定义控件能够正确显示android:layoutwidth、android:layoutheight...等等尺寸设定。

    public sealed class CountMeter : View
    {
    // Fields
    private readonly int _defaultWidth = 400; private readonly int _defaultHeight = 210; // Methods
    protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
    // Base
    base.OnMeasure(widthMeasureSpec, heightMeasureSpec); // Size
    this.SetMeasuredDimension(this.MeasureSize(widthMeasureSpec, _defaultWidth), this.MeasureSize(heightMeasureSpec, _defaultHeight));
    } private int MeasureSize(int measureSpec, int defaultSize)
    {
    // Size
    var specSize = MeasureSpec.GetSize(measureSpec); // Measure
    switch (MeasureSpec.GetMode(measureSpec))
    {
    case MeasureSpecMode.AtMost: return Math.Min(specSize, defaultSize);
    case MeasureSpecMode.Exactly: return specSize;
    default: return defaultSize;
    }
    } // ......
    }

  3. 接着在CountMeter类别中,覆写Android.Views.View的OnDraw方法,使用程序代码的方式来描绘自定义控件呈现在接口上的显示外观。而针对如何描绘控件外观,开发人员可以参考下列资料,学习如何透过Xamarin.Android所提供的绘图类别来使用图形描绘功能:「Xamarin>Android>Other UX>Drawing」。

    public sealed class CountMeter : View
    {
    // Fields
    private readonly int _defaultWidth = 400; private readonly int _defaultHeight = 210; // Methods
    protected override void OnDraw(Canvas canvas)
    {
    // Base
    base.OnDraw(canvas); // Background
    canvas.DrawColor(Color.White); // Paint
    var paint = new Paint();
    paint.Color = Color.Red;
    paint.StrokeWidth = 10; // Size
    var x = 0;
    var y = 0;
    var width = this.Width;
    var height = this.Height - 10;
    var ellipseWidth = width;
    var ellipseHeight = height * 2;
    var scaleLength = 20;
    var spaceLength = 10; // Scale
    paint.Color = Color.Red;
    for (int scaleCount = 0; scaleCount <= 100; scaleCount += 10)
    {
    var scaleAngle = 180f / 100f * scaleCount;
    var scaleOffset = scaleLength;
    var scalePoint1 = this.GetEllipsePoint(x, y, ellipseWidth, ellipseHeight, scaleAngle);
    var scalePoint2 = this.GetEllipsePoint(x + scaleOffset, y + scaleOffset, ellipseWidth - scaleOffset * 2, ellipseHeight - scaleOffset * 2, scaleAngle);
    canvas.DrawLine(scalePoint1.X, scalePoint1.Y, scalePoint2.X, scalePoint2.Y, paint);
    }
    } // ......
    }

  4. 自定义控件除了呈现静态数据之外,更大的功用是用来呈现动态数据,例如:目前时速、目前温度、载货量...等等。要完成呈现动态数据的功能,开发人员必须要在自定义控件中加入对象属性、对象方法来提供外部程序输入动态数据。而控件内部程序,在更新数据之后,就可以依照资料内容来在画面上描绘出对应的显示图形。

    public sealed class CountMeter : View
    {
    // Fields
    private int _count = 0; // Properties
    public int Count
    {
    get
    {
    // Get
    return _count;
    }
    set
    {
    // Set
    _count = value; // Refresh
    this.Invalidate();
    }
    } // Methods
    protected override void OnDraw(Canvas canvas)
    {
    // Base
    base.OnDraw(canvas); // Background
    canvas.DrawColor(Color.White); // Paint
    var paint = new Paint();
    paint.Color = Color.Red;
    paint.StrokeWidth = 10; // Size
    var x = 0;
    var y = 0;
    var width = this.Width;
    var height = this.Height - 10;
    var ellipseWidth = width;
    var ellipseHeight = height * 2;
    var scaleLength = 20;
    var spaceLength = 10; // Needle
    paint.Color = Color.Gold;
    var needleAngle = 180f / 100f * _count;
    var needleOffset = scaleLength + spaceLength;
    var needlePoint1 = this.GetEllipsePoint(x + needleOffset, y + needleOffset, ellipseWidth - needleOffset * 2, ellipseHeight - needleOffset * 2, needleAngle);
    var needlePoint2 = new PointF(width / 2, height);
    canvas.DrawLine(needlePoint1.X, needlePoint1.Y, needlePoint2.X, needlePoint2.Y, paint);
    } // ......
    }

使用自定义控件

完成建立自定义控件的开发步骤后,接下来就是将自定义控件加入到项目之中。在Xamarin.Android项目中,有许多种方式可以将自定义控件,加入到实际处理用户接口Activity类别之中,本篇文章的范例采用直接加入axml档案的方式,在项目中使用自定义控件。

  • Main.axml

    <CustomControlSample.CountMeter
    android:id="@+id/MyCountMeter1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginTop="20dp" />

透过加入axml档案方式将自定义控制向加入项目之后,在实际处理用户接口Activity类别中,就可以跟内建控件一样透过FindViewById方法来取得控件,并且操作控件所提供方法、属性、事件,来提供更加贴近用户需求的使用界面。

  • MainActivity.cs

    [Activity(Label = "CustomControlSample", MainLauncher = true, Icon = "@drawable/icon")]
    public class MainActivity : Activity
    {
    // Fields
    private int _count = 0; // Methods
    protected override void OnCreate(Bundle bundle)
    {
    // Base
    base.OnCreate(bundle); // View
    this.SetContentView(Resource.Layout.Main); // CountMeter
    var countMeter1 = FindViewById<CountMeter>(Resource.Id.MyCountMeter1); // UpButton
    var upButton = FindViewById<Button>(Resource.Id.UpButton);
    upButton.Click += delegate
    {
    _count += 10;
    countMeter1.Count = _count;
    }; // DownButton
    var downButton = FindViewById<Button>(Resource.Id.DownButton);
    downButton.Click += delegate
    {
    _count -= 10;
    countMeter1.Count = _count;
    };
    }
    }

范例下载

范例程序代码:点此下载

[Xamarin.Android] 自定义控件的更多相关文章

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

    自定义控件的基本要求 这篇文章就当是自定义控件入门,看了几篇android关于自定义控件的文章,了解了一下,android自定义控件主要有3种方式: 自绘控件:继承View类,所展示的内容在OnDra ...

  2. [置顶] xamarin android toolbar(踩坑完全入门详解)

    网上关于toolbar的教程有很多,很多新手,在使用toolbar的时候踩坑实在太多了,不好好总结一下,实在浪费.如果你想学习toolbar,你肯定会去去搜索androd toolbar,既然你能看到 ...

  3. Xamarin.Forms 自定义控件(呈现器和效果)

    Xamarin.Forms 使用目标平台的本机控件呈现用户界面,从而让 Xamarin.Forms 应用程序为每个平台保留了相应的界面外观.凭借效果,无需进行自定义呈现器实现,即可自定义每个平台上的本 ...

  4. XAMARIN.ANDROID SIGNALR 实时消息接收发送示例

    SignalR 是一个开发实时 Web 应用的 .NET 类库,使用 SignalR 可以很容易的构建基于 ASP.NET 的实时 Web 应用.SignalR 支持多种服务器和客户端,可以 Host ...

  5. XAMARIN ANDROID 二维码扫描示例

    现在二维码的应用越来越普及,二维码扫描也成为手机应用程序的必备功能了.本文将基于 Xamarin.Android 平台使用 ZXing.Net.Mobile  做一个简单的 Android 条码扫描示 ...

  6. 我正在使用Xamarin的跨平台框架—Xamarin.Android回忆录

    一.缘起 在自己给别家公司做兼职外包的时候,已经明确知道外包的活不是那么好干的,一般在经历了初期热血澎湃的激情后,逐渐冷淡,愤怒,再冷淡,再愤怒…,听上去好像高潮迭起,但令人尴尬的是,这高潮迭起我们都 ...

  7. APP并非一个人在战斗,还有API—Xamarin.Android回忆录

    前言 一般来说,一个客户端APP并非独立存在的,很多时候需要与服务器交互.大体可分为两方面的数据,常规字符串数据和文件数据,因为这两种数据很可能传输方式不一样,比如字符串之类的数据,使用HTTP协议, ...

  8. Xamarin.Android通知详解

    一.发送通知的机制 在日常的app应用中经常需要使用通知,因为服务.广播后台活动如果有事件需要通知用户,则需要通过通知栏显示,而在Xamarin.Android下的通知需要获取Notification ...

  9. Xamarin.Android之SQLiteOpenHelper

    一.前言 在手机中进行网络连接不仅是耗时也是耗电的,而耗电却是致命的.所以我们就需要数据库帮助我们存储离线数据,以便在用户未使用网络的情况下也可以能够使用应用的部分功能,而在需要网络连接的功能上采用提 ...

随机推荐

  1. dissmiss a UISearchBar with an SearchBarController

    If you want do dissmiss a UISearchBar with an SearchBarController, just use this Code: [self.searchD ...

  2. 在CodedUI中使用JQuery选择器

    在CodedUI中使用JQuery选择器http://automationqa.com/forum.php?mod=viewthread&tid=3574&fromuid=29

  3. 跟随标准与Webkit源码探究DOM -- 获取元素之getElementsByClassName

    按照类名获取元素 -- getElementsByClassName(HTML5) 标准 WHATWG 在Document与Element上均有定义,原型 HTMLCollection getElem ...

  4. haproxy 配置

    1.环境: 操作系统:CentOS 6.4 haproxy: 1.3.15.10 [下载:http://download.chinaunix.net/download.php?id=25784& ...

  5. 二十五、【开源】EFW框架Winform前端开发之强大的自定义控件库

    回<[开源]EFW框架系列文章索引>        EFW框架源代码下载V1.2:http://pan.baidu.com/s/1hcnuA EFW框架实例源代码下载:http://pan ...

  6. KIS旗舰版常用数据表

    select * from IC_Web2ERPOrders  --网上订单  FOrderStatus 14--已发货,6--待发货,2--待配货,1--未审核 (审核后变为2,进入待配货)sele ...

  7. SNF开发平台WinForm之九-代码生成器使用说明-SNF快速开发平台3.3-Spring.Net.Framework

    下面就具体的使用说明: 1.获取代码生成器的授权码(根据本机)-----还原数据库-------改config-----代码生成器 改代码生成器Config 2.登录代码生成器 3.查看是否连接成功 ...

  8. 封装系统自带的Debug

    Unity3d的Debug.Log函数用于打印日志,一般项目中都会对其作如下两件事情: (1)希望有一个总的开关来控制整个游戏中日志的打印与否: (2)有的系统会将Log封一层并添加统一的标记,比如S ...

  9. [IR] Tolerant Retrieval & Spelling Correction & Language Model

    Dictionary不一定是个list,它可以是多种形式. 放弃Hash的原因: 通常,tree是比较适合的结构. From: http://www.cnblogs.com/v-July-v/arch ...

  10. Java泛型数组

    文章来自http://blog.csdn.net/orzlzro/article/details/7017435 Java 不支持泛型数组.也就是说, List<String>[] ls ...