使用 Objective-C 从 PDF 中提取可编辑字段

2024-03-18

我已经研究在我的 iOS 应用程序中使用 PDF 一段时间了。我已经解决了一些难题,例如扫描操作员并在 UIWebView 中显示 PDF。然而,我真正需要做的是确定可编辑字段在 PDF 文档中。

理想情况下,我希望能够直接与这些领域进行交互,但这听起来非常困难,而且不是明显的第一步。我已经在与一个 Windows 服务进行交互,该服务可以通过这种方式操作 PDF,并且可以确定可编辑字段,在表单视图中从用户收集字段数据,并将该数据发布回服务器。问题是我看不到如何识别字段。我正在与政府颁发的 PDF(例如 I-9 和 W-4)进行交互,因此我无法控制 PDF 的创建或字段的命名。这就是为什么我需要动态提取它们。任何帮助和/或参考将不胜感激。

我正在使用 Apple 的 Quatrz 2D 编程指南中的[此参考](https://developer.apple.com/library/mac/#documentation/graphicsimaging/conceptual/drawingwithquartz2d/dq_pdf_scan/dq_pdf_scan.html"PDF Document Parsing")扫描 PDF 时触发操作员回调,但这并不能帮助我找到可编辑字段。

我还只是加载带有 PDF 数据的 UIWebView 以向用户显示。

[_webView loadData:decodedData MIMEType:@"application/pdf" textEncodingName:@"utf-8" baseURL:nil];

UPDATE:

我构建了一个 PDF Helper 类(如下所示)来遍历目录中所有可能的对象类型。最初我没有处理数组中的嵌套字典,所以我没有看到表单字段。一旦我修复了这个问题,我就意识到我必须考虑父引用,以避免循环递归调用,从而启动无限循环。下面的代码显示了文档目录中的大量信息。现在我只需要解析它以隔离我需要的表单字段。

PDFHelper.h

#import <Foundation/Foundation.h>

id selfClass;

@interface PDFHelper : NSObject

@property (nonatomic, strong) NSData *pdfData;
@property (nonatomic, strong) NSMutableDictionary *pdfDict;
@property (nonatomic) int catalogLevel;


-(NSArray *) copyPDFArray:(CGPDFArrayRef)arr referencingDictionary:(CGPDFDictionaryRef)dict referencingKey:(const char *)key;
-(NSArray *) getFormFields;
-(CGPDFDictionaryRef) getDocumentCatalog;

@end

PDF助手.m

#import "PDFHelper.h"
#import "FileHelpers.h"
#import "Log.h"

@implementation PDFHelper

@synthesize pdfData = _pdfData;
@synthesize pdfDict = _pdfDict;
@synthesize catalogLevel = _catalogLevel;

-(id)init
{
    self = [super init];
    if(self)
    {
        selfClass = self;
        _pdfDict = [[NSMutableDictionary alloc] init];
        _catalogLevel = 1;
    }

    return self;
}

-(NSArray *) getFormFields
{
    CGPDFDictionaryRef acroForm = NULL;
    if (CGPDFDictionaryGetDictionary([self getPdfDocDictionary], "AcroForm", &acroForm))
        CGPDFDictionaryApplyFunction(acroForm, getDictionaryObjects, acroForm);
    return [_pdfDict objectForKey:@"XFA"];
}

-(CGPDFDictionaryRef) getDocumentCatalog
{
    CGPDFDictionaryRef docCatalog = [self getPdfDocDictionary];
    CGPDFDictionaryApplyFunction(docCatalog, getDictionaryObjects, docCatalog);
    return docCatalog;
}

-(CGPDFDictionaryRef) getPdfDocDictionary
{
    NSURL *pdf = [[NSURL alloc] initFileURLWithPath:[FileHelpers pathInLibraryDirectory:@"file.pdf"]];

    [_pdfData writeToFile:[pdf path] atomically:YES];

    CGPDFDocumentRef pdfDocument = CGPDFDocumentCreateWithURL((__bridge CFURLRef)pdf);
    CGPDFDictionaryRef returnDict = CGPDFDocumentGetCatalog(pdfDocument);
    return returnDict;
}

void getDictionaryObjects (const char *key, CGPDFObjectRef object, void *info) {

    NSString *logString = [[NSString alloc] initWithString:[NSString stringWithFormat:@"key: %s", key]];
    for (int i = 0; i < [selfClass catalogLevel]; i++)
        logString = [NSString stringWithFormat:@"-%@", logString];
    [Log LogDebug:logString];

    CGPDFDictionaryRef contentDict = (CGPDFDictionaryRef)info;

    CGPDFObjectType type = CGPDFObjectGetType(object);
    switch (type) {
        case kCGPDFObjectTypeNull: {            
                [Log LogDebug:[NSString stringWithFormat:@"*****pdf null value"]];
            break;
        }
        case kCGPDFObjectTypeBoolean: {
            CGPDFBoolean objectBoolean;
            if (CGPDFObjectGetValue(object, kCGPDFObjectTypeBoolean, &objectBoolean)) {
                NSString *logString = [[NSString alloc] initWithString:[NSString stringWithFormat:@"pdf boolean value: %@", [NSNumber numberWithBool:objectBoolean]]];
                for (int i = 0; i < [selfClass catalogLevel]; i++)
                    logString = [NSString stringWithFormat:@"-%@", logString];
                [Log LogDebug:logString];
                [[selfClass pdfDict] setObject:[NSNumber numberWithBool:objectBoolean]
                                        forKey:[NSString stringWithCString:key encoding:NSUTF8StringEncoding]];
            }
            break;
        }
        case kCGPDFObjectTypeInteger: {
            CGPDFInteger objectInteger;
            if (CGPDFObjectGetValue(object, kCGPDFObjectTypeInteger, &objectInteger)) {
                NSString *logString = [[NSString alloc] initWithString:[NSString stringWithFormat:@"pdf integer value: %ld", (long int)objectInteger]];
                for (int i = 0; i < [selfClass catalogLevel]; i++)
                    logString = [NSString stringWithFormat:@"-%@", logString];
                [Log LogDebug:logString];
                [[selfClass pdfDict] setObject:[NSNumber numberWithInt:objectInteger]
                                        forKey:[NSString stringWithCString:key encoding:NSUTF8StringEncoding]];
            }
            break;
        }
        case kCGPDFObjectTypeReal: {
            CGPDFReal objectReal;
            if (CGPDFObjectGetValue(object, kCGPDFObjectTypeReal, &objectReal)) {
                NSString *logString = [[NSString alloc] initWithString:[NSString stringWithFormat:@"pdf real value: %ld", (long int)objectReal]];
                for (int i = 0; i < [selfClass catalogLevel]; i++)
                    logString = [NSString stringWithFormat:@"-%@", logString];
                [Log LogDebug:logString];
                [[selfClass pdfDict] setObject:[NSNumber numberWithInt:objectReal]
                                        forKey:[NSString stringWithCString:key encoding:NSUTF8StringEncoding]];
            }
            break;
        }
        case kCGPDFObjectTypeName: {
            const char *name;
            if (CGPDFDictionaryGetName(contentDict, key, &name))
            {
                NSString *dictName = [[NSString alloc] initWithCString:name encoding:NSUTF8StringEncoding];
                if (dictName)
                {
                    NSString *logString = [[NSString alloc] initWithString:[NSString stringWithFormat:@"pdf name value: %@", dictName]];
                    for (int i = 0; i < [selfClass catalogLevel]; i++)
                        logString = [NSString stringWithFormat:@"-%@", logString];
                    [Log LogDebug:logString];
                    [[selfClass pdfDict] setObject:dictName
                                            forKey:[NSString stringWithCString:key encoding:NSUTF8StringEncoding]];
                }
            }
            break;
        }
        case kCGPDFObjectTypeString: {
            CGPDFStringRef objectString;
            if (CGPDFObjectGetValue(object, kCGPDFObjectTypeString, &objectString)) {
                NSString *logString = [[NSString alloc] initWithString:[NSString stringWithFormat:@"pdf string value: %@", (__bridge NSString *)CGPDFStringCopyTextString(objectString)]];
                for (int i = 0; i < [selfClass catalogLevel]; i++)
                    logString = [NSString stringWithFormat:@"-%@", logString];
                [Log LogDebug:logString];
                [[selfClass pdfDict] setObject:(__bridge NSString *)CGPDFStringCopyTextString(objectString)
                                        forKey:[NSString stringWithCString:key encoding:NSUTF8StringEncoding]];
            }
            break;
        }
        case kCGPDFObjectTypeArray: {
            CGPDFArrayRef objectArray;
            if (CGPDFObjectGetValue(object, kCGPDFObjectTypeArray, &objectArray)) {
                NSArray *myArray=[selfClass copyPDFArray:objectArray referencingDictionary:contentDict referencingKey:key];
                [[selfClass pdfDict] setObject:myArray
                                        forKey:[NSString stringWithCString:key encoding:NSUTF8StringEncoding]];

            }
            break;
        }
        case kCGPDFObjectTypeDictionary: {
            CGPDFDictionaryRef objectDictionary;
            if (CGPDFObjectGetValue(object, kCGPDFObjectTypeDictionary, &objectDictionary)) {
                NSString *logString = @"Found dictionary";
                for (int i = 0; i < [selfClass catalogLevel]; i++)
                    logString = [NSString stringWithFormat:@"-%@", logString];
                //[Log LogDebug:logString];
                NSString *keyCheck = [[NSString alloc] initWithUTF8String:key];
                if (![keyCheck isEqualToString:@"Parent"] && ![keyCheck isEqualToString:@"P"])
                {
                    [selfClass setCatalogLevel:[selfClass catalogLevel] + 1];
                    CGPDFDictionaryApplyFunction(objectDictionary, getDictionaryObjects, objectDictionary);
                    [selfClass setCatalogLevel:[selfClass catalogLevel] - 1];
                }
            }
            break;
        }
        case kCGPDFObjectTypeStream: {
            CGPDFStreamRef objectStream;
            if (CGPDFObjectGetValue(object, kCGPDFObjectTypeStream, &objectStream)) {

                CGPDFDictionaryRef dict = CGPDFStreamGetDictionary( objectStream );

                CGPDFDataFormat fmt = CGPDFDataFormatRaw;
                CFDataRef streamData = CGPDFStreamCopyData(objectStream, &fmt);
                NSData *data = [[NSData alloc] initWithData:(__bridge NSData *)(streamData)];
                [data writeToFile:[FileHelpers pathInDocumentDirectory:@"data.dat"] atomically:YES];
                NSString *dataString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                //if (!dataString) {
                //    dataString = [[NSString alloc] initWithData:(__bridge NSData *)(streamData) encoding:NSUTF16StringEncoding];
               // }

                NSString *logString = [[NSString alloc] initWithString:[NSString stringWithFormat:@"pdf stream length: %ld - %@", (long int)CFDataGetLength( streamData ), dataString]];

                for (int i = 0; i < [selfClass catalogLevel]; i++)
                    logString = [NSString stringWithFormat:@"-%@", logString];
                [Log LogDebug:logString];

                NSString *keyCheck = [[NSString alloc] initWithUTF8String:key];
                if( dict && ![keyCheck isEqualToString:@"Parent"] && ![keyCheck isEqualToString:@"P"])
                {
                    [selfClass setCatalogLevel:[selfClass catalogLevel] + 1];
                    CGPDFDictionaryApplyFunction(dict, getDictionaryObjects, dict);
                    [selfClass setCatalogLevel:[selfClass catalogLevel] - 1];
                }
            }
        }
    }
}

- (NSArray *)copyPDFArray:(CGPDFArrayRef)arr referencingDictionary:(CGPDFDictionaryRef)dict referencingKey:(const char *)key
{
    int i = 0;
    NSMutableArray *temp = [[NSMutableArray alloc] init];

    NSString *logString = [[NSString alloc] initWithString:[NSString stringWithFormat:@"pdf array count: %zu", CGPDFArrayGetCount(arr)]];
    for (int i = 0; i < [selfClass catalogLevel]; i++)
        logString = [NSString stringWithFormat:@"-%@", logString];
    [Log LogDebug:logString];

    for(i=0; i<CGPDFArrayGetCount(arr); i++){
        CGPDFObjectRef object;
        CGPDFArrayGetObject(arr, i, &object);
        CGPDFObjectType type = CGPDFObjectGetType(object);
        switch(type){
            case kCGPDFObjectTypeNull: {
                NSString *logString = [[NSString alloc] initWithString:[NSString stringWithFormat:@"pdf array null(%d)", i]];
                for (int i = 0; i < [selfClass catalogLevel]; i++)
                    logString = [NSString stringWithFormat:@"-%@", logString];
                [Log LogDebug:logString];
                break;
            }
            case kCGPDFObjectTypeBoolean: {
                CGPDFBoolean objectBool;
                if (CGPDFObjectGetValue(object, kCGPDFObjectTypeBoolean, &objectBool)) {
                    NSString *logString = [[NSString alloc] initWithString:[NSString stringWithFormat:@"pdf array boolean value(%d): %@", i, [NSNumber numberWithBool:objectBool]]];
                    for (int i = 0; i < [selfClass catalogLevel]; i++)
                        logString = [NSString stringWithFormat:@"-%@", logString];
                    [Log LogDebug:logString];
                    [temp addObject:[NSNumber numberWithBool:objectBool]];
                }
                break;
            }
            case kCGPDFObjectTypeInteger: {
                CGPDFInteger objectInteger;
                if (CGPDFObjectGetValue(object, kCGPDFObjectTypeInteger, &objectInteger)) {
                    NSString *logString = [[NSString alloc] initWithString:[NSString stringWithFormat:@"pdf array integer value(%d): %ld", i, (long int)objectInteger]];
                    for (int i = 0; i < [selfClass catalogLevel]; i++)
                        logString = [NSString stringWithFormat:@"-%@", logString];
                    [Log LogDebug:logString];
                    [temp addObject:[NSNumber numberWithInt:objectInteger]];
                }
                break;
            }
            case kCGPDFObjectTypeReal:
            {
                CGPDFReal objectReal;
                if (CGPDFObjectGetValue(object, kCGPDFObjectTypeReal, &objectReal))
                {
                    NSString *logString = [[NSString alloc] initWithString:[NSString stringWithFormat:@"pdf array real(%d): %ld", i, (long int)objectReal]];
                    for (int i = 0; i < [selfClass catalogLevel]; i++)
                        logString = [NSString stringWithFormat:@"-%@", logString];
                    [Log LogDebug:logString];
                    [temp addObject:[NSNumber numberWithInt:objectReal]];
                }
                break;
            }
            case kCGPDFObjectTypeName:
            {
                const char *name;
                if (CGPDFDictionaryGetName(dict, key, &name))
                {
                    NSString *dictName = [[NSString alloc] initWithCString:name encoding:NSUTF8StringEncoding];

                    if (dictName)
                    {
                        NSString *logString = [[NSString alloc] initWithString:[NSString stringWithFormat:@"pdf array name value(%d): %@", i, dictName]];
                        for (int i = 0; i < [selfClass catalogLevel]; i++)
                            logString = [NSString stringWithFormat:@"-%@", logString];
                        [Log LogDebug:logString];
                        [[selfClass pdfDict] setObject:dictName
                                                forKey:[NSString stringWithCString:key encoding:NSUTF8StringEncoding]];
                    }
                }
                break;
            }
            case kCGPDFObjectTypeString:
            {
                CGPDFStringRef objectString;
                if (CGPDFObjectGetValue(object, kCGPDFObjectTypeString, &objectString))
                {
                    NSString *tempStr = (__bridge NSString *)CGPDFStringCopyTextString(objectString);
                    NSString *logString = [[NSString alloc] initWithString:[NSString stringWithFormat:@"pdf array string(%d): %@", i, tempStr]];
                    for (int i = 0; i < [selfClass catalogLevel]; i++)
                        logString = [NSString stringWithFormat:@"-%@", logString];
                    [Log LogDebug:logString];
                    [temp addObject:tempStr];
                }
                break;
            }
            case kCGPDFObjectTypeArray :
            {
                CGPDFArrayRef objectArray;
                if (CGPDFObjectGetValue(object, kCGPDFObjectTypeArray, &objectArray))
                {
                    NSArray *tempArr = [selfClass copyPDFArray:objectArray referencingDictionary:dict referencingKey:key];
                    [temp addObject:tempArr];
                }
                break;
            }
            case kCGPDFObjectTypeDictionary :
            {
                CGPDFDictionaryRef objectDict;
                NSString *keyCheck = [[NSString alloc] initWithUTF8String:key];
                if (CGPDFObjectGetValue(object, kCGPDFObjectTypeDictionary, &objectDict) && ![keyCheck isEqualToString:@"Parent"] && ![keyCheck isEqualToString:@"P"])
                {
                    [selfClass setCatalogLevel:[selfClass catalogLevel] + 1];
                    CGPDFDictionaryApplyFunction( objectDict, getDictionaryObjects,  objectDict);
                    [selfClass setCatalogLevel:[selfClass catalogLevel] - 1];
                }
                break;
            }
            case kCGPDFObjectTypeStream :
            {
                CGPDFStreamRef objectStream;
                if (CGPDFObjectGetValue(object, kCGPDFObjectTypeStream, &objectStream))
                {
                    CGPDFDictionaryRef streamDict = CGPDFStreamGetDictionary( objectStream );
                    CGPDFDataFormat fmt = CGPDFDataFormatRaw;
                    CFDataRef streamData = CGPDFStreamCopyData(objectStream, &fmt);
                    NSString *dataString = [[NSString alloc] initWithData:(__bridge NSData *)(streamData) encoding:NSUTF8StringEncoding];

                    NSString *logString = [[NSString alloc] initWithString:[NSString stringWithFormat:@"pdf array stream length: (%d): %ld - %@", i, (long int)CFDataGetLength( streamData ), dataString]];

                    for (int i = 0; i < [selfClass catalogLevel]; i++)
                        logString = [NSString stringWithFormat:@"-%@", logString];
                    [Log LogDebug:logString];


                    NSString *keyCheck = [[NSString alloc] initWithUTF8String:key];
                    if( streamDict && ![keyCheck isEqualToString:@"Parent"] && ![keyCheck isEqualToString:@"P"])
                    {
                        [selfClass setCatalogLevel:[selfClass catalogLevel] + 1];
                        CGPDFDictionaryApplyFunction( streamDict, getDictionaryObjects, streamDict );
                        [selfClass setCatalogLevel:[selfClass catalogLevel] - 1];
                    }
                }
            }

        }
    }
    return temp;
}

@end

“可编辑字段”是指可以使用 Acrobat 或 Adob​​e Reader 填写的表单元素类型吗?

这些字段不是实际页面描述的一部分。如果您查看 PDF 规范文档,您会在第 12.7 章中找到“交互式表单”的描述,其中解释了文档的字段字典是从文档目录中名为“AcroForm”的元素开始存储的。

据我所知,iOS 确实允许您访问文档目录,因此您必须在该目录字典中找到“AcroForm”字段,然后深入到字段字典结构中以收集所需的信息。完整文档中的所有字段都以分层方式存储在此处。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Objective-C 从 PDF 中提取可编辑字段 的相关文章

  • 了解 React Native 中的默认字体大小

    在过去的几个月里 我一直在开发一个 React Native 应用程序 但有些事情总是让我困惑 而我现在正试图弄清楚它的真相 我正在尝试标准化应用程序中的字体大小 正文 标题等 并且正在努力了解 React Native 究竟从哪里获取默认
  • 从 AVAudioRecorder 获取分贝

    我正在尝试从 AVAudio 录音机获取分贝值 这是我目前的代码 我有一个启动录音机的方法 然后是一个读取分贝值的方法 var recorder AVAudioRecorder 全局定义的记录器 然后在此处使用 func init reco
  • 使用 iPhone 控制蓝牙音频设备

    我正在寻找为 iPhone 编写应用程序 它将能够控制汽车中的收音机和 CD 播放器 收音机和播放器具有可用的蓝牙连接 我开始这个问题是为了获得这个地方所需的所有信息 我有几个问题 但如果您发现任何我没有要求的对我开始开发此应用程序不重要的
  • 如何使用存储在 Cocoa Touch 框架中的 Localized.strings?

    我想为 CocoaTouch 框架添加多语言支持 问题 可本地化的字符串我创建的文件仅被使用NSLocalizedString当它是主应用程序及其目标的一部分时 我想将其存储在框架内以将事物分开 我怎样才能使用可本地化的字符串当放置在 Co
  • Cordova iOS 启动画面

    我无法让闪屏停留在页面加载之前 我已经阅读了谷歌搜索第一页 第二页和第三页中的所有条目 我阅读了 stackoverflow 上发布的所有问题 包括一个很好的解释 https stackoverflow com questions 1800
  • React Native ios运行问题

    我是反应本机和运行新手yarn ios我的 React Native 项目不断失败并出现以下错误 构建失败 以下构建命令失败 编译C Users gift Library Developer Xcode DerivedData gainer
  • Swift 3 中数组的 indexOf(_:) 方法的替换

    在我的项目 用 Swift 3 编写 中 我想使用从数组中检索元素的索引indexOf 方法 存在于 Swift 2 2 中 但我找不到任何替代方法 Swift 3 中是否有任何好的替代方法或类似的方法 Update 我忘记提及我想在自定义
  • ExpandableLabel iOS 中的“少看”

    我正在使用第三方库可扩展标签 https github com apploft ExpandableLabel实施一个see more特征 我正在寻找仅快速的解决方案 其中包含标签中的文本而不是按钮中的文本 因此这可以完美地工作 添加库并更
  • 尝试注册 RCTBridgeModule 类 RCTFileReaderModule

    尝试为名称 FileReaderModule 注册 RCTBridgeModule 类 RCTFileReaderModule 但该名称已由类 FileReaderModule 注册 尝试使用命令react native run ios在i
  • TableView 中图像的大小不正确

    我正在使用来自 URL 的图像创建一个表视图 但图像不会调整到所有视图的大小 直到我将其按入行中 知道为什么会发生这种情况吗 这是一个自定义的表格视图 我的代码是 UITableViewCell tableView UITableView
  • IOS 上图像的加密/解密

    我们正在使用加密 解密和 UIIMAGE 如果我们加密和解密 UIIMAge 而不保存到 iphone 画廊中 它工作正常 但如果我们加密 保存到画廊中 将 加密的图像 加载到应用程序中 然后解密它效果不好 我们使用这个函数来加密 解密 保
  • 调用了 numberOfRowsInSection 但未调用 cellForRowAtIndexPath

    在我的表视图中节中的行数被调用两次但是cellForRowAtIndexPath不叫 我想在 tableView 中显示 Facebook 好友列表 如果 cellForRowAtIndexPath 调用我的问题就解决了 我在这里的数组中得
  • 禁用 iPhone 4S / 新 iPad 键盘上的听写按钮

    我们的应用程序是一个医疗保健应用程序 我们的应用程序中有一个符合 HIPAA 标准的语音识别器 所有听写都可以通过它进行 医院不希望医生意外开始与不符合 HIPAA 标准的 Nuance Dragon 服务器进行对话 因此 我正在寻找可以抑
  • Rails 4 - 如何链接到 PDF 文件(名称.PDF)?

    我正在生成 PDF 文件 我的链接如下所示 当我点击这个时 它会带我去 display invoice 123456789 这是一个 HTML 版本 在控制器中的操作如下 def display invoice if params invo
  • GoogleSignIn ios 附加到谷歌表格

    我目前正在开发一个 iOS 应用程序 该应用程序需要写入登录用户拥有的 Google 工作表 要登录我正在使用的用户GoogleSignInpod 并附加到我正在使用的谷歌表GoogleAPIClientForREST Sheets pod
  • 如何像谷歌日历一样将单元格的内容滚动到表格视图中的另一个单元格中?

    我希望用户界面像谷歌日历那样进入桌面视图 它在不同的行中显示相同的日期事件 但是当您向上或向下滚动时 左侧的日期也会向上向下滚动 Can you please help me how to achieve this Please take
  • Apple 如何在机场菜单打开时更新它? (当 NSMenu 已经打开时如何更改它)

    我有一个状态栏项目 可以弹出一个 NSMenu 并且我有一个委托集 并且它已正确连接 void menuNeedsUpdate NSMenu menu工作正常 也就是说 该方法设置为在显示菜单之前调用 我需要监听该方法并触发异步请求 稍后在
  • 如何在运行仅 iPhone 应用程序(非通用)的 iPad 上的 UIPickerView 中支持 VoiceOver?

    一般来说 我会查看 Apple 的 UICatalog 示例代码以获取基本的 VoiceOver 支持 但示例代码中似乎有对 UIPickerViews 的 VoiceOver 支持 我是否需要在某处提供accessibilityLabel
  • 在iOS中设置框架的原点

    我正在尝试以编程方式设置框架的原点 Method1 button frame origin y 100 方法二 CGRect frame button frame frame origin y 100 我尝试了方法 1 但它不起作用 显示错
  • 是否可以在增强现实应用程序中使用自定义 iOS UI 元素(例如 UILabel)

    我想知道是否可以使用像这样的 UI 元素UIButton UILabel在带有 ARKit 的增强现实应用程序中 如果您也对 UIView 子类的透明度模式感兴趣 请尝试我的示例https github com erikhric ar me

随机推荐