app横屏之后适配错误 ios
2018-09-03 16:42:00 weixin_33857230 阅读数 23

屏幕的横竖屏适配有很多种,今天写直播demo的时候发现给播放器一套约束或者frame,自动切换横屏的时候布局混乱拉伸。

这第一种方法,直接监听横竖屏切换,然后改变布局代码,纯代码布局基本都是这个思路。

/** 注册屏幕横竖通知 */

//开启和监听 设备旋转的通知(不开启的话,设备方向一直是UIInterfaceOrientationUnknown)
    if (![UIDevice currentDevice].generatesDeviceOrientationNotifications) {
        [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
    }
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(handleDeviceOrientationChange:)
                                                name:UIDeviceOrientationDidChangeNotification object:nil];

/** 通知事件处理 */

//设备方向改变的处理
- (void)handleDeviceOrientationChange:(NSNotification *)notification{
    UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
    switch (ddeviceOrientation) {
        case UIDeviceOrientationFaceUp:
            NSLog(@"屏幕朝上平躺");
            break;
        case UIDeviceOrientationFaceDown:
            NSLog(@"屏幕朝下平躺");
            break;
        case UIDeviceOrientationUnknown:
            NSLog(@"未知方向");
            break;
        case UIDeviceOrientationLandscapeLeft:{
            NSLog(@"屏幕向左横置");
            //以左横为例,改变frame的话可以加动画,也可以用masonry处理(mas_remake),视情况选择,一般来说不需要每种情况都处理,左横右横直立三种就差不多了。
                [UIView animateWithDuration:1.0 animations:^{
                    _player.view.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
                }];
                
                [_player.view mas_remakeConstraints:^(MASConstraintMaker *make) {
                    make.top.mas_equalTo(0);
                    make.left.mas_equalTo(0);
                    make.size.mas_equalTo(CGSizeMake([UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height));
                }];
}
            break;
        case UIDeviceOrientationLandscapeRight:
            NSLog(@"屏幕向右橫置");
            break;
        case UIDeviceOrientationPortrait:
            NSLog(@"屏幕直立");
            break;
        case UIDeviceOrientationPortraitUpsideDown:
            NSLog(@"屏幕直立,上下顛倒");
            break;
        default:
            NSLog(@"无法辨识");
            break;
    }
}

/** 最后在dealloc中移除通知 和结束设备旋转的通知 */

- (void)dealloc{
    //...
    [[NSNotificationCenter defaultCenter]removeObserver:self];
    [[UIDevice currentDevice]endGeneratingDeviceOrientationNotifications];
}

/** 提示一下,需要记住以下几种方法,这些方法都是tabbar navigation viewcontroller 层层传递,具体使用另行查阅资料*/

- (BOOL)shouldAutorotate{
    //是否自动旋转,返回YES可以自动旋转,返回NO禁止旋转
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations{
    //返回支持的方向
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation{
    //由模态推出的视图控制器 优先支持的屏幕方向
}
第二种就是xib创建的视图,Trait Variations其实就是iOS8.0之后取代sizeClass而已,具体的东西得自己去研究。

拖入控件后,勾上此处的width,然后开始布局添加约束,添加完之后点击Down Varying,此间添加的所有约束就只针对竖屏生效,反之点击height,约束就对横屏生效。


10845361-f918ee2bfe4227e6.png
image.png

10845361-a9b60dd9ce40679a.png
image.png
第三种,还是xib,针对一个约束添加多个不同优先级的约束,把约束关联到代码里面,然后跟第一种方法一样监听横屏,再把约束的优先级更改,便可使相应优先级的约束生效(默认第一优先级1000生效),如图默认约束为60,49为次优先级,可在代码中使其生效。

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *testConstraint;
_testConstraint.priority = UILayoutPriorityDefaultLow;

10845361-12b39c3220731197.png
image.png

第四种,随便提一下就行,在我看来也就是sizeClass和第二种一样的,如下图,竖屏状态是wC:hR 横屏下是wC:hC (w是width h是height,C是Compact R是Regular) ,可以针对横屏和竖屏分别添加或修改约束值。

注意:不管是第二种还是第四种,如果在拖入控件之前就限制了方向,那么你就会发现切换到另一种方向的时候此控件是不存在的。只有拖入控件时installed选中或者第二种没有操作,才会两种状态都存在控件,运行也是一样的效果。具体操作坑还是比较多的,所以需要自己去实践,这里只提供一个思路。

10845361-4dbbf069ec682664.png
image.png
2014-12-05 13:58:06 u013243469 阅读数 1848
//取最小值  
#define SCREEN_WIDTH	     MIN(CGRectGetWidth([[UIScreen mainScreen] bounds]),CGRectGetHeight([[UIScreen mainScreen] bounds]))
//取最大值
#define SCREEN_HEIGHT        MAX(CGRectGetWidth([[UIScreen mainScreen] bounds]),CGRectGetHeight([[UIScreen mainScreen] bounds]))

原理分析:
     在iOS7中,获取到的当前物理屏幕宽高是固定的  高:1024   宽:768   不论横竖屏
     在iOS8中,获取到的当前物理屏幕宽高是不固定的,即:
                                        竖屏: 高:1024    宽:768
                                        横屏: 高:768     宽:1024

所以  以上方法也要再判断横竖屏的情况下使用,但是这种写法在根本上已经写死了,也就是说,无论iOS7还是iOS8  高都是1024  宽都是768 
2017-08-23 11:12:00 weixin_34008784 阅读数 42

在做CollectionView横屏适配之前需要导入第三方库Masonry,这个第三方还是很好用的.

ViewController.m

#import "myCollectionViewCell.h"//需要重写

#import<Masonry.h>

#import "Head.h"//页眉

#import "Foot.h"//页脚

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {

[super viewDidLoad];

// Do any additional setup after loading the view, typically from a nib.

//创建

UICollectionViewFlowLayout *bj = [[UICollectionViewFlowLayout alloc]init];

bj.itemSize = CGSizeMake(80, 80);

bj.headerReferenceSize = CGSizeMake(40, 30);

bj.footerReferenceSize = CGSizeMake(40, 30);

//创建CollectionView对象

UICollectionView *cv = [[UICollectionView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height) collectionViewLayout:bj];

cv.delegate = self;

cv.dataSource = self;

[self.view addSubview:cv];

//适配可横屏

[cv mas_makeConstraints:^(MASConstraintMaker* make)

{

make.edges.equalTo(self.view);

}];

//为CollectionView注册单元格

[cv registerClass:[myCollectionViewCell class] forCellWithReuseIdentifier:@"myCollectionViewCell"];

//为CollectionView注册页眉类

[cv registerClass:[Head class] forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"Head"];

//为CollectionView注册页脚类

[cv registerClass:[Foot class] forSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"Foot"];

}

//设置页眉或页脚

-(UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath{

UICollectionReusableView * theReusable = nil;

if ([kind isEqualToString:UICollectionElementKindSectionHeader]) {

//获取可以重用的页眉对象,如果没有,就自动创建

theReusable = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"Head" forIndexPath:indexPath];

Head * theHeader = (Head *)theReusable;

theHeader.theTitleLabel.text = @"页眉";

}else if ([kind isEqualToString:UICollectionElementKindSectionFooter]){

theReusable = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"Foot" forIndexPath:indexPath];

Foot * theFooter = (Foot *)theReusable;

theFooter.theTitleLabel.text = @"页脚";

}

return theReusable;

}

-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section

{

return 30;

}

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath

{

myCollectionViewCell *theCell = [collectionView dequeueReusableCellWithReuseIdentifier:@"myCollectionViewCell" forIndexPath:indexPath];

theCell.theImg.image = [UIImage imageNamed:@"1.jpg"];

return theCell;

}

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath

{

NSLog(@"section:%ld, row:%ld",indexPath.section,indexPath.row);

}


myCollectionViewCell.h

#import<UIKit/UIKit.h>

@interface myCollectionViewCell : UICollectionViewCell

@property(nonatomic,strong)UIImageView * theImg;

//@property(nonatomic,strong)UILabel * theLabel;

@end

.m重写

-(instancetype)initWithFrame:(CGRect)frame{

if (self = [super initWithFrame:frame]) {

[self addSubview:self.theImg];

//        [self addSubview:self.theLabel];

}

return self;

}

-(UIImageView *)theImg{

if (!_theImg) {

_theImg = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 80, 80)];

_theImg.layer.cornerRadius = 40;

[_theImg.layer setMasksToBounds:YES];

}

return _theImg;

}

Head.h

@interface Head : UICollectionReusableView

@property(nonatomic,strong)UILabel * theTitleLabel;

@end

.m

-(instancetype)initWithFrame:(CGRect)frame{

if (self = [super initWithFrame:frame]) {

[self addSubview:self.theTitleLabel];

}

return self;

}

-(UILabel *)theTitleLabel{

if (!_theTitleLabel) {

_theTitleLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 200, 20)];

_theTitleLabel.textColor = [UIColor whiteColor];

}

return _theTitleLabel;

}

Foot.h

@interface Foot : UICollectionReusableView

@property(nonatomic,strong)UILabel * theTitleLabel;

@end

.m

-(instancetype)initWithFrame:(CGRect)frame{

if (self = [super initWithFrame:frame]) {

[self addSubview:self.theTitleLabel];

}

return self;

}

-(UILabel *)theTitleLabel{

if (!_theTitleLabel) {

_theTitleLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, 200, 20)];

_theTitleLabel.textColor = [UIColor whiteColor];

}

return _theTitleLabel;

}

其实CollectionView还是很好做的,与tableView近乎百分百相似,只要掌握tableView后,CollectionView也是很容易就上手的.

2017-08-29 19:44:13 Keep_Moving31038 阅读数 1491

导语:iOS 11 为整个生态系统的 UI 元素带来了一种更加大胆、动态的新风格。 本文介绍iOS11中在UI方面做了哪些更新,有些更新可以为用户提供更加完美的体验,但也有的可能会给目前的APP带来异常bug

前言

前几天发现在做的APP在 iOS11 系统上动画有异常,在其他系统的设备上都是正常的,动画的操作是观察tableViewcontentOffset变化后执行的,异常动画发生在tableView reloadData之后,也就是说tableView reloadData之后,tableViewcontentOffset发生了几次变化。查了下资料发现原因是 iOS11 中默认开启了Self-Sizing,在WWDC 2017 session204 Updating Your App for iOS 11 中有介绍,因此研究了下这个session,本文作为一个总结,下文的第三部分会有对上述的动画异常的原因分析及解决方式。

本文内容包括:集成了搜索的大标题栏、横向选项卡栏、Margins 和 Insets以及 UIScrollViewUITableView 的更新和功能更强大的滑动操作。

一. 在UIKit’s Bars中加入的新功能

WWDC通过iOS新增的文件管理App:Files开始介绍,在Files这个APP中能够看到iOS11中UIKit’s Bars的一些新特性:在浏览功能上的大标题视图(向上滑动后标题会回到原来的UI效果)、横屏状态下tab上的文字和icon会变为左右排列。我用iOS11的模拟器体验了一下Files这个APP的竖屏和横屏,如下图所示:

(command+向左的箭头让模拟器横屏)

横屏时,在iPhone上,tab上的图标较小,tab bar较小,这样垂直空间可多放置内容。如果有人看不清楚tab bar上的图标或文字,可以通过长按tab bar上的任意item,会将该item显示在HUD上,这样可以清楚的看清icon和text。对tool bar 和 navigation bar同理,长按item也会放大显示。如下图显示:

UIBarItem

UIBarItem是UI tab bar item和UI bar button item的父类,要想实现上面介绍的效果,只需要为UIBarItem 设置landscapeImagePhone属性,在storyboard中也支持这个设置,对于HUD的image需要设置另一个iOS11新增的属性:largeContentSizeImage,关于这部分更详细的讨论,可以参考 WWDC2017 Session 215:What’s New in Accessibility

控制大标题的显示

在UI navigation bar中新增了一个BOOL属性prefersLargeTitles,将该属性设置为ture,navigation bar就会在整个APP中显示大标题,如果想要在控制不同页面大标题的显示,可以通过设置当前页面的navigationItemlargeTitleDisplayMode属性;

typedef NS_ENUM(NSInteger, UINavigationItemLargeTitleDisplayMode) {  
/// 自动模式依赖上一个 item 的特性
UINavigationItemLargeTitleDisplayModeAutomatic,
/// 针对当前 item 总是启用大标题特性
UINavigationItemLargeTitleDisplayModeAlways,
/// Never 
UINavigationItemLargeTitleDisplayModeNever,
}

Navigation 集成 UISearchController

把你的UISearchController赋值给navigationItem,就可以实现将UISearchController集成到Navigation

navigationItem.searchController  //iOS 11 新增属性
navigationItem.hidesSearchBarWhenScrolling //决定滑动的时候是否隐藏搜索框;iOS 11 新增属性

UINavigationController和滚动交互

滚动的时候,以下交互操作都是由UINavigationController负责调动的:

  1. UIsearchController搜索框效果更新
  2. 大标题效果的控制
  3. Rubber banding效果 //当你开始往下拉,大标题会变大来回应那个滚轮

所以,如果你使用navigation bar,组装push和pop体验,你不会得到searchController的集成、大标题的控制更新和Rubber banding效果,因为这些都是由UINavigationController控制的。

UIToolbar and UINavigationBar— Layout

在 iOS 11 中,当苹果进行所有这些新特性时,也进行了其他的优化,针对 UIToolbar 和 UINavigaBar 做了新的自动布局扩展支持,自定义的bar button items、自定义的title都可以通过layout来表示尺寸。 需要注意的是,你的constraints需要在view内部设置,所以如果你有一个自定义的标题视图,你需要确保任何约束只依赖于标题视图及其任何子视图。当你使用自动布局,系统假设你知道你在做什么。

Avoiding Zero-Sized Custom Views

自定义视图的size为0是因为你有一些模糊的约束布局。要避免视图尺寸为0,可以从以下方面做:

  • UINavigationBar 和 UIToolbar 提供位置
  • 开发者则必须提供视图的size,有三种方式:

    • 对宽度和高度的约束;
    • 实现 intrinsicContentSize;
    • 通过约束关联你的子视图;

二. 管理margins 和 insets

layout margins

基于约束的Auto Layout,使我们搭建能够动态响应内部和外部变化的用户界面。Auto Layout为每一个view都定义了marginmargin指的是控件显示内容部分的边缘和控件边缘的距离。 可以用layoutMargins或者layoutMarginsGuide属性获得view的margin,margin是视图内部的一部分。layoutMargins允许获取或者设置UIEdgeInsets结构的marginlayoutMarginsGuide则获取到只读的UILayoutGuide对象。

在iOS11新增了一个属性:directional layout margins,该属性是NSDirectionalEdgeInsets结构体类型的属性:

typedef struct NSDirectionalEdgeInsets {  
    CGFloat top, leading, bottom, trailing;
} NSDirectionalEdgeInsets API_AVAILABLE(ios(11.0),tvos(11.0),watchos(4.0));

layoutMarginsUIEdgeInsets结构体类型的属性:

typedef struct UIEdgeInsets {  
CGFloat top, left, bottom, right;
} UIEdgeInsets;

从上面两种结构体的对比可以看出,NSDirectionalEdgeInsets 属性用leading 和 trailing 取代了之前的 left 和 right。

directional layout margins属性的说明如下:

directionalLayoutMargins.leading is used on the left when the user interface direction is LTR and on the right for RTL.

Vice versa for directionalLayoutMargins.trailing.

例子:当你设置了trailing = 30;当在一个right to left 语言下trailing的值会被设置在view的左边,可以通过layout margins的left属性读出该值。如下图所示:

还有其他一些更新。自从引入layout margins,当将一个view添加到viewController时,viewController会修复view的layoutMargins为UIKit定义的一个值,这些调整对外是封闭的。从iOS11开始,这些不再是一个固定的值,它们实际是最小值,你可以改变你的view的layoutMargins为任意一个更大的值。而且,viewController新增了一个属性:viewRespectsSystemMinimumLayoutMargins,如果你设置该属性为”false”,你就可以改变你的layout margins为任意你想设置的值,包括0,如下图所示:

安全区域(Safe Area)

如下图:照片应用程序

从iOS 7以来,我们在整个操作系统中都有这些半透明的bars,苹果鼓励我们通过这些bars绘制内容,我们是通过viewController 的edgesForExtendedLayout属性来做这些的。

iOS 7 开始,在 UIViewController中引入的 topLayoutGuide和 bottomLayoutGuide 在 iOS 11 中被废弃了,取而代之的就是safeArea的概念,safeArea是描述你的视图部分不被任何内容遮挡的方法。 它提供两种方式:safeAreaInsetssafeAreaLayoutGuide来提供给你safeArea的参照值,即 insets 或者 layout guide。 safeArea区域如下图所示:

如果有一个自定义的viewController,你可能要添加你自己的bars,增加safeAreaInsets的值,可以通过一个新的属性:addtionalSafeAreaInsets来改变safeAreaInsets的值,当你的viewController改变了它的safeAreaInsets值时,有两种方式获取到回调:

UIView.safeAreaInsetsDidChange()
UIViewController.viewSafeAreaInsetsDidChange()

三. UIScrollView and UITableView的新特性

Scroll Views

如果有一些文本位于UI滚动视图的内部,并包含在导航控制器中,现在一般navigationContollers会传入一个contentInset给其最顶层的viewController的scrollView,在iOS11中进行了一个很大的改变,不再通过scrollView的contentInset属性了,而是新增了一个属性:adjustedContentInset,下面的两张图的对比能够表示adjustContentInset表示的区域:

新增的contentInsetAdjustmentBehavior属性用来配置adjustedContentInset的行为,该结构体有以下几种类型:

typedef NS_ENUM(NSInteger, UIScrollViewContentInsetAdjustmentBehavior) {  
    UIScrollViewContentInsetAdjustmentAutomatic, 
    UIScrollViewContentInsetAdjustmentScrollableAxes,
    UIScrollViewContentInsetAdjustmentNever,
    UIScrollViewContentInsetAdjustmentAlways,
}
@property(nonatomic) UIScrollViewContentInsetAdjustmentBehavior contentInsetAdjustmentBehavior;
@property(nonatomic, readonly) UIEdgeInsets adjustedContentInset;
//adjustedContentInset值被改变的delegate
- (void)adjustedContentInsetDidChange; 
- (void)scrollViewDidChangeAdjustedContentInset:(UIScrollView *)scrollView;

Table Views :在iOS 11中默认启用Self-Sizing

这个应该是UITableView最大的改变。我们知道在iOS8引入Self-Sizing 之后,我们可以通过实现estimatedRowHeight相关的属性来展示动态的内容,实现了estimatedRowHeight属性后,得到的初始contenSize是个估算值,是通过estimatedRowHeight x cell的个数得到的,并不是最终的contenSizetableView就不会一次性计算所有的cell的高度了,只会计算当前屏幕能够显示的cell个数再加上几个,滑动时,tableView不停地得到新的cell,更新自己的contenSize,在滑到最后的时候,会得到正确的contenSize。在测试Demo中,创建tableView到显示出来的过程中,contentSize的计算过程如下图:

Self-Sizing在iOS11下是默认开启的,Headers, footers, and cells都默认开启Self-Sizing,所有estimated 高度默认值从iOS11之前的 0 改变为UITableViewAutomaticDimension

@property (nonatomic) CGFloat estimatedRowHeight NS_AVAILABLE_IOS(7_0); // default is UITableViewAutomaticDimension, set to 0 to disable

如果目前项目中没有使用estimateRowHeight属性,在iOS11的环境下就要注意了,因为开启Self-Sizing之后,tableView是使用estimateRowHeight属性的,这样就会造成contentSize和contentOffset值的变化,如果是有动画是观察这两个属性的变化进行的,就会造成动画的异常,因为在估算行高机制下,contentSize的值是一点点地变化更新的,所有cell显示完后才是最终的contentSize值。因为不会缓存正确的行高,tableView reloadData的时候,会重新计算contentSize,就有可能会引起contentOffset的变化。

iOS11下不想使用Self-Sizing的话,可以通过以下方式关闭:(前言中提到的问题也是通过这种方式解决的)

self.tableView.estimatedRowHeight = 0;
self.tableView.estimatedSectionHeaderHeight = 0;
self.tableView.estimatedSectionFooterHeight = 0;

iOS11下,如果没有设置estimateRowHeight的值,也没有设置rowHeight的值,那contentSize计算初始值是 44 * cell的个数,如下图:rowHeight和estimateRowHeight都是默认值UITableViewAutomaticDimension 而rowNum = 15;则初始contentSize = 44 * 15 = 660;

Table Views:separatorInset 扩展

iOS 7 引入separatorInset属性,用以设置 cell 的分割线边距,在 iOS 11 中对其进行了扩展。可以通过新增的UITableViewSeparatorInsetReference枚举类型的separatorInsetReference属性来设置separatorInset属性的参照值。

typedef NS_ENUM(NSInteger, UITableViewSeparatorInsetReference) {  
UITableViewSeparatorInsetFromCellEdges,   //默认值,表示separatorInset是从cell的边缘的偏移量
UITableViewSeparatorInsetFromAutomaticInsets  //表示separatorInset属性值是从一个insets的偏移量
}

下图清晰的展示了这两种参照值的区别:

Table Views 和 Safe Area

有以下几点需要注意:

  • separatorInset 被自动地关联到 safe area insets,因此,默认情况下,表视图的整个内容避免了其根视图控制器的安全区域的插入。
  • UITableviewCell 和 UITableViewHeaderFooterView的 content view 在安全区域内;因此你应该始终在 content view 中使用add-subviews操作。
  • 所有的 headers 和 footers 都应该使用UITableViewHeaderFooterView,包括 table headers 和 footers、section headers 和 footers。

滑动操作(Swipe Actions)

在iOS8之后,苹果官方增加了UITableVIew的右滑操作接口,即新增了一个代理方法(tableView: editActionsForRowAtIndexPath:)和一个类(UITableViewRowAction),代理方法返回的是一个数组,我们可以在这个代理方法中定义所需要的操作按钮(删除、置顶等),这些按钮的类就是UITableViewRowAction。这个类只能定义按钮的显示文字、背景色、和按钮事件。并且返回数组的第一个元素在UITableViewCell的最右侧显示,最后一个元素在最左侧显示。从iOS 11开始有了一些改变,首先是可以给这些按钮添加图片了,然后是如果实现了以下两个iOS 11新增的代理方法,将会取代(tableView: editActionsForRowAtIndexPath:)代理方法:

// Swipe actions
// These methods supersede -editActionsForRowAtIndexPath: if implemented
- (nullable UISwipeActionsConfiguration *)tableView:(UITableView *)tableView leadingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath
- (nullable UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath

这两个代理方法返回的是UISwipeActionsConfiguration类型的对象,创建该对象及赋值可看下面的代码片段:

- ( UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath {
    //删除
    UIContextualAction *deleteRowAction = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive title:@"delete" handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
        [self.titleArr removeObjectAtIndex:indexPath.row];
        completionHandler (YES);
    }];
    deleteRowAction.image = [UIImage imageNamed:@"icon_del"];
    deleteRowAction.backgroundColor = [UIColor blueColor];

    UISwipeActionsConfiguration *config = [UISwipeActionsConfiguration configurationWithActions:@[deleteRowAction]];
    return config;
}

创建UIContextualAction对象时,UIContextualActionStyle有两种类型,如果是置顶、已读等按钮就使用UIContextualActionStyleNormal类型,delete操作按钮可使用UIContextualActionStyleDestructive类型,当使用该类型时,如果是右滑操作,一直向右滑动某个cell,会直接执行删除操作,不用再点击删除按钮,这也是一个好玩的更新。

typedef NS_ENUM(NSInteger, UIContextualActionStyle) {
    UIContextualActionStyleNormal,
    UIContextualActionStyleDestructive
} NS_SWIFT_NAME(UIContextualAction.Style)

滑动操作这里还有一个需要注意的是,当cell高度较小时,会只显示image,不显示title,当cell高度够大时,会同时显示image和title。我写demo测试的时候,因为每个cell的高度都较小,所以只显示image,然后我增加cell的高度后,就可以同时显示image和title了。见下图对比:

总结

大概介绍了iOS 11的UI方面的一些更新,大部分内容都用代码测试过了,有些更新确实是很实用,可以适配下iOS 11,有的更新可能会给现有APP造成bug,所以学习下这些内容还是很有必要的。

2017-02-22 19:55:00 weixin_34314962 阅读数 7

在viewDidLayoutSubviews方法中,添加了设置页面中各个控件frame的方法。在每次转屏的时候都会调用。当适配tableViewCell或自定义子视图的转屏时,可以重写layoutSubviews方法,在这个方法里添加设置各个子控件frame的方法。注意,一定要[super layoutSubviews],否则在cell复用的时候,cell的分割线会消失。

viewDidLayoutSubviews(网上找的,仅供参考)

1、loadView只会被调用一次。

2、viewDidLoad 类中成员对象和变量的初始化放在这个方法中,只会调用一次。

3、viewWillAppare:视图将要展现时会调用。

4、viewWillLayoutSubviews:在viewWillAppare后调用,将要对子视图进行布局。

5、viewDidLayoutSubviews:已经布局完成子视图。

6、viewDidAppare:视图完成显示时调用。

layoutSubviews

1、init初始化不会触发layoutSubviews。

2、addSubview会触发layoutSubviews。

3、设置view的Frame会触发layoutSubviews,当然前提是frame的值设置前后发生了变化。

4、滚动一个UIScrollView会触发layoutSubviews。

5、旋转Screen会触发父UIView上的layoutSubviews事件。

6、改变一个UIView大小的时候也会触发父UIView上的layoutSubviews事件。

App适配iOS 11

阅读数 2231

App适配iOS 11

阅读数 746

App适配iOS 11

阅读数 246

App适配iOS 11

阅读数 5

没有更多推荐了,返回首页