《MonoTouch开发实践指南》一3.5 实现自定义UIView

简介: 本节书摘来自华章出版社《MonoTouch开发实践指南》一 书中的第3章,第3.5节,作者:(美)Michael Bluestein,更多章节内容可以访问云栖社区“华章计算机”公众号查看。

3.5 实现自定义UIView

对于SecondView类,首先要将它设置为UIView的子类,同时添加MonoTouch.UIkit命名空间。要绘制视图,可以调用DrawRect方法。为了给视图添加自定义绘图代码,需要重写DrawRect方法。每一个iOS应用程序都有一个主循环。当给DrawRect添加代码时,它在下一次循环时才会调用。不能在程序中直接调用DrawRect方法,它只能由系统在需要的时候调用。当视图第一次加载的时候,会执行绘图代码,所以不需要额外的步骤去调用DrawRect。当视图在初始绘制后,如果要强制重画,可以调用视图的SetNeedDisplay方法,这样视图就可以在事件循环过程中进行重画。
在执行自定义绘图时,可通过视图的图形上下文(graphics context)进行绘制操作。图形上下文是用户绘图用的抽象画布(如屏幕),可在上面使用任何可用的画图工具(如颜色笔、几何形状等)进行画图。代码清单3-6列出了部分SecondView类用于绘制一个正方形的代码。
注意 视图的绘图工作实际通过层技术实现,这将在第6章进行详细讲述。
代码清单3-6 自定义绘图UIView

using System;
using MonoTouch.UIKit;
using MonoTouch.CoreGraphics;
using System.Drawing;

namespace LMT33
{
    public class SecondView : UIView
    {
        CGPath _path;

        public SecondView ()
        {
        }
        public override void Draw (RectangleF rect)
        {
            base.Draw (rect);

            // Get graphics context
            CGContext gctx = UIGraphics.GetCurrentContext ();

            // Set up drawing attributes
            gctx.SetLineWidth (2);
            UIColor.Gray.SetFill ();
            UIColor.Black.SetStroke ();

            // Create geometry
            _path = new CGPath ();

            _path.AddLines (new PointF[] {
                new PointF (110, 100),
                new PointF (210, 100),
                new PointF (210, 200),
                new PointF (110, 200) });

            _path.CloseSubpath ();

            // Add geometry to graphics context and draw it
            gctx.AddPath (_path);
            gctx.DrawPath (CGPathDrawingMode.FillStroke);
        }
    }
}

代码清单3-6中的绘图代码使用了核心图形(Core Graphics)功能,这会在第6章讲述。也可以在UIView实现中直接使用UIKit类。例如,在UIView内使用UILabel显示视图的标题,并通过提供标题(title)属性让控制器设置标题,代码如下:

...
string _title;
UILabel _titleLabel;

public string Title {
    get { return _title; }
    set {
          _title = value;
          _titleLabel.Text = _title;
    }
}

public SecondView ()
{
    _titleLabel = new UILabel ();
}

...

public override void Draw (RectangleF rect)
{
    ...

    _titleLabel.Frame = new RectangleF(5,5,Bounds.Width-10, 25);
    this.AddSubview (_titleLabel);
}

注意 如果不使用UILabel,而是使用核心图形(Core Graphics)功能直接绘制标题的字符串,那么需要在设置标题时调用SetNeedDisplay方法。尽管在初始化时看不到标题,但调用者会改变视图的标题。当更改标题时,调用SetNeedsDisplay方法可以重画视图。当更改标题时,UILabel会在内部调用SetNeedsDisplay方法。
代码中添加了一个包含标题的UILabel作为子视图。视图是按层次结构排列。当添加一个子视图到一个视图时,无论是在视图内部实现(如当前示例的UILabel),还是在外部通过控制器或IB的视图类实现,按照z次序放置子视图都会位于其父视图的上方。如果现在运行应用程序并选择第二个标签,将会看到绘制有标题和正方形的屏幕(如图3-11所示)。
在该示例中,标签使用了Frame属性和父视图的Bounds对象来设置其大小和位置。Frame属性将视图的大小设置为一个矩形,它的位置则由父视图坐标系中的点决定,而边界则由视图自己坐标系的大小和位置决定。通常情况下,Frame属性用来设置视图实例的大小和位置,而不是在一个实际的视图实现中作为边界使用。例如,在该示例中使用UILabel的实例,而不是SecondView的实现。在该示例中,父视图就是secondView。设置UILabel的Frame属性,定义矩形的大小和位置是以父视图的原点为测量点的。iOS坐标系的原点在左上角,往右就是+x,往下就是+y。
注意 在设置视图的Frame属性时,它实际上并不存储在视图内,而是用来从内部获得其他值,如边界。同样,这将在第6章中讲述。
视图要做的另外一件事情就是捕捉事件,如触碰事件。如果检查代码清单3-7中的UIView的类层次结构,就会看到它派生于UIResponder,除此之外,还定义了几个虚函数用来处理触碰事件。为了演示这一点,现在在视图中添加一个简单的命中测试以检测用户是否触碰了正方形。
代码清单3-7 UIResponder使用虚函数处理触碰事件

public class UIResponder : NSObject
{
    ...
    public virtual void TouchesBegan (NSSet touches, UIEvent evt);
    public virtual void TouchesMoved (NSSet touches, UIEvent evt);
    public virtual void TouchesEnded (NSSet touches, UIEvent evt);
    public virtual void TouchesCancelled (NSSet touches, UIEvent evt);
    ...
}

要判断是否触碰了正方形,需要重写UIView子类的TouchesBegan方法,详细代码请看代码清单3-8。为了简单起见,这里只处理单一的触碰。触碰点封装在UITouch类中。要找到视图的实际触碰点,可以调用UITouch对象的LocationInView方法,它将返回视图坐标系内的点。
代码清单3-8 在UIView子类中处理触碰事件

public override void TouchesBegan (NSSet touches, UIEvent evt)
{
    base.TouchesBegan (touches, evt);

    UITouch touch = touches.AnyObject as UITouch;

    if (touch != null) {
        PointF pt = touch.LocationInView (this);

        if (_path.ContainsPoint (pt, true)) {
            Title = "You touched the square";
        } else {
            Title = "You didn't touch the square";
        }
    }
}

之前使用核心图形的路径功能来绘制正方形。在路径中有个ContainsPoint函数可以用来执行命中测试,将UITouch返回的点传递到该函数,它告知点是在路径组成的正方形内还是在正方形外。然后就可以通过标题将结果输出给用户(如图3-12所示)。

screenshot

相关文章
|
存储 安全 Java
一文带你搞懂OAuth2.0
一文带你搞懂OAuth2.0
660 0
|
SQL 分布式计算 Hadoop
大数据行业部署实战1:Hadoop伪分布式部署
大数据行业部署实战1:Hadoop伪分布式部署
1103 0
|
存储 云安全 运维
腾讯云认证云从业者考试系列 腾讯云从业者认证考试内容、范围、 学习资料
本文列举腾讯云从业者认证的考试范围、知识点、分数比例、教程学习地址、一些官方资料文档。
1685 0
腾讯云认证云从业者考试系列 腾讯云从业者认证考试内容、范围、 学习资料
|
5月前
|
Web App开发 人工智能 自然语言处理
深度解析:匠厂OpenClaw如何重构国际货代“单证处理”自动化架构与GEO策略
【背景】国际货代单证处理的技术瓶颈与挑战在跨境贸易与物流货代行业中,单证处理(Document Processing)一直是典型的“高频、复杂、容错率低”的核心环节。根据匠厂在物流行业的调研数据显示,...
|
8月前
|
负载均衡 Java 数据安全/隐私保护
Gateway服务网关
网关是微服务架构的统一入口,核心功能包括请求路由、权限控制和限流。通过Spring Cloud Gateway可实现高效路由转发与过滤器处理,支持全局过滤与跨域解决方案,提升系统安全性和稳定性。(239字)
268 0
|
JSON Shell Linux
抖音ip地址怎么换成外省的?
抖音IP地址跨省修改的技术实现方案 1. 基本原理与前置知识
|
Web App开发 移动开发 前端开发
React 视频播放器样式自定义实战指南
本文详细介绍了如何在React项目中实现视频播放器的样式自定义,涵盖HTML5 `<video>`标签的基础知识、CSS样式定制技巧及常见问题解决方案。针对全屏模式样式失效、移动端触摸事件冲突和进度条样式定制等问题提供了具体代码示例。同时,探讨了视频预加载策略和内存优化方法,并推荐了几款调试工具,帮助开发者提升用户体验和应用性能。
553 6
|
SQL 弹性计算 DataWorks
Flink CDC 在阿里云 DataWorks 数据集成入湖场景的应用实践
Flink CDC 在阿里云 DataWorks 数据集成入湖场景的应用实践
895 6
|
数据安全/隐私保护
基于MATLAB的PEF湍流风场生成器模拟与仿真
本课题基于MATLAB 2022a开发PEF(Primitive Equations Formulation)湍流风场生成器,模拟大气流动和气象现象。PEF模型考虑地球旋转效应、层结稳定性及湍流混合等复杂物理过程,适用于大尺度天气系统研究。核心程序采用高斯分布尾流模型,计算尾流中心到转子中心的距离,并绘制风速分布图。仿真结果展示了不同条件下的风场特征,无水印输出。该模型在天气预报和气候研究中具有重要应用价值。
|
编解码
音视频录制播放原理
音视频录制播放原理
554 1