iOS小技能:下拉刷新控件的适配

简介: 1. 下拉顶部背景色设置: 往tableView的父控件添加拉伸背景视图2. present 半屏适配iOS13 modalPresentationStyle属性默认不是全屏样式`UIModalPresentationFullScreen`,而是半屏样式,需要根据需求手动设置。 present 半屏,会导致列表下拉刷新失效。

前言

  1. 下拉顶部背景色设置: 往tableView的父控件添加拉伸背景视图
  2. present 半屏适配
iOS13 modalPresentationStyle属性默认不是全屏样式 UIModalPresentationFullScreen,而是半屏样式,需要根据需求手动设置。 present 半屏,会导致列表下拉刷新失效。

I 下拉刷新适配

1.1 下拉顶部背景色设置

在这里插入图片描述

  1. 设置下拉样式
#import <MJRefresh/MJRefresh.h>
@interface ERPMJRefreshNormalHeader4StyleWhite : MJRefreshNormalHeader

+ (instancetype)headerWithRefreshingTarget:(id)target refreshingAction:(SEL)action
{
    MJRefreshHeader *cmp = [[self alloc] init];
    
    [cmp setRefreshingTarget:target refreshingAction:action];
    [self setupStyleWhite:cmp];
    return cmp;
}

+(void)setupStyleWhite:(MJRefreshNormalHeader*)mj_header{
    
    
    mj_header.stateLabel.textColor = UIColor.whiteColor;
    mj_header.lastUpdatedTimeLabel.textColor=mj_header.stateLabel.textColor;
    mj_header.loadingView.activityIndicatorViewStyle =UIActivityIndicatorViewStyleWhite;
    
}
  1. 下拉顶部背景色设置:往tableView的父控件添加拉伸背景视图
        ERPMJRefreshNormalHeader4StyleWhite *mj_header =[ERPMJRefreshNormalHeader4StyleWhite headerWithRefreshingTarget:self refreshingAction:@selector(headerRereshing)];        
        
        UIImage *bgImg = [UIImage getMaingradientColorImage];
        
        UIColor *tmpColor = [UIColor colorWithPatternImage:bgImg];
        
        mj_header.backgroundColor =tmpColor;
        
        [self setupStretchViewColor:mj_header.backgroundColor tableView:_vcView.tableView];
        
        _vcView.tableView.mj_header = mj_header;

        _vcView.tableView.bounces = YES;

- (void)setupStretchViewColor:(UIColor*) stretchViewColor tableView:(UIView*)tableView{
    

    [tableView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
    
    
    self.stretchView.backgroundColor =stretchViewColor;
    //往tableView的父控件添加拉伸背景视图
    [tableView.superview addSubview:self.stretchView];
    

}

#pragma mark - 拉顶部背景色
-(void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id>*)change context:(void*)context{
    if([keyPath isEqualToString:@"contentOffset"]){
        NSValue *value = change[NSKeyValueChangeNewKey];
        CGFloat chaneoffsetY = value.UIOffsetValue.vertical;
        UIView *mj_header= self.vcView.tableView.mj_header;
        
        self.stretchView.frame = CGRectMake(0,0,mj_header.width,-chaneoffsetY-mj_header.height);
    }
}

/**
 拉伸背景

 @return view
 */
-(UIView *)stretchView{
    
    if (!_stretchView) {
        
        UIView *tmp =[[UIView alloc] init];
        _stretchView =tmp;
//        _stretchView.backgroundColor = self.backgroundColor;
    }
    return _stretchView;
}

1.2 present 半屏适配

  1. 手动设置全屏样式
xxNavigationViewController *nav = [[xxNavigationViewController alloc] initWithRootViewController:loginViewController];
nav.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:nav animated:YES completion:nil];
//推荐使用UIModalPresentationOverFullScreen
  1. 灵活控制模态展示的视图样式
iOS13适配【灵活控制模态展示的视图样式】(全屏/下滑返回)文中提供完整demo源码
  1. 全局hook presentViewController方法
//
//  UIViewController+ERPPresent13.h

#import <UIKit/UIKit.h>
#import <objc/runtime.h>

NS_ASSUME_NONNULL_BEGIN

@interface UIViewController (ERPPresent13)

/**
Whether or not to set ModelPresentationStyle automatically for instance, Default is [Class K_automaticallySetModalPresentationStyle].
@return BOOL
*/
@property (nonatomic, assign) BOOL K_automaticallySetModalPresentationStyle;

/**
 Whether or not to set ModelPresentationStyle automatically, Default is YES, but UIImagePickerController/UIAlertController is NO.
 @return BOOL
 */
+ (BOOL)K_automaticallySetModalPresentationStyle;

@end

NS_ASSUME_NONNULL_END
//
//  UIViewController+ERPPresent13.m

#import "UIViewController+ERPPresent13.h"

static const char *K_automaticallySetModalPresentationStyleKey;

@implementation UIViewController (ERPPresent13)
+ (void)load {
    Method originAddObserverMethod = class_getInstanceMethod(self, @selector(presentViewController:animated:completion:));
    Method swizzledAddObserverMethod = class_getInstanceMethod(self, @selector(K_presentViewController:animated:completion:));
    method_exchangeImplementations(originAddObserverMethod, swizzledAddObserverMethod);
}

- (void)setK_automaticallySetModalPresentationStyle:(BOOL)K_automaticallySetModalPresentationStyle {
    objc_setAssociatedObject(self, K_automaticallySetModalPresentationStyleKey, @(K_automaticallySetModalPresentationStyle), OBJC_ASSOCIATION_ASSIGN);
}

- (BOOL)K_automaticallySetModalPresentationStyle {
    id obj = objc_getAssociatedObject(self, K_automaticallySetModalPresentationStyleKey);
    if (obj) {
        return [obj boolValue];
    }
    return [self.class K_automaticallySetModalPresentationStyle];
}

+ (BOOL)K_automaticallySetModalPresentationStyle {
    if ([self isKindOfClass:[UIImagePickerController class]] || [self isKindOfClass:[UIAlertController class]]) {
        return NO;
    }
    return YES;
}

- (void)K_presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion {
    if (@available(iOS 13.0, *)) {
        if (viewControllerToPresent.K_automaticallySetModalPresentationStyle) {
            viewControllerToPresent.modalPresentationStyle = UIModalPresentationFullScreen;
        }
        [self K_presentViewController:viewControllerToPresent animated:flag completion:completion];
    } else {
        // Fallback on earlier versions
        [self K_presentViewController:viewControllerToPresent animated:flag completion:completion];
    }
}

@end

II 上拉加载适配

2.1 安全距离适配

https://blog.csdn.net/z929118967/article/details/126224009?spm=1001.2014.3001.5501

问题:没有上拉的时候加载更多控件的文案也显示出来了

修复方式1:修改视图距离底部的高度

    [self.vcView mas_makeConstraints:^(MASConstraintMaker *make) {
        
        make.left.equalTo(weakSelf.view).offset(0);
        make.right.equalTo(weakSelf.view).offset(- 0);
        make.top.equalTo(weakSelf.view).offset(0);
        if(isHasSafeAreaInsets()){// 避免没有上拉的时候加载更多控件的文案也显示出来了
            UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];
            CGFloat bottom = mainWindow.safeAreaInsets.bottom;
            make.bottom.equalTo(weakSelf.view).offset(bottom);

        }else{
            make.bottom.equalTo(weakSelf.view);
        }
        
        
    }];
    

修复方式2:修改上拉加载控件距离底部的高度 【推荐】


/** 忽略多少scrollView的contentInset的bottom */
//@property (assign, nonatomic) CGFloat ignoredScrollViewContentInsetBottom;

            UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];
            CGFloat bottom = mainWindow.safeAreaInsets.bottom;//34
_tableView.mj_footer.ignoredScrollViewContentInsetBottom = isIphoneX ? bottom : 0;

适配之后的效果
判断安全区域距离

static inline BOOL isIPhoneXSeries() {
    if (@available(iOS 11.0, *)) {
        UIWindow *mainWindow = [[[UIApplication sharedApplication] delegate] window];
        if (mainWindow.safeAreaInsets.bottom > 0.0) {
            return YES;
        }
    }
    return NO;
}

2.2 分页并发适配

方式1. 升级MJRefresh到3.7.5版本
Fix/duplicated async method -> Installing MJRefresh 3.7.5 (was 3.3.1)

- (void)executeRefreshingCallback
{
    if (self.refreshingBlock) {
        self.refreshingBlock();
    }
    if ([self.refreshingTarget respondsToSelector:self.refreshingAction]) {
        MJRefreshMsgSend(MJRefreshMsgTarget(self.refreshingTarget), self.refreshingAction, self);
    }
    if (self.beginRefreshingCompletionBlock) {
        self.beginRefreshingCompletionBlock();
    }
}

方式2. 使用自动刷新控件MJRefreshNormalHeader->MJRefreshAutoNormalFooter

see also

公号:iOS逆向

目录
相关文章
|
iOS开发
iOS 利用贝塞尔曲线实现Q弹的下拉刷新
iOS 利用贝塞尔曲线实现Q弹的下拉刷新
50 0
|
4月前
|
IDE API Android开发
安卓与iOS开发环境的差异及适配策略
在移动应用开发的广阔舞台上,Android和iOS两大操作系统各据一方,各自拥有独特的开发环境和工具集。本文旨在深入探讨这两个平台在开发环境上的关键差异,并提供有效的适配策略,帮助开发者优化跨平台开发流程。通过比较Android的Java/Kotlin和iOS的Swift/Objective-C语言特性、IDE的选择、以及API和系统服务的访问方式,本文揭示了两个操作系统在开发实践中的主要分歧点,并提出了一套实用的适配方法,以期为移动开发者提供指导和启示。
|
6月前
|
iOS开发
SwiftUI适配iOS16导航控制器引起的闪退
SwiftUI适配iOS16导航控制器引起的闪退
74 0
|
6月前
|
监控 iOS开发
iOS15适配问题:viewForSupplementaryElementOfKind表头和表尾复用闪退,UITableView section header多22像素等问题
iOS15适配问题:viewForSupplementaryElementOfKind表头和表尾复用闪退,UITableView section header多22像素等问题
100 0
|
小程序 开发工具 Android开发
Donut多端框架小程序打包适配ios和安卓app
腾讯新出了一个 Donut 多端框架,可以直接将微信小程序转成 ios 和 安卓 app,小程序开发者工具里也集成了 app 相关升级、调试和打包的功能,终于可以一套代码开发出3个客户端了!
261 0
Donut多端框架小程序打包适配ios和安卓app
|
安全 前端开发 开发工具
iOS12、iOS11、iOS10、iOS9常见适配
iOS12、iOS11、iOS10、iOS9常见适配
238 0
|
iOS开发
iOS 多个滚动控件嵌套Demo
iOS 多个滚动控件嵌套Demo
71 0
|
iOS开发
iOS 常用的 上下左右 拉刷新控件
iOS 常用的 上下左右 拉刷新控件
106 0
|
小程序 iOS开发
uniapp中IOS端小程序底部黑线适配的方法(整理)
uniapp中IOS端小程序底部黑线适配的方法(整理)
|
开发工具 iOS开发 开发者
iOS 暗黑模式的适配总结
iOS 暗黑模式的适配总结