iOS无障碍适配西瓜视频Voice Over实践示例

目录
  • 一、Voice Over 简介
  • 二、Voice Over 使用指南
    • Voice Over 开发环境配置
    • Voice Over 基本使用 —— 以西瓜为例
      • 入门手势
      • 进阶手势
  • 三、快速适配 Voice Over / 无障碍
    • 设置无障碍焦点
    • 设置无障碍文案
    • 调整焦点顺序
    • 西瓜首页适配实战
      • 搜索栏
      • 频道栏 & 频道编辑器
      • 作者动态栏
      • 视频列表
  • 四、Voice Over 相关协议介绍
    • UIAccessibility 无障碍标签标注
    • UIAccessibilityAction 无障碍手势响应
    • UIAccessibilityFocus 无障碍焦点响应
    • UIAccessibilityContainer 无障碍自定义焦点
  • 五、常见问题与解决方案
    • 焦点缺失/焦点冗余
    • 焦点过细/焦点合并
    • 焦点信息错误 (目的不明确,信息冗余等)
    • 焦点停留不当
    • 焦点顺序错误问题
    • 焦点选中时乱跳问题
    • 浮窗问题 / 焦点被覆盖时仍可访问
    • 嵌套容器 ScrollView 无法跟随滚动问题
    • 横滑拖拽问题(手势替代问题)

为了解决老年人、残疾人等群体在使用互联网等智能技术时遇到的困难,自 2021 年春季开始,西瓜视频开展了无障碍与适老化改造专项行动。陆续完成了无障碍影院、色弱模式、护眼模式、大字号模式、外挂字幕等多个改造需求,充分满足了视力障碍、听力障碍以及老年人等特殊群体的需求。

一、Voice Over 简介

Voice Over 旁白是苹果手机自带的工具。它能让人们在不看屏幕的情况下了解页面内容和信息。盲人用户在使用 iOS 设备时依赖 Voice Over 提供听觉反馈。苹果在自研的各类系统中均实现了 Voice Over 功能,如 OS X,iOS,watchOS 等等。透过 Voice Over 视障用户可以在不同设备上获得相同的体验。

使用旁白来访问西瓜视频的用户有很多,“盲人小马哥”就是其中的一位,感兴趣的同学可以通过观看他的视频进一步了解旁白。

二、Voice Over 使用指南

本节介绍了 Voice Over 开发者通常需要配置的开发环境。并以西瓜视频为例,演示了 Voice Over 的基本操作。

Voice Over 开发环境配置

为了测试的方便,建议开发者可以将辅助功能快捷键设置成 VoiceOver 的切换,只需要连按三次右侧开关键就能开启/关闭 VoiceOver。

下方路径中的 “通用” 适用于低版本系统,高版本系统通过设置-> “辅助功能” 即可找到旁白

开启/关闭 Voice Over(旁白)

设置 -> “通用” -> “辅助功能” -> “VoiceOver”(旁白)

设置连按三次右侧开关键开启/关闭 Voice Over(旁白) (开启后可以便捷的打开/关闭旁白)

设置 -> “通用” -> “辅助功能” ->“辅助功能快捷键”,勾选 Voice Over 功能。

开启 Voice Over+字幕面板 (开启后可以便捷的查看旁白的全部朗读文案)

设置 -> “通用” -> “辅助功能” ->“VoiceOver”->“字幕面板”

Voice Over 基本使用 —— 以西瓜为例

Voice Over 常用手势详解

这里主要例举出 iOS 系统和西瓜视频中最常用的手势,完整操作可以参照苹果官方文档

https://support.apple.com/zh-cn/guide/iphone/iph3e2e3a6d/15.0/ios/15.0

入门手势

  • 使用手势进行元素筛选

轻点或触摸项目——选择并朗读项目

向右轻扫——选择下一项

向左轻扫——选择上一项

三指向某个方向滑动——翻页操作,可以使 UIScrollView(包括 TableView、CollectionView)向某个方向翻动一页

  • 使用手势响应元素事件

轻点两下——响应当前元素的事件

轻点三下——双击当前所选元素

双指轻点两下——响应开发者定义的快捷事件 (如播放视频、暂停视频等)

双指左右滑动(快速来回移动双指三次,形成“Z”字形)——关闭弹窗或返回到上一级页面

双指轻点两下并按住——用户自定义元素名称

进阶手势

  • 使用手势快速筛选元素

四指轻点屏幕顶部附近——选择屏幕上的第一项

四指轻点屏幕底部附近——选择屏幕上的最后一项

  • 使用“旁白”转子

您可以使用转子来更改“旁白”设置(如语速、遍历方法等),在屏幕上从一个项目跳到下一个项目,以及选择特殊输入方法(如“盲文屏幕输入”或“手写”)等。有关详细信息,请参阅在 iPhone 上使用转子控制“旁白”

https://support.apple.com/zh-cn/guide/iphone/iph3e2e3a6d/15.0/ios/15.0

通过以下手势来使用转子。

双指转动——选取转子设置

向上轻扫——移到上一项或调高(取决于转子设置)

向下轻扫——移到下一项或调低(取决于转子设置)

三、快速适配 Voice Over / 无障碍

想让 App 达到无障碍基本可用并非难事,通过设置无障碍焦点、设置无障碍文案、调整焦点顺序三步可以完成绝大多数的无障碍适配工作。本节对以上三步适配进行了快速入门的介绍,并将西瓜首页作为实战案例为大家讲解。

设置无障碍焦点

焦点是视力障碍用户访问应用的唯一途径,Voice Over 开启时,如果一个元素没有被设置为焦点,那么该元素在屏幕中将不可被访问。用户可以通过在屏幕上移动焦点来“浏览”内容。正确的焦点标注和焦点顺序能够让读屏软件用户获得更好的体验。

打开旁白后,系统会使用黑色框体框选当前的焦点。通过轻触某个位置 或 单指左右轻扫即可切换焦点。

  • 哪些场景需要焦点:

除装饰性组件以外的功能性组件都需要焦点,如标题、作者头像、点赞、收藏、评论、更多等。

  • 哪些场景需要合并焦点:

功能相同且距离近的焦点需要合并。如作者名称、作者头像(功能都是跳转个人主页,且距离近)。

需要高效筛选信息的场景需要合并,保留合并焦点的主功能,其余功能添加到转子中,如 Feed。具体参照各业务方设计。

  • 如何设置无障碍焦点:

针对绝大多数情况,我们可以利用以下的几个属性来调整焦点。

isAccessibilityElement:使用该属性可以调整单个元素的无障碍可见性。对于大多数 UI 基本元素,当父控件为无障碍元素时,子控件将无法获焦。

accessibilityElementsHidden:使用该属性可以调整单个元素及其 subviews的无障碍可见性,一般用于屏蔽整个组件。

accessibilityViewIsModal:使用该属性可以使该元素在同级 view中保持唯一可见性。常见场景见焦点被覆盖时仍然可以被访问。

设置无障碍文案

好的无障碍文案可以让用户清晰的了解到当前焦点的目的,一般来说我们可以将元素按照按钮、输入框、搜索框等来划分,从而进行标注。

当我们参照“开发环境配置”配置好字幕后,旁白朗读的文案将显示在屏幕的底部。

  • 无障碍文案应该包含什么:

无障碍文案需要能准确描述一个焦点的功能及当前的状态 (如 已选定、点赞、标签栏)。如果一个焦点包含多个不同的内容,应当按照信息优先级,将该焦点内全部肉眼可见信息全部朗读。

  • 如何配置无障碍文案:

从代码层面来看,我们可以通过以下的几个属性来设置无障碍文案。

accessibilityLabel:一般来说,任意元素都需要设置 Label,Label 应当为短语 如:点赞、收藏;

accessibilityValue:(可选)用于经常变化的标签数据类文案,例如 视频的点赞按钮的具体数值 (共 xxx 人);

accessibilityTraits:当元素作为一个无障碍焦点时,我们需要描述该焦点的类别,如按钮、已选中等。此时需要使用 Traits 对元素进行标记;

accessibilityHint:(可选)当元素标签无法明确指出动作结果的时候,应该给出一个提示;

accessibilityFrame:当元素的焦点过小,需要手动调整焦点到较大值的时候,可以使用 Frame

VoiceOver 会把这几个属性连接起来,一般情况朗读顺序为accessibilityLabelaccessibilityValueaccessibilityTraitsaccessibilityHint

特例:accessibilitytraits中包含UIAccessibilityTraitSelected则会在最前方朗读“已选定”。

调整焦点顺序

焦点顺序应该遵循 从左往右 & 从上到下。正常情况下,焦点的顺序与 SubViews 的顺序一致,我们无需手动置顶焦点顺序。如果焦点顺序出现问题,我们可以利用 UIAccessibilityContainer 来调整屏幕中焦点的顺序。

accessibilityElements:通过该属性,我们可以指定一个元素包含的所有无障碍子元素。

UITableViewCell 中重设需要格外谨慎,可能会出现焦点循环问题。

以下图为例,如果 C、D、E 是无障碍可视元素,通过如下设置我们就能使无障碍元素按照 D、E、C 的顺序来排列。

A.accessibilityElements = @[B, C]
B.accessibilityElements = @[D, E]

西瓜首页适配实战

下面以西瓜首页为示例,为大家演示无障碍的基础适配。

以西瓜首页为例,自上而下我们主要有五个区域需要设置焦点。分别是 搜索栏、频道栏 & 频道编辑器、作者动态栏 (Story)、视频卡片 (卡片为一个焦点,用户通过转子进行其他操作)、底部 Tab 选择器。下面针对每个部分进行无障碍适配的解释。

搜索栏

searchBox.isAccessibilityElement = YES;
searchBox.accessibilityLabel = @"搜索框";
searchBox.accessibilityValue = @"热搜词1,第一座4万亿GDP的城市。热搜词2,南昌至台湾专列开通";
searchBox.accessibilityTraits = UIAccessibilityTraitSearchField;

频道栏 & 频道编辑器

/// 频道栏的无障碍适配
categoryCell.isAccessibilityElement = YES;
categoryCell.accessibilityLabel = @"推荐频道";
categoryCell.accessibilityVaule = @"热搜词1,第一座4万亿GDP的城市。热搜词2,南昌至台湾专列开通";
categoryCell.accessibilityHint = @"轻点两下切换首页频道";
/// 未选中时
categoryCell.accessibilityTraits = UIAccessibilityTraitTabBar;
/// 已选中时
categoryCell.accessibilityTraits = UIAccessibilityTraitTabBar|UIAccessibilityTraitSelected;
/// 频道编辑器的无障碍适配
// 如果面板是以addSubview的形式添加到界面上时,需要屏蔽底层元素的访问
@implementation categoryEditViewController
- (void)viewDidAppear {
    categoryEditView.accessibilityViewIsModal = YES;
    /// 使用户焦点移动到频道编辑面板上。
    UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, categoryEditView);
}
- (void)viewDidDisAppear {
    categoryEditView.accessibilityViewIsModal = NO;
}
@end

作者动态栏

storyCell.isAccessibilityElement = YES;
storyCell.accessibilityLabel = isLive ?  @"入江闪闪,正在直播" : @"入江闪闪";
storyCell.accessibilityHint = isLive ? @"轻点两下进入作者直播观看视频" : @"轻点两下进入作者视频列表播放视频";
@implementation storyCell
// TableView与CollectionView嵌套时,cell可能会出现无法自然滚动的问题。
- (void)accessibilityElementDidBecomeFocused {
    [self.collectionView scrollToIndexPath:self.indexPath];
}
@end

视频列表

videoCell.isAccessibilityElement = YES
videoCell.accessibilityLabel = [视频标题、作者名称、点赞数、收藏数、评论数等]
videoCell.accessibilityHint = @"轻点两下进入详情页播放视频,上下轻扫使用转子访问更多功能"
UIAccessibilityCustomAction * action1 = [[UIAccessibilityCustomAction alloc] initWithName:@"点赞" target:self selector:@selector(action1)];
UIAccessibilityCustomAction * action2 = [[UIAccessibilityCustomAction alloc] initWithName:@"收藏" target:self selector:@selector(action2)];
UIAccessibilityCustomAction * action3 = [[UIAccessibilityCustomAction alloc] initWithName:@"更多" target:self selector:@selector(action3)];
videoCell.accessibilityCustomActions = @[action1,action2,action3];

四、Voice Over 相关协议介绍

UIAccessibility 无障碍标签标注

@interface NSObject (UIAccessibility)
/// 标记一个元素是否是无障碍元素
@property (nonatomic) BOOL isAccessibilityElement;
/// 标记一个元素的无障碍元素的简短描述 如 (点赞、收藏)
@property (nullable, nonatomic, copy) NSString *accessibilityLabel;
/// (可选)标记一个元素的无障碍元素的详细描述 如 (轻点两下与xxx人一起点赞,轻点两下将视频添加到收藏列表)
@property (nullable, nonatomic, copy) NSString *accessibilityHint;
/// (可选)标记一个元素的无障碍元素的具体值,如50%等
@property (nullable, nonatomic, copy) NSString *accessibilityValue;
/// (可选)标记一个元素的无障碍特征 如(按钮、标签夹等)
@property (nonatomic) UIAccessibilityTraits accessibilityTraits;
/// (可选)自定义一个元素的无障碍模式下的焦点大小
@property (nonatomic) CGRect accessibilityFrame;
@end

UIAccessibilityAction 无障碍手势响应

@interface NSObject (UIAccessibilityAction)
/// 自定义无障碍事件,可以使点击事件与普通用户隔离。
- (BOOL)accessibilityActivate API_AVAILABLE(ios(7.0));
/// 当元素被定义为可变元素时,可以实现下面的方法。如音量、亮度调节器。
- (void)accessibilityIncrement API_AVAILABLE(ios(4.0));
- (void)accessibilityDecrement API_AVAILABLE(ios(4.0));
- (BOOL)accessibilityScroll:(UIAccessibilityScrollDirection)direction API_AVAILABLE(ios(4.2));
/// 通常浮窗或页面需要实现该方法,实现该方法后用户可以使用“Z”字形手势退出页面
- (BOOL)accessibilityPerformEscape API_AVAILABLE(ios(5.0));
/// 该方法可以接收到用户的双指双击事件。可以用于弹出更多面板 or 定义一些重要操作如 暂停。
- (BOOL)accessibilityPerformMagicTap API_AVAILABLE(ios(6.0));
/// 转子的核心方法,给accessibilityCustomActions赋值后可以上下轻扫访问转子
@property (nullable, nonatomic, strong) NSArray <UIAccessibilityCustomAction *> *accessibilityCustomActions API_AVAILABLE(ios(8.0));
@end

UIAccessibilityFocus 无障碍焦点响应

@interface NSObject (UIAccessibilityFocus)
/// 焦点响应事件,可以捕获元素是否成为了焦点。通常重写这两个方法。
- (void)accessibilityElementDidBecomeFocused API_AVAILABLE(ios(4.0));
- (void)accessibilityElementDidLoseFocus API_AVAILABLE(ios(4.0));
/// 可以判断该元素是否被聚焦,通常不要处理该方法。
- (BOOL)accessibilityElementIsFocused API_AVAILABLE(ios(4.0));
@end

UIAccessibilityContainer 无障碍自定义焦点

@interface NSObject (UIAccessibilityContainer)
/// 返回当前容器无障碍元素的总数
- (NSInteger)accessibilityElementCount NS_SWIFT_UI_ACTOR;
/// 返回对应index的元素
/// 需要保证返回的是真实存在的实例(不能为alloc出来的)
- (nullable id)accessibilityElementAtIndex:(NSInteger)index NS_SWIFT_UI_ACTOR;
/// 返回对应元素的index
- (NSInteger)indexOfAccessibilityElement:(id)element NS_SWIFT_UI_ACTOR;
️如果使用上面的三个方法,一般需要同时全部实现。
️如果实现了上面的三个方法,那么就不要再手动设置accessibilityElements
/// 容器的无障碍元素List,设置后页面无障碍元素范围将会被限制在List内,顺序与List内元素顺序相同。
@property (nullable, nonatomic, strong) NSArray *accessibilityElements API_AVAILABLE(ios(8.0)) NS_SWIFT_UI_ACTOR;
/// default == UIAccessibilityContainerTypeNone,绝大多数情况保持None即可。如果手动设置Type则需要实现对于Type的指定协议。
@property (nonatomic) UIAccessibilityContainerType accessibilityContainerType API_AVAILABLE(ios(11.0)) NS_SWIFT_UI_ACTOR;
@end

五、常见问题与解决方案

该部分根据西瓜真实的业务实践,列举了数个常见无障碍问题的修复方案。例如:焦点目的不明确、焦点乱跳问题、嵌套容器 ScrollView 无法跟随滚动等。

焦点缺失/焦点冗余

焦点缺失是无障碍 Bug 中最基础但最严重的问题。极端情况情况下会产生致命的阻塞性的 Bug(如返回按钮缺失焦点)。通常而言产品上一些按钮、链接、勾选框、图片、编辑框等需要焦点方便用户交互。

此外焦点冗余也会严重影响用户的使用体验,一些装饰性元素焦点冗余后,用户的信息筛选效率会严重降低。通常而言,用户点击后无明确响应事件的组件不应该成为焦点。

「解决方法」:一般情况下,系统会自动给标准控件 UIButton 等交互控件添加焦点,其他自定义控件需要手动添加/更改。一般情况下手动指定属性isAccessibilityElement为 YES 或者 NO 可解决该问题。

self.isAccessibilityElement = YES;
self.accessibilityLabel = @"点赞";  // 通常焦点描述也会缺失,需要一并补充。
/// 对于一些自定义的UI控件,也可以重写上述两个对象的Get方法。
- (NSString *)accessibilityLabel {
    return @"点赞";
}
- (BOOL) isAccessibilityElement {
    return YES;
}

焦点过细/焦点合并

焦点合并指的是有相同目的、相同操作的,或具有组合意义的组合视图,焦点没有合并的情况,问题描述为“合并焦点”。例如,好友列表中的好友头像和昵称应合并为一个焦点,二者功能都一样,都是跳转到个人资料界面。

「解决方法」:在需要合并焦点的 superView 处将 isAccessibilityElement 设置为 YES。

self.isAccessibilityElement = YES;

焦点信息错误 (目的不明确,信息冗余等)

焦点目的不明确是指页面中的焦点仅朗读出基本文案,但是未朗读该控件的类型(按钮、标签栏、链接等),或者未朗读该焦点响应后会发生的事件(轻点两下进入详情页播放视频等)。

「解决方法」:参照产品的无障碍标注规范。调整问题焦点的 accessibilityLabel、accessibilityTraits、accessibilityHint 等字段,从而使焦点信息朗读准确。

/// Button
// 点赞按钮未被选中时
self.accessibilityTraits = UIAccessibilityTraitButton;
self.accessibilityHint = @"轻点两下与xxx人一同点赞";
// 点赞按钮被选中时
self.accessibilityTraits = UIAccessibilityTraitButton|UIAccessibilityTraitSelected;
self.accessibilityHint = @"轻点两下取消点赞";
///TabBar(包括顶Tab和底Tab)
// 当对象为TabBar
self.accessibilityTraits = UIAccessibilityTraitTabBar
// 被选中的TabBar
self.accessibilityTraits = UIAccessibilityTraitTabBar|UIAccessibilityTraitSelected;

焦点停留不当

页面刷新后跑焦点、对视图或控件进行操作后跑焦点,打开新界面焦点停留的位置不适当,问题描述为“焦点停留不当”。例如进入一些页面后,焦点默认停留在原位置,或者停留在新页面的返回按钮。

「解决方法」:在进入界面时将 VoiceOver 焦点定位到特定控件。可以使用UIAccessibilityPostNotification发送通知给特定控件,改变 voiceOver 焦点。

@implementation MyViewController
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification,
self.myFirstElement);
}
@end

焦点顺序错误问题

焦点顺序不符合逻辑顺序时,通常描述为:“焦点顺序不符合逻辑顺序”;焦点顺序不符合视觉顺序时,描述为“焦点顺序不符合视觉顺序”。

「解决方法」:手动设置 accessibilityElements。极端场景下可以主动实现 UIAccessibilityContainer 协议。

/// 普通场景. 切勿在TableView的Cell中使用
self.accessibilityElements = @[View1,View2,View3];
/// 复杂场景,务必将三个方法都实现,否则容易出现意料之外的问题
- (NSInteger)accessibilityElementCount {
    return 3;
}
- (nullable id)accessibilityElementAtIndex:(NSInteger)index {
    return Views[index];
}
- (NSInteger)indexOfAccessibilityElement:(id)element {
    return [Views indexOfObject:element];
}

焦点选中时乱跳问题

该问题主要发生在 CollectionView 上,一般现象为调整一个 Cell 的选中态并 reloadData,焦点会先转移到一个随机的位置(一般是选中 Cell 的后一个),而后再跳回正确的位置。

「解决方法」:慎用 UICollectionView、UITableView 的 reloadData。当需要刷新 Cell 的选中状态时,尽量自己实现一个 updateVisibleCell。reloadData 时会导致 Cell 随机复用,最终产生焦点乱跳的异常。

[self reloadData];

[self updateVisibleCells];
- (void)updateVisibleCells {
  NSArray<UICollectionViewCell *> *visibleCells = self.collectionView.visibleCells;
  [visibleCells enumerateObjectsUsingBlock:^(UICollectionViewCell * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    // Todo something
  }];
}

浮窗问题 / 焦点被覆盖时仍可访问

在西瓜视频中,浮窗有多种不同的存在形式,如 XIGAlert(隐私弹窗等)、XIGToast(网络异常等)、半屏浮窗(键盘、清晰度面板、倍速面板等)。在弹窗出现时,用户可以通过左右滑动切换焦点至不可视的视图。这些视图产生的相关事件可能会使程序崩溃,发生一些意料之外的事情。

「解决方法」:一般做法为让底层控件元素失去焦点来达到屏蔽底层元素的效果,将灰色变暗区域设为单个大焦点,标签设为 “关闭” 或 “收起” 等提示,双击可关闭浮层。弹窗或弹层时,自动使上层容器的第一控件(如标题或通知内容)获取焦点,视障用户无须二次切换焦点,更符合视障用户使用体验,更加体现人性化。

self.accessibilityViewIsModal = YES

对蒙层设置属性,会使蒙层的同级 view不响应 VoiceOver,而蒙层的子 view 可响应。如下图所示,如果希望 E 可以被访问,CD 不可被访问,此时需要设置 B 的accessibilityViewIsModal为 YES。

嵌套容器 ScrollView 无法跟随滚动问题

在 UICollectionView 中,嵌套一个 UIScrollView 或者 UITableView,焦点在 TableView、ScrollView 中滑动时,不会发生自动滚动,从而导致页面发生白屏等现象。

「解决方法」:使用 accessibilityActivate,在焦点聚焦到一个 Cell 上的时候,手动调用

scrollToRowAtIndexPath: atScrollPosition: animated:

如果一个 Cell 中包含多个功能,Cell 还需要进行转子适配。

- (BOOL)accessibilityElementDidBecomeFocused {
   [self.tableview scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionNone animated:NO];
   return YES;
}

横滑拖拽问题(手势替代问题)

在应用中有许多场景有横滑手势,如横滑删除,横滑编辑等。此类事件在 Voice Over 开启时无法被响应。故需要通过一些其他手段使用户能够访问到横滑的功能。

「解决方法」:使用转子对功能进行改造。

UIAccessibilityCustomAction * action1 = [[UIAccessibilityCustomAction alloc] initWithName:@"进入详情页" target:self selector:@selector(action1)];
UIAccessibilityCustomAction * action2 = [[UIAccessibilityCustomAction alloc] initWithName:@"删除该视频" target:self selector:@selector(action2)];
UIAccessibilityCustomAction * action3 = [[UIAccessibilityCustomAction alloc] initWithName:@"隐藏该视频" target:self selector:@selector(action3)];
self.accessibilityCustomActions = @[action1,action2,action3];

以上就是iOS无障碍适配西瓜视频Voice Over实践示例的详细内容,更多关于iOS适配Voice Over的资料请关注我们其它相关文章!

(0)

相关推荐

  • iOS开发————详解适配iOS10问题

    2016年9月7日,苹果发布iOS 10.2016年9月14日,全新的操作系统iOS 10将正式上线. 作为开发者,如何适配iOS10呢? 1.Notification(通知) 自从Notification被引入之后,苹果就不断的更新优化,但这些更新优化只是小打小闹,直至现在iOS 10开始真正的进行大改重构,这让开发者也体会到UserNotifications的易用,功能也变得非常强大. •iOS 9 以前的通知 1.在调用方法时,有些方法让人很难区分,容易写错方法,这让开发者有时候很苦恼.

  • iOS开发教程之常见的性能优化技巧

    前言 性能问题的主要原因是什么,原因有相同的,也有不同的,但归根到底,不外乎内存使用.代码效率.合适的策略逻辑.代码质量.安装包体积这一类问题. 但从用户体验的角度去思考,当我们置身处地得把自己当做用户去玩一款应用时候,那么都会在意什么呢?假如正在玩一款手游,首先一定不希望玩着玩着突然闪退,然后就是不希望卡顿,其次就是耗电和耗流量不希望太严重,最后就是安装包希望能小一点.简单归类如下: 快:使用时避免出现卡顿,响应速度快,减少用户等待的时间,满足用户期望. 稳:不要在用户使用过程中崩溃和无响应.

  • iOS无障碍适配西瓜视频Voice Over实践示例

    目录 一.Voice Over 简介 二.Voice Over 使用指南 Voice Over 开发环境配置 Voice Over 基本使用 —— 以西瓜为例 入门手势 进阶手势 三.快速适配 Voice Over / 无障碍 设置无障碍焦点 设置无障碍文案 调整焦点顺序 西瓜首页适配实战 搜索栏 频道栏 & 频道编辑器 作者动态栏 视频列表 四.Voice Over 相关协议介绍 UIAccessibility 无障碍标签标注 UIAccessibilityAction 无障碍手势响应 UIA

  • IOS 屏幕适配方案实现缩放window的示例代码

    背景: 公司有个iPad项目(只支持横屏),是11年开发的,那时的iPad只有1024x768的分辨率,所以没有屏幕适配的问题,frame都是写死的.后来不同尺寸的iPad相继出现,本来应该会出现屏幕不能适配的问题,但是由于该项目没有设置启动图,页面会自动等比例缩放撑满整个屏幕,各分辨率的宽高比相差不多,所以并没有出现太大问题.但是2020年3月4日,苹果要求所有提交至 App Store 的 app 都须使用 Xcode storyboard(故事板) 来提供 app 的启动屏幕,之前的不设置

  • iOS WKWebView适配实战篇

    一.Cookie适配 1.现状 WKWebView适配中最麻烦的就是cookie同步问题 WKWebView采用了独立存储控件,因此和以往的UIWebView并不互通 虽然iOS11以后,iOS开放了WKHTTPCookieStore让开发者去同步,但是还是需要考虑低版本的 同步问题,本章节从各个角度切入考虑cookie同步问题 2.同步cookie(NSHTTPCookieStorage->WKHTTPCookieStore) iOS11+ 可以直接使用WKHTTPCookieStore遍历方

  • python3.5+tesseract+adb实现西瓜视频或头脑王者辅助答题

    最近的答题赢钱很火爆,我也参与了几次,有些题目确实很难答,但是10秒钟的时间根本不够百度的,所以写了个辅助挂,这样可以出现题目时自动百度,这个时间也就花掉2秒钟,剩下的7.8秒钟可以进行分析和作答,提升了赢钱概率. 源码可以见我的github:点击链接 原理分析下:使用adb命令,抓取手机视频播放的界面,然后通过python的截取和ocr,获得到题目和答案, 然后百度得到结果.这个环境怎么搭建,有需要的童鞋可以联系我,因为使用本地的ocr所以解析不花钱,也没有使用的限制. github上的代码中

  • iOS使用AVFoundation展示视频

    本文实例为大家分享了iOS使用AVFoundation展示视频的具体代码,供大家参考,具体内容如下 // // Capter2ViewController.m // IosTest // // Created by garin on 13-7-19. // Copyright (c) 2013年 garin. All rights reserved. // #import "Capter2ViewController.h" @interface Capter2ViewControlle

  • iOS 13适配汇总(推荐)

    随着iPhone 11的发布,iOS 13适配也提上了日程,接下来就开发中升级iOS13的手机可能出现的问题 Xcode: 11.0 iOS : 13.0 UIViewController 模态弹出界面 viewController.present(presentVC, animated: true, completion: nil) 在调用模态弹出视图,会发现弹出的界面没有全屏.如图 通过多次的尝试,发现在低版本里面不会发生这种情况(iOS12及以下),于是我查阅了最新的开发文档,发现了端倪,

  • Python 给我一个链接西瓜视频随便下载爬虫

    1.实现原理 首先,我们需要来到西瓜视频的官网,链接为:西瓜视频,随便点击其中一个视频进入,点击电脑键盘的F12来到开发者模式,按ctrl+F进行搜索,输入video,如下: 我们可以发现,这里有一个视频链接,我们点击这个链接进入,依旧按电脑F12键来到开发者模式,继续搜索video,可以发现,这里直接有视频的下载链接,如下: 我们是不是只要运用代码就可以找到视频的下载链接呢?不过,由于上述图片这些视频下载链接是动态加载的,这里需要用到selenium模块哈!不懂这个模块的 读者可以看看小编之前

  • Python 超简洁且详细爬取西瓜视频案例

    一.写在前面 真的,为什么别人发游戏这么多人看,我发了两次了加起来才一百个. 算了算了,不整游戏了,反正你们也不爱看~ 今天来试试把头条上扭腰上热门的那些妹子爬一爬,不知道我顶不顶得住~ 二.准备工作 1.使用的环境 python 3.8pycharm 2021.2 专业版 2.要用的第三方模块 seleniumrequestsparsel 三.大致流程 鉴于你们不喜欢我啰嗦,但是流程呢,我还是要给你们写出来,所以我就单独把它列出来了. 1.网站分析(明确需求) 在视频网页源代码当中找到 emb

  • Python 超简洁且详细爬取西瓜视频案例

    一.写在前面 真的,为什么别人发游戏这么多人看,我发了两次了加起来才一百个. 算了算了,不整游戏了,反正你们也不爱看~ 今天来试试把头条上扭腰上热门的那些妹子爬一爬,不知道我顶不顶得住~ 二.准备工作 1.使用的环境 python 3.8 pycharm 2021.2 专业版 2.要用的第三方模块 selenium requests parsel 三.大致流程 鉴于你们不喜欢我啰嗦,但是流程呢,我还是要给你们写出来,所以我就单独把它列出来了. 1.网站分析(明确需求) 在视频网页源代码当中找到

  • Python爬取视频时长场景实践示例

    目录 简介: 获取视频时长的方式 安装 获取视频时长的3种方式对比 简介: 在视频相关测试场景下,例如:有时需要知道全部视频的汇总时长,显然一个个打开并且手工计算耗时耗力,我们可以通过编写脚本进行快速汇总. 获取视频时长的方式 1.通过subprocess进行获取. 2.通过moviepy库中VideoFileClip获取. 3.通过cv2库获取. 安装 1.subprocess:无需安装,Python内置. 2.moviepy:pip install moviepy. 3.cv2:pip in

随机推荐