一、登录页添加
- 1.1 新建空白页面
选中Views目录并右键选择“添加”--> “新建页”。这里以登录页为例,选择新建空白页并修改名称(以下以LoginPage为例)。
新建成功后,会自动生成三个相互对应的文件:布局文件(***.xmal)、页面文件(***.xmal.cs)、模型文件(***ViewModel.cs),如下图所示:
- 1.2 自定义控件
有的时候,平台自带的控件不满足我们的需求,比如输入框指定最大行数,边框样式等,这就需要我们自定义控件了。自定义的控件可以直接在Previewer中预览出效果。以下以自定义输入框添加边框样式为例。
1.2.1 创建自定义控件
首先右键项目标题创建文件夹“Customer”,用于存放所有自定义控件,便于管理。
其次,右键新建的“Customer”文件夹,点击添加类。
选择“类”类型,修改文件名称,并点击“添加”按钮。
完善自定义控件内容。先定义三种类型:盒子、线条、无背景。
public static int Box = 1;//盒子
public static int Liner = 2;//线条
public static int None = 3;//无背景
添加属性字段“BorderType”并定义对应的Property,用户可直接在.xaml布局文件中使用“BorderType”字段来指定当前输入框的属性。
public static readonly BindableProperty BorderTypeProperty =
BindableProperty.Create("BorderType",
typeof(int),
typeof(MyEntry),
Box
);
public int BorderType
{
get { return (int)GetValue(BorderTypeProperty); }
set { SetValue(BorderTypeProperty, value); }
}
1.2.2 创建安卓渲染器
以相同方式在Android目录下新建“CustomerRenderer”文件夹并添加类文件。
用声明,“[assembly: ExportRenderer(typeof(MyEntry), typeof(MyEntryRenderer))]”中MyEntry与MyEntryRenderer分别为自定义的控件名称及当前控件渲染器名称。重写
“OnElementChanged”及“OnElementPropertyChanged”方法。
using System;
using Android.Graphics.Drawables;
using Android.Widget;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
[assembly: ExportRenderer(typeof(MyEntry), typeof(MyEntryRenderer))]
namespace ***.Droid.CustomerRenderer
{
class MyEntryRenderer : EntryRenderer
{
MyEntry sourceView;
EditText targetView;//获得当前控件
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if(e.OldElement == null)
{
sourceView = (MyEntry)e.NewElement;
//targetView = (EditText)this.Control;//转化为安卓输入控件
//targetView.SetTextSize(Android.Util.ComplexUnitType.Sp, sourceView.TextFont.ToScaledPixel());
int typeTemp = sourceView.BorderType;//获得自定义的字段“BorderType”判断边框类型
switch (typeTemp)
{
case 1://盒子
BoxType();
break;
case 2://线条,控件默认为线条类型,这里暂不做处理,有需要可自行定义
break;
case 3://无背景
NoneType();
break;
}
}
}
protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == MyEntry.BorderTypeProperty.PropertyName)
{
int typeTemp = sourceView.BorderType;
switch (typeTemp)
{
case 1://盒子
BoxType();
break;
case 2://线条
//lineType(e);
break;
case 3://无背景
NoneType();
break;
}
}
}
//盒子
private void BoxType() {
var gradientDrawable = new GradientDrawable();
gradientDrawable.SetCornerRadius(3.0f);
gradientDrawable.SetStroke(1, Android.Graphics.Color.Berg(0x00, 0x66, 0x99));
gradientDrawable.SetColor(Android.Graphics.Color.White);
Control.SetBackground(gradientDrawable);
Control.SetPadding(10, Control.PaddingTop, 10, Control.PaddingBottom);
Control.TextAlignment = Android.Views.TextAlignment.Center;
Control.Gravity = Android.Views.GravityFlags.CenterVertical;//文字垂直居中
}
//无背景
private void NoneType()
{
var gradientDrawable = new GradientDrawable();
Control.SetBackground(gradientDrawable);
Control.SetPadding(10, Control.PaddingTop, 10,Control.PaddingBottom);
Control.Gravity = Android.Views.GravityFlags.CenterVertical;
}
}
}
1.2.3 创建IOS渲染器
以相同方式在IOS项目下添加类文件
程序说明:
using System;
using System.ComponentModel;
using CustomRenderer.iOS;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Internals;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(MyEntry), typeof(MyEntryRenderer))]
namespace CustomRenderer.iOS
{
public class MyEntryRenderer : EntryRenderer
{
MyEntry sourceView;
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{
sourceView = (MyEntry)e.NewElement;
int typeTemp = sourceView.BorderType;
switch (typeTemp)
{
case 1://盒子
BoxType();
break;
case 2://线条
LineType();
break;
case 3://无背景
NoneType();
break;
}
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == MyEntry.BorderTypeProperty.PropertyName)
{
int typeTemp = sourceView.BorderType;
switch (typeTemp)
{
case 1://盒子
BoxType();
break;
case 2://线条
LineType();
break;
case 3://无背景
NoneType();
break;
}
}
}
//线条
private void LineType()
{
if (Control != null)
{
// do whatever you want to the UITextField here!
Control.BackgroundColor = UIColor.FromRGB(0xff, 0xff, 0xff);
Control.BorderStyle = UITextBorderStyle.Line;//设置边框类型
Control.Layer.BorderWidth = 1f;
Control.Layer.BorderColor = new CoreGraphics.CGColor(0x00, 0x66, 0x99);
Control.VerticalAlignment = UIControlContentVerticalAlignment.Center;//文字垂直居中
}
}
//无背景
private void NoneType()
{
if (Control != null)
{
// do whatever you want to the UITextField here!
Control.BackgroundColor = UIColor.FromRGBA(0xff, 0xff, 0xff, 0x00);
Control.BorderStyle = UITextBorderStyle.None;
Control.VerticalAlignment = UIControlContentVerticalAlignment.Center;
}
}
//盒子
private void BoxType()
{
if (Control != null)
{
// do whatever you want to the UITextField here!
Control.BackgroundColor = UIColor.FromRGB(0xff, 0xff, 0xff);
Control.BorderStyle = UITextBorderStyle.RoundedRect;
Control.Layer.BorderWidth = 1f;
Control.Layer.CornerRadius = 3;
Control.Layer.BorderColor = new CoreGraphics.CGColor(0x00, 0x66, 0x99);
Control.VerticalAlignment = UIControlContentVerticalAlignment.Center;
}
}
}
}
- 1.3 编辑布局文件
程序说明:
StackLayout(栈布局)相当于安卓中的线性布局,Image控件的Source属性即指定图片资源(如果是本地图片资源需要将图片文件分别放在安卓及IOS的资源目录下)。
GestureRecognizers可添加控件监听,一般用于无点击事件的控件中,其中TapGestureRecognizer监听点击事件,相当于安卓中的click事件。“Tapped=“Forget””即指定这个点击事件为***.cs文件中的Forget命令(后面将介绍)。
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
xmlns:local="clr-namespace:****.Customer"
<!--声明命名空间,与下方自定义控件的所在位置保持一致,“local”字段可随意指定,但需要与下方自定义控件引用的名称保持一致。-->
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="*****.Views.LoginPage"> <StackLayout Orientation ="Vertical" > <StackLayout Orientation="Horizontal" > <Image HeightRequest="90" WidthRequest="90" Source="icon_head" Aspect="AspectFit" HorizontalOptions="CenterAndExpand" Margin="60" /> </StackLayout> <!--账号,引用自定义控件--> <local:MyEntry x:Name="userName" HeightRequest="45" BorderType ="1" Placeholder="请输入账号" PlaceholderColor="#a2a2a2" FontSize="Medium" Margin="20,10,20,10"/> <!--密码--> <local:MyEntry x:Name="password" HeightRequest="45" BorderType ="2" Placeholder="请输入密码" PlaceholderColor="#a2a2a2" FontSize="Medium" Margin="20,0,20,10"/> <StackLayout Orientation="Horizontal" Margin="20,0,20,10"> <!--忘记密码--> <Label Text="忘记密码" FontSize="Small" > <Label.GestureRecognizers > <TapGestureRecognizer Tapped="Forget"/> </Label.GestureRecognizers> </Label> <!--注册--> <Label Text="立即注册" FontSize="Small" HorizontalOptions="EndAndExpand" > <Label.GestureRecognizers > <TapGestureRecognizer Tapped="Register[]"/> </Label.GestureRecognizers> </Label> </StackLayout> <!--登录--> <Button Clicked="Login" HeightRequest="45" Margin="20,0,10,0" Text="登 录" TextColor="White" FontSize="Medium" BackgroundColor="#006699"/> </StackLayout> </ContentPage>
- 1.4 添加监听事件
处理事件可在***.xaml.cs文件中执行,也可在***.cs文件中执行,推荐使用方式一。注意方式一的格式必需为以下示例中的格式,命令的名称与布局文件中的调用名称一致即可。
方式一(以Login(登录)为例):
private DelegateCommand<object> _Login;
public DelegateCommand<object> Login
{
get
{
return _Login = _Login ?? new DelegateCommand<object>(async (x) =>
{
//登录操作具体执行方法
});
}
}
方式二:
页面文件即为布局文件下自动生成的.xmal.cs文件。
using System;
using Xamarin.Forms;
namespace ***.Views
{
public partial class LoginPage : ContentPage
{
public LoginPage()
{
InitializeComponent();
}
//忘记密码
private void Forget(object sender, EventArgs args)
{
//忘记密码具体执行方法
}
//立即注册
private void Register(object sender, EventArgs args)
{
//立即注册具体执行方法
}
//登录
private void Login(object sender, EventArgs args) {
String name = userName.Text;
String pwd = password.Text;
//登录具体执行方法
}
}
}
- 1.5 运行效果