摘要:[Xamarin.Android] 自訂控制項
[Xamarin.Android] 自訂控制項
前言
軟體專案開發的過程中,免不了遇到一些無法使用內建控制項就能滿足的客戶需求,例如:時速表、折線圖...等等。這時開發人員可以透過自訂控制項的方式,為專案量身打造控制項,來提供更加貼近使用者需求的使用介面。本篇文章介紹在開發Xamarin.Android專案的時候,如何建立自訂控制項,為自己留個紀錄也希望能幫助到有需要的開發人員。
建立自訂控制項
在Xamarin.Android專案中,有許多種方式可以建立自訂控制項,本篇文章的範例採用繼承View、覆寫OnDraw的方式來實作自訂控制項。
-
首先在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) { } // ...... }
-
接著在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; } } // ...... }
-
接著在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); } } // ...... }
-
自訂控制項除了呈現靜態資料之外,更大的功用是用來呈現動態資料,例如:目前時速、目前溫度、載貨量...等等。要完成呈現動態資料的功能,開發人員必須要在自訂控制項中加入物件屬性、物件方法來提供外部程式輸入動態資料。而控制項內部程式,在更新資料之後,就可以依照資料內容來在畫面上描繪出對應的顯示圖形。
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; }; } }
範例下載
範例程式碼:點此下載
能以更簡潔的文字與程式碼,傳達出程式設計背後的精神。
真正做到「以形寫神」的境界。