iOS之Drawing<2>

本文介绍了在iOS中使用图形上下文进行绘图的基本方法,包括通过UIKit和CoreGraphics进行绘图的不同方式,并提供了具体的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

图形上下文(Graphics Contexts)

我们可以使用代码来创建图画,图形上下文是可以绘画的地方。这里推荐两种获取图形上下文的方法:

  • 创建一个图片上下文(image context)
    函数UIGraphicsBeginImageContextWithOptions用来创建一个图形上下文,接着你可以在上面绘制来产生图片,然后通过UIGraphicsGetImageFromCurrentImageContext来将上下文转变为UIImage,最后使用UIGraphicsEndImageContext关闭上下文。
  • Cocoa交给你一个图形上下文(graphics context)
    子类化UIView,然后实现drawRect:。在drawRect:被调用时,Cocoa已经创建了一个图形上下文,你在上面绘制什么,UIView就展示什么。

进一步,注意当前图形上下文:

  • UIGraphicsBeginImageContextWithOptions函数不仅仅创建一个图片上下文,它也会让刚创建的上下文成为当前的图形上下文。
  • drawRect:被调用的时候,UIView的绘图上下文已经是当前的图形上下文了。
  • 带有context:参数的回调并没让任何一个上下文成为当前的图形上下文。这个参数是图形上下文的引用,你将会在上面绘制图形,所以你要确保让它成为当前的上下文。

有两种工具可以绘制图形:

  • UIKit
    许多Cocoa类都知道如何绘制自己,包括UIImage,NSString(绘制文本),UIBezierPath(绘制形状),和UIColor。一些类提供便利方法,但是能力有限;其它类是相当强大的。

如果是通过context:参数传入图形上下文的话,你可以通过UIGraphicsPushContext方法来使传进来的上下文成为当前上下文,确保稍后调用UIGraphicsPopContext恢复到以前状态。
- Core Graphics
这是强大的绘图API。Core Graphics通常指的是Quartz或者Quartz 2D,是位于所有iOS绘图之下的绘图系统,UIKit也是建立在其之上,所以,它是底层的,由C函数组成的。

使用Core Graphics,你必须要声明一个绘图上下文(CGContext)来在上面绘图。如果是通过context:参数传入的图形上下文的话,那个就是你要在上面绘图的上下文;但是在UIGraphicsBeginImageContextWithOptions或者drawRect:情况下,你没有对上下文的引用,为了使用Core Graphics,你必须要得到引用。因为你想要绘制的就是当前上下文,所以可以调用UIGraphicsGetCurrentContext获得引用。

1.实现UIView子类的drawRect:方法,使用UIKit在当前上下文中进行绘图:

override func drawRect(rect: CGRect) {
        let p=UIBezierPath(ovalInRect: CGRectMake(0, 0, 100, 100))
        UIColor.blueColor().setFill()
        p.fill()
    }

2.使用Core Graphics实现相同的事情:

override func drawRect(rect: CGRect) {
        let con=UIGraphicsGetCurrentContext()!
        CGContextAddEllipseInRect(con, CGRectMake(0, 0, 100, 100))
        CGContextSetFillColorWithColor(con, UIColor.blueColor().CGColor)
        CGContextFillPath(con)
    }

3.实现UIView子类的drawLayer:inContext:方法,这种情况下,有一个上下文的引用,但它不是当前上下文,所以必须使它成为当前上下文来使用UIKit:

    override func drawLayer(layer: CALayer, inContext ctx: CGContext) {  
       UIGraphicsPushContext(ctx)
        let p=UIBezierPath(ovalInRect: CGRectMake(0, 0, 100, 100))
        UIColor.redColor().setFill()
        p.fill()
        UIGraphicsPopContext()
    }

4.使用Core Graphics实现上面的效果:

```
    override func drawLayer(layer: CALayer, inContext ctx: CGContext) {  
       CGContextAddEllipseInRect(ctx, CGRectMake(0, 0, 100, 100))
        CGContextSetFillColorWithColor(ctx, UIColor.blueColor().CGColor)
        CGContextFillPath(ctx)
    }

5.最后,来制作一个UIImage,我们可以在任何时候完成这个任务。产生的UIImage可以用在任何地方:

使用UIKit:

override func viewDidLoad() {
        super.viewDidLoad()
        let draw=UIImageView()
        draw.frame=CGRectMake(100, 100, 100, 100)

        UIGraphicsBeginImageContextWithOptions(CGSize(width: 100, height: 100), false, 1.0)
        let p=UIBezierPath(ovalInRect: CGRectMake(0, 0, 100, 100))
        UIColor.blueColor().setFill()
        p.fill()

        let im:UIImage=UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        draw.image=im

        self.view.addSubview(draw)
    }

使用Core Graphics:

verride func viewDidLoad() {
        super.viewDidLoad()

        let draw=UIImageView()
        draw.frame=CGRectMake(100, 100, 100, 100)

        UIGraphicsBeginImageContextWithOptions(CGSize(width: 100, height: 100), false, 1.0)
        let con=UIGraphicsGetCurrentContext()
        CGContextAddEllipseInRect(con, CGRectMake(0, 0, 100, 100))
        CGContextSetFillColorWithColor(con, UIColor.blueColor().CGColor)
        CGContextFillPath(con)

        let im:UIImage=UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()

        draw.image=im

        self.view.addSubview(draw)
    }
using AIToy.Common; using System.Collections.ObjectModel; using System.ComponentModel; namespace AIToy.Pages.My; public partial class UpdateResources : BasePage { public ObservableCollection<MenuItem> MenuItems { get; set; } = new(); public UpdateResources() { InitializeComponent(); LoadMenuItems(); BindingContext = this; } private async void LoadMenuItems() { await Task.Run(() => { var data = GenerateMenuItems(); Dispatcher.Dispatch(() => { MenuItems.Clear(); foreach (var item in data) MenuItems.Add(item); }); }); } private List<MenuItem> GenerateMenuItems() { var female = new[] { "female01", "female02", "female03", "female04", "female05", "female06" }; var male = new[] { "male01", "male02", "male03", "male04", "male05", "male06" }; var result = new List<MenuItem>(12); for (int i = 0; i < 12; i++) { result.Add(new MenuItem { Name = i > 5 ? female[i - 6] : male[i], SubItems = new ObservableCollection<SubItem> { new() { Name = "视频" }, new() { Name = "音频" } } }); } return result; } public class MenuItem : INotifyPropertyChanged { public string Name { get; set; } public ObservableCollection<SubItem> SubItems { get; set; } = new(); private bool _isChecked; public bool IsChecked { get => _isChecked; set { _isChecked = value; foreach (var subItem in SubItems) { subItem.IsChecked = value; } OnPropertyChanged(); } } private bool _isExpanded = true; public bool IsExpanded { get => _isExpanded; set { _isExpanded = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } public class SubItem : INotifyPropertyChanged { public string Name { get; set; } private bool _isChecked; public bool IsChecked { get => _isChecked; set { _isChecked = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }<?xml version="1.0" encoding="utf-8" ?> <common:BasePage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="AIToy.Pages.My.UpdateResources" xmlns:common="clr-namespace:AIToy.Common" xmlns:m="clr-namespace:AIToy.Manager" xmlns:controls="clr-namespace:AIToy.Controls" Title="UpdateResources" BackgroundColor="#0D0C0D"> <ScrollView> <VerticalStackLayout Padding="20" Spacing="15"> <Label Text="资源管理器" FontSize="24" FontAttributes="Bold" HorizontalOptions="Center"/> <Border Stroke="#512BD4" StrokeThickness="2" StrokeShape="RoundRectangle 10" Padding="10"> <VerticalStackLayout Spacing="10"> <CollectionView ItemsSource="{Binding MenuItems}"> <CollectionView.ItemTemplate> <DataTemplate> <VerticalStackLayout Spacing="5"> <Grid> <CheckBox IsChecked="{Binding IsChecked}" VerticalOptions="Center"/> <Label Text="{Binding Name}" FontSize="18" FontAttributes="Bold" Margin="30,0,0,0"/> </Grid> <BoxView HeightRequest="1" Color="LightGray" Margin="30,0,0,0"/> <StackLayout Margin="30,0,0,0" Spacing="5" IsVisible="{Binding IsExpanded}"> <CollectionView ItemsSource="{Binding SubItems}"> <CollectionView.ItemTemplate> <DataTemplate> <Grid> <CheckBox IsChecked="{Binding IsChecked}" VerticalOptions="Center"/> <Label Text="{Binding Name}" Margin="30,0,0,0"/> </Grid> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </StackLayout> </VerticalStackLayout> </DataTemplate> </CollectionView.ItemTemplate> </CollectionView> </VerticalStackLayout> </Border> </VerticalStackLayout> </ScrollView> </common:BasePage> 这是.net maui代码,加载需要6-7秒,如何优化让他秒开,前端写死也行
08-07
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值