iOS utility classes for asynchronous rendering and display.

Overview

YYAsyncLayer

License MIT  Carthage compatible  CocoaPods  CocoaPods  Support  Build Status

iOS utility classes for asynchronous rendering and display.
(It was used by YYText)

Simple Usage

@interface YYLabel : UIView
@property NSString *text;
@property UIFont *font;
@end

@implementation YYLabel

- (void)setText:(NSString *)text {
    _text = text.copy;
    [[YYTransaction transactionWithTarget:self selector:@selector(contentsNeedUpdated)] commit];
}

- (void)setFont:(UIFont *)font {
    _font = font;
    [[YYTransaction transactionWithTarget:self selector:@selector(contentsNeedUpdated)] commit];
}

- (void)layoutSubviews {
    [super layoutSubviews];
    [[YYTransaction transactionWithTarget:self selector:@selector(contentsNeedUpdated)] commit];
}

- (void)contentsNeedUpdated {
    // do update
    [self.layer setNeedsDisplay];
}

#pragma mark - YYAsyncLayer

+ (Class)layerClass {
    return YYAsyncLayer.class;
}

- (YYAsyncLayerDisplayTask *)newAsyncDisplayTask {
    
    // capture current state to display task
    NSString *text = _text;
    UIFont *font = _font;
    
    YYAsyncLayerDisplayTask *task = [YYAsyncLayerDisplayTask new];
    task.willDisplay = ^(CALayer *layer) {
        //...
    };
    
    task.display = ^(CGContextRef context, CGSize size, BOOL(^isCancelled)(void)) {
        if (isCancelled()) return;
        NSArray *lines = CreateCTLines(text, font, size.width);
        if (isCancelled()) return;
        
        for (int i = 0; i < lines.count; i++) {
            CTLineRef line = line[i];
            CGContextSetTextPosition(context, 0, i * font.pointSize * 1.5);
            CTLineDraw(line, context);
            if (isCancelled()) return;
        }
    };
    
    task.didDisplay = ^(CALayer *layer, BOOL finished) {
        if (finished) {
            // finished
        } else {
            // cancelled
        }
    };
    
    return task;
}
@end

Installation

CocoaPods

  1. Add pod 'YYAsyncLayer' to your Podfile.
  2. Run pod install or pod update.
  3. Import <YYAsyncLayer/YYAsyncLayer.h>.

Carthage

  1. Add github "ibireme/YYAsyncLayer" to your Cartfile.
  2. Run carthage update --platform ios and add the framework to your project.
  3. Import <YYAsyncLayer/YYAsyncLayer.h>.

Manually

  1. Download all the files in the YYAsyncLayer subdirectory.
  2. Add the source files to your Xcode project.
  3. Import YYAsyncLayer.h.

Documentation

Full API documentation is available on CocoaDocs.
You can also install documentation locally using appledoc.

Requirements

This library requires iOS 6.0+ and Xcode 8.0+.

License

YYAsyncLayer is provided under the MIT license. See LICENSE file for details.



中文介绍

iOS 异步绘制与显示的工具类。
(该工具是从 YYText 提取出来的独立组件)

简单用法

@interface YYLabel : UIView
@property NSString *text;
@property UIFont *font;
@end

@implementation YYLabel

- (void)setText:(NSString *)text {
    _text = text.copy;
    [[YYTransaction transactionWithTarget:self selector:@selector(contentsNeedUpdated)] commit];
}

- (void)setFont:(UIFont *)font {
    _font = font;
    [[YYTransaction transactionWithTarget:self selector:@selector(contentsNeedUpdated)] commit];
}

- (void)layoutSubviews {
    [super layoutSubviews];
    [[YYTransaction transactionWithTarget:self selector:@selector(contentsNeedUpdated)] commit];
}

- (void)contentsNeedUpdated {
    // do update
    [self.layer setNeedsDisplay];
}

#pragma mark - YYAsyncLayer

+ (Class)layerClass {
    return YYAsyncLayer.class;
}

- (YYAsyncLayerDisplayTask *)newAsyncDisplayTask {
    
    // capture current state to display task
    NSString *text = _text;
    UIFont *font = _font;
    
    YYAsyncLayerDisplayTask *task = [YYAsyncLayerDisplayTask new];
    task.willDisplay = ^(CALayer *layer) {
        //...
    };
    
    task.display = ^(CGContextRef context, CGSize size, BOOL(^isCancelled)(void)) {
        if (isCancelled()) return;
        NSArray *lines = CreateCTLines(text, font, size.width);
        if (isCancelled()) return;
        
        for (int i = 0; i < lines.count; i++) {
            CTLineRef line = line[i];
            CGContextSetTextPosition(context, 0, i * font.pointSize * 1.5);
            CTLineDraw(line, context);
            if (isCancelled()) return;
        }
    };
    
    task.didDisplay = ^(CALayer *layer, BOOL finished) {
        if (finished) {
            // finished
        } else {
            // cancelled
        }
    };
    
    return task;
}
@end

安装

CocoaPods

  1. 在 Podfile 中添加 pod 'YYAsyncLayer'
  2. 执行 pod installpod update
  3. 导入 <YYAsyncLayer/YYAsyncLayer.h>。

Carthage

  1. 在 Cartfile 中添加 github "ibireme/YYAsyncLayer"
  2. 执行 carthage update --platform ios 并将生成的 framework 添加到你的工程。
  3. 导入 <YYAsyncLayer/YYAsyncLayer.h>。

手动安装

  1. 下载 YYAsyncLayer 文件夹内的所有内容。
  2. 将 YYAsyncLayer 内的源文件添加(拖放)到你的工程。
  3. 导入 YYAsyncLayer.h

文档

你可以在 CocoaDocs 查看在线 API 文档,也可以用 appledoc 本地生成文档。

系统要求

该项目最低支持 iOS 6.0Xcode 8.0

许可证

YYAsyncLayer 使用 MIT 许可证,详情见 LICENSE 文件。

相关文章

iOS 保持界面流畅的技巧

Comments
  • 使用 YYAsyncLayer 异步绘制图片内存占用高的问题

    使用 YYAsyncLayer 异步绘制图片内存占用高的问题

    YY 大神你好,我尝试着对你的微博 List 进行了优化,cell 上的一些细小的视图(比如人名、日期、来源等)这些控件使用了 YYAsyncLayer 异步绘制成了 layercontents,减少了视图层级,在流畅性上获得了很好的提升。虽然我用 Xcode 的 Debug Session 查看发现即使的暴力滑动的情况下内存依然控制在 20M 左右,但是使用 Instruments 的 Allocations 一调试,发现 UIGraphicsBeginImageContextWithOptionsUIGraphicsGetImageFromCurrentImageContext 两个方法内存占用竟然有几百兆。

    2016-03-08 4 30 26

    我尝试在 SO 上寻找解决方案,试着给绘制代码加了 autoreleasepool

        task.display = { [weak self] (context, size, isCancelled) in
          if isCancelled() {
            return
          }
          autoreleasepool({ () -> () in
            self?.draw(context,size: size) // 这里是具体的绘制代码
          })
        }
    

    draw 的具体代码类似如下:

      private func draw(context: CGContextRef, size: CGSize) {
        //background color
        kWeiboStatusViewBackgroundColor.set()
        CGContextFillRect(context, CGRect(x: 0, y: 0, width: size.width, height: size.height))
    
        //timeline
        kWeiboStatusViewTimelineColor.set()
        CGContextFillRect(context, CGRectMake(kWeiboStatusCellLeftMargin+kWeiboStatusCellAvatarSize/2, 0, 1, height))
    
        //...
        retweetIcon.drawInRect(iconRect)
        //...
        retweetString.drawAtPoint(CGPoint(x: iconRect.origin.x + 3 + iconRect.width, y: retweet ? (iconRect.origin.y - 4) : (iconRect.origin.y - 3)))
    
      }
    

    可是无果。想请教您指点,感谢。

    opened by KittenYang 10
  • 请教一个关于计数器 YYSentinel 的问题

    请教一个关于计数器 YYSentinel 的问题

    在看源码的过程中,对及时退出绘制任务的实现方案的理解有点拿不准,特来求证一下。 首先我一直很好奇,什么时候会 value != sentinel.value;,换言之,得滑到多快,才能让 value != sentinel.value;

    源码里面,只要 cell 出现在屏幕上,都会触发一次 setNeedsDisplay:

    - (void)setNeedsDisplay {
        [self _cancelAsyncDisplay]; //1
        [super setNeedsDisplay]; //2
    }
    

    这里面,//1 处会让计数器加1,我们可以把它认为是标准值;//2 里面会做一次取值:

    YYSentinel *sentinel = _sentinel;
    int32_t value = sentinel.value; //3
    

    而由于 1、2 操作都是在主线程做的,所以会按先后顺序来。

    所以,我的结论就是,源码中只是利用了函数调用的时间差,也就是说,只有当滑动的速度比 1、3 两处函数调用的时间差还要快,才会触发 isCancelled 判断条件。

    以上是我的理解,不知道是否正确,特来求证,望指教。

    PS:另外,还有一点想法,源码中的 isCancelled 属于主动式获取,必须去调用才知道是否不一致了,不太精准,容易漏掉。有没有可能实现被动式通知,就是一旦触发 value != sentinel.value; 就通知线程退出呢?

    opened by KittenYang 6
  • size.width < 1 || size.height < 1还是size.width < 1 && size.height < 1 ?

    size.width < 1 || size.height < 1还是size.width < 1 && size.height < 1 ?

    if (size.width < 1 || size.height < 1) { CGImageRef image = (__bridge_retained CGImageRef)(self.contents); self.contents = nil; if (image) { dispatch_async(YYAsyncLayerGetReleaseQueue(), ^{ CFRelease(image); }); } if (task.didDisplay) task.didDisplay(self, YES); CGColorRelease(backgroundColor); return; } 这段代码的意思是?

    opened by BeatsKitano 1
  • [self setNeedsDisplay] 无效

    [self setNeedsDisplay] 无效

    - (void)contentsNeedUpdated {
        // do update
        [self setNeedsDisplay];
    }
    

    此处地方self setNeedsDisplay无效。我也纳闷,因为 view 的 setNeedsDisplay 会自动转发到 layer 的 setNeedsDisplay,而 layerClass 已经指定了 YYAsyncLayer ,按理应该能转发到。请教原因。另外,改成[self.layer setNeedsDisplay] 解决。

    opened by KittenYang 1
  • It is better to use [UIScreen -nativeScale] instead of [UIScreen -scale].

    It is better to use [UIScreen -nativeScale] instead of [UIScreen -scale].

    In YYAsyncLayer's -init method:

    scale = [UIScreen mainScreen].scale;

    is better to be changed into:

    scale = [UIScreen mainScreen].nativeScale;

    in post-iPhone-6-Plus age.

    opened by WeZZard 1
  • NSOperationQueue 和 NSOperation 方式

    NSOperationQueue 和 NSOperation 方式

    YY 大神你好,请教一个问题:

    你用多个串行队列来实现并发、控制线程数量,避免GCD在并行队列上执行耗时任务时开辟过多线程、消耗系统资源。如果通过NSOperationQueue 和 NSOperation的方式,控制maxConcurrentOperationCount 为YYAsyncLayerGetDisplayQueue中的queueCount,能够实现同样的效果嘛?

    opened by Beyond-Chao 2
  • YYTransaction中 Runloop 为什么只在主线程中使用 ?

    YYTransaction中 Runloop 为什么只在主线程中使用 ?

    _ASAsyncTransactionGroup.m中 CFRunLoopRef runLoop = CFRunLoopGetCurrent(); YYTransaction中CFRunLoopRef runloop = CFRunLoopGetMain(); 只会在主线程中回调,可不可以改成CFRunLoopGetCurrent()?

    opened by MaydayFive 1
  • RunLoop的作用

    RunLoop的作用

    大神你好,我看AsyncDisplayKit的代码的时候,它是直接在display时将displayBlock加入到后台线程执行,然后在RunLoop触发Observer回调时提交block的执行结果,然后调用completeBlock,但是我看YYAsyncLayer好像是在RunLoop触发Observer回调时才在display里面将displayBlock添加到后台线程执行,然后执行完后直接向主线程提交结果,好像跟ASDK不太一样,所以这里感觉有点糊涂,到底为什么要在RunLoop上添加Observer呢,为什么不直接将绘制任务添加到后台线程然后将结果返回给主线程呢?

    opened by sugite 0
Releases(1.0)
Owner
null
A super easy way to check if the installed app has an update available. It is built with simplicity and customisability in mind and comes with pre-written tests.

UpdateAvailableKit This is UpdateAvailableKit: a super easy way to check if the installed app has an update available. It is built with simplicity and

Swapnanil Dhol 22 Jan 5, 2023
Drawing and Geometry made easy on iOS - now in Swift 3.0

InkKit Swift Support Swift 4.0 InkKit is Swift 4.0 by default, so to use that just include InkKit in your podfile: pod 'InkKit' Swift 3.2 In order to

Shaps 373 Dec 27, 2022
An iOS framework for easily adding drawings and text to images.

jot is an easy way to add touch-controlled drawings and text to images in your iOS app. What's jot for? Annotating Images jot is the easiest way to ad

IFTTT 1.8k Oct 28, 2022
The application is develop in Objective IOS. kids can draw whatever they want and also kids can save the drawing as well as undo erase the drawing.

IOSObjC_KidsBoard The application is develop in Objective IOS. kids can draw whatever they want and also kids can save the drawing as well as undo era

Haresh 0 Oct 28, 2021
A lightweight XMLParser for assembling and parsing XML values written for iOS 8+ in Swift 2.

Overview Description Requirements Installation Usage Author License Description XMLParser lets you convert a pure Swift dictionary into XML string and

Eugene Mozharovsky 75 Feb 2, 2022
A simple, performant, and lightweight SVG parser

Key Features Parsing performance that meets or beats other popular SVG Frameworks A simple architecture, optimized for extension, flexibility and deve

Michael Choe 1.8k Dec 29, 2022
NXDrawKit is a simple and easy but useful drawing kit for iPhone

⚠️ To use with Swift 5.0 please ensure you are using >= 0.8.0 ⚠️ ⚠️ To use with Swift 4.2 please ensure you are using >= 0.7.1 ⚠️ ⚠️ To use with Swift

Nicejinux 1.3k Dec 31, 2022
Create gradients and blur gradients without a single line of code

EZYGradientView is a different and unique take on creating gradients and gradients with blur on the iOS platform. The default CAGradientLayer implemen

Shashank Pali 380 Dec 6, 2022
Powerful and easy-to-use vector graphics Swift library with SVG support

Macaw Powerful and easy-to-use vector graphics Swift library with SVG support We are a development agency building phenomenal apps. What is Macaw? Mac

Exyte 5.9k Jan 2, 2023
When you scan the clothing tag, a 3D character appears and informs you of the clothing information.

1. Introduction When you scan the clothing tag, a 3D character appears and tells you the information on the clothes. You can select necessary informat

kimniki 0 Dec 23, 2021
SVG parser and renderer written in SwiftUI

SVGView SVG parser written in SwiftUI We are a development agency building phenomenal apps. Overview The goal of this project is to bring the full pow

Exyte 269 Jan 4, 2023
3D Touch Application for Weighing Plums (and other small fruit!)

Plum-O-Meter ###3D Touch Application for Weighing Plums (and other small fruit!) Companion project to this blog post: http://flexmonkey.blogspot.co.uk

simon gladman 526 Sep 27, 2022
The code for my CoreGraphics+CoreAnimation talk, held during the 2012 iOS Game Design Seminar at the Technical University Munich.

PKCoreTechniques ======= Core Techniques is the result of a presentation I held at the Technical University of Munich during the 'iOS Game Design Semi

Philip Kluz 143 Sep 21, 2022
Visual designing library for iOS & OSX

ProcessingKit ProcessingKit is a Visual designing library for iOS & OSX. ProcessingKit written in Swift ?? and you can write like processing. Demo Dem

Atsuya Sato 333 Nov 12, 2022
Conical (angular) gradient for iOS written in Swift

AEConicalGradient Conical (angular) gradient in Swift I hope that somebody will find this useful. And nice. Usage AEConicalGradient is a minion which

Marko Tadić 82 Dec 27, 2022
🌈 Highly customizable Core Graphics based gradient view for iOS

MKGradientView Highly customizable Core Graphics based gradient view Features Available gradient types: Linear (Axial) Radial (Circular) Conical (Angu

Max Konovalov 167 Dec 27, 2022
GraphLayout - iOS UI controls to visualize graphs. Powered by Graphviz

GraphLayout GraphLayout - UI controls for graph visualization. It is powered by Graphviz. Graph visualization is a way of representing structural info

null 97 Sep 26, 2022
🎞 Powerful gradient animations made simple for iOS.

AnimatedGradientView is a UIView subclass which makes it simple to add animated gradients to your iOS app. It is written purely in Swift. Further docu

Ross Butler 431 Dec 12, 2022
Create Live Graphics in SwiftUI (iOS, tvOS & macOS)

PixelUI import SwiftUI import PixelUI struct ContentView: View { var body: some View { GeometryReader { geo in

Anton Heestand 21 Dec 17, 2022