| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807 |
- //
- // TCommonCell.m
- // TXIMSDK_TUIKit_iOS
- //
- // Created by annidyfeng on 2019/5/6.
- // Copyright © 2023 Tencent. All rights reserved.
- //
- #import "TUICommonModel.h"
- #import <objc/runtime.h>
- #import "NSString+TUIUtil.h"
- #import "TUIDarkModel.h"
- #import "TUIGlobalization.h"
- #import "TUIThemeManager.h"
- #import "TUITool.h"
- #import "UIView+TUILayout.h"
- /////////////////////////////////////////////////////////////////////////////////
- //
- // TUIUserFullInfo
- //
- /////////////////////////////////////////////////////////////////////////////////
- @implementation V2TIMUserFullInfo (TUIUserFullInfo)
- - (NSString *)showName {
- if ([NSString isEmpty:self.nickName]) return self.userID;
- return self.nickName;
- }
- - (NSString *)showGender {
- if (self.gender == V2TIM_GENDER_MALE) return TUIKitLocalizableString(Male);
- if (self.gender == V2TIM_GENDER_FEMALE) return TUIKitLocalizableString(Female);
- return TUIKitLocalizableString(Unsetted);
- }
- - (NSString *)showSignature {
- if (self.selfSignature == nil) return TUIKitLocalizableString(TUIKitNoSelfSignature);
- return [NSString stringWithFormat:TUIKitLocalizableString(TUIKitSelfSignatureFormat), self.selfSignature];
- }
- - (NSString *)showAllowType {
- if (self.allowType == V2TIM_FRIEND_ALLOW_ANY) {
- return TUIKitLocalizableString(TUIKitAllowTypeAcceptOne);
- }
- if (self.allowType == V2TIM_FRIEND_NEED_CONFIRM) {
- return TUIKitLocalizableString(TUIKitAllowTypeNeedConfirm);
- }
- if (self.allowType == V2TIM_FRIEND_DENY_ANY) {
- return TUIKitLocalizableString(TUIKitAllowTypeDeclineAll);
- }
- return nil;
- }
- @end
- /////////////////////////////////////////////////////////////////////////////////
- //
- // TUIUserModel
- //
- /////////////////////////////////////////////////////////////////////////////////
- @implementation TUIUserModel
- - (id)copyWithZone:(NSZone *)zone {
- TUIUserModel *model = [[TUIUserModel alloc] init];
- model.userId = self.userId;
- model.name = self.name;
- model.avatar = self.avatar;
- return model;
- }
- @end
- /////////////////////////////////////////////////////////////////////////////////
- //
- // TUIScrollView
- //
- /////////////////////////////////////////////////////////////////////////////////
- static void *gScrollViewBoundsChangeNotificationContext = &gScrollViewBoundsChangeNotificationContext;
- @interface TUIScrollView ()
- @property(nonatomic, readonly) CGFloat imageAspectRatio;
- @property(nonatomic) CGRect initialImageFrame;
- @property(strong, nonatomic, readonly) UITapGestureRecognizer *tap;
- @end
- @implementation TUIScrollView
- @synthesize tap = _tap;
- #pragma mark - Tap to Zoom
- - (UITapGestureRecognizer *)tap {
- if (_tap == nil) {
- _tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapToZoom:)];
- _tap.numberOfTapsRequired = 2;
- }
- return _tap;
- }
- - (void)tapToZoom:(UIGestureRecognizer *)gestureRecognizer {
- if (self.zoomScale > self.minimumZoomScale) {
- [self setZoomScale:self.minimumZoomScale animated:YES];
- } else {
- CGPoint tapLocation = [gestureRecognizer locationInView:self.imageView];
- CGFloat zoomRectWidth = self.imageView.frame.size.width / self.maximumZoomScale;
- CGFloat zoomRectHeight = self.imageView.frame.size.height / self.maximumZoomScale;
- CGFloat zoomRectX = tapLocation.x - zoomRectWidth * 0.5;
- CGFloat zoomRectY = tapLocation.y - zoomRectHeight * 0.5;
- CGRect zoomRect = CGRectMake(zoomRectX, zoomRectY, zoomRectWidth, zoomRectHeight);
- [self zoomToRect:zoomRect animated:YES];
- }
- }
- #pragma mark - Private Methods
- - (void)configure {
- self.showsVerticalScrollIndicator = NO;
- self.showsHorizontalScrollIndicator = NO;
- [self startObservingBoundsChange];
- }
- - (void)setImageView:(UIImageView *)imageView {
- if (_imageView.superview == self) {
- [_imageView removeGestureRecognizer:self.tap];
- [_imageView removeFromSuperview];
- }
- if (imageView) {
- _imageView = imageView;
- _initialImageFrame = CGRectNull;
- _imageView.userInteractionEnabled = YES;
- [_imageView addGestureRecognizer:self.tap];
- [self addSubview:imageView];
- }
- }
- - (CGFloat)imageAspectRatio {
- if (self.imageView.image) {
- return self.imageView.image.size.width / self.imageView.image.size.height;
- }
- return 1;
- }
- - (CGSize)rectSizeForAspectRatio:(CGFloat)ratio thatFitsSize:(CGSize)size {
- CGFloat containerWidth = size.width;
- CGFloat containerHeight = size.height;
- CGFloat resultWidth = 0;
- CGFloat resultHeight = 0;
- if ((ratio <= 0) || (containerHeight <= 0)) {
- return size;
- }
- if (containerWidth / containerHeight >= ratio) {
- resultHeight = containerHeight;
- resultWidth = containerHeight * ratio;
- } else {
- resultWidth = containerWidth;
- resultHeight = containerWidth / ratio;
- }
- return CGSizeMake(resultWidth, resultHeight);
- }
- - (void)scaleImageForScrollViewTransitionFromBounds:(CGRect)oldBounds toBounds:(CGRect)newBounds {
- CGPoint oldContentOffset = CGPointMake(oldBounds.origin.x, oldBounds.origin.y);
- CGSize oldSize = oldBounds.size;
- CGSize newSize = newBounds.size;
- CGSize containedImageSizeOld = [self rectSizeForAspectRatio:self.imageAspectRatio thatFitsSize:oldSize];
- CGSize containedImageSizeNew = [self rectSizeForAspectRatio:self.imageAspectRatio thatFitsSize:newSize];
- if (containedImageSizeOld.height <= 0) {
- containedImageSizeOld = containedImageSizeNew;
- }
- CGFloat orientationRatio = (containedImageSizeNew.height / containedImageSizeOld.height);
- CGAffineTransform t = CGAffineTransformMakeScale(orientationRatio, orientationRatio);
- self.imageView.frame = CGRectApplyAffineTransform(self.imageView.frame, t);
- self.contentSize = self.imageView.frame.size;
- CGFloat xOffset = (oldContentOffset.x + oldSize.width * 0.5) * orientationRatio - newSize.width * 0.5;
- CGFloat yOffset = (oldContentOffset.y + oldSize.height * 0.5) * orientationRatio - newSize.height * 0.5;
- xOffset -= MAX(xOffset + newSize.width - self.contentSize.width, 0);
- yOffset -= MAX(yOffset + newSize.height - self.contentSize.height, 0);
- xOffset += MAX(-xOffset, 0);
- yOffset += MAX(-yOffset, 0);
- self.contentOffset = CGPointMake(xOffset, yOffset);
- }
- - (void)setupInitialImageFrame {
- if (self.imageView.image && CGRectEqualToRect(self.initialImageFrame, CGRectNull)) {
- CGSize imageViewSize = [self rectSizeForAspectRatio:self.imageAspectRatio thatFitsSize:self.bounds.size];
- self.initialImageFrame = CGRectMake(0, 0, imageViewSize.width, imageViewSize.height);
- self.imageView.frame = self.initialImageFrame;
- self.contentSize = self.initialImageFrame.size;
- }
- }
- #pragma mark - KVO
- - (void)startObservingBoundsChange {
- [self addObserver:self
- forKeyPath:@"bounds"
- options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew
- context:gScrollViewBoundsChangeNotificationContext];
- }
- - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey, id> *)change context:(void *)context {
- if (context == gScrollViewBoundsChangeNotificationContext) {
- CGRect oldRect = ((NSValue *)change[NSKeyValueChangeOldKey]).CGRectValue;
- CGRect newRect = ((NSValue *)change[NSKeyValueChangeNewKey]).CGRectValue;
- if (!CGSizeEqualToSize(oldRect.size, newRect.size)) {
- [self scaleImageForScrollViewTransitionFromBounds:oldRect toBounds:newRect];
- }
- }
- }
- - (void)dealloc {
- [self removeObserver:self forKeyPath:@"bounds"];
- }
- #pragma mark - UIScrollView
- - (void)setContentOffset:(CGPoint)contentOffset {
- const CGSize contentSize = self.contentSize;
- const CGSize scrollViewSize = self.bounds.size;
- if (contentSize.width < scrollViewSize.width) {
- contentOffset.x = -(scrollViewSize.width - contentSize.width) * 0.5;
- }
- if (contentSize.height < scrollViewSize.height) {
- contentOffset.y = -(scrollViewSize.height - contentSize.height) * 0.5;
- }
- [super setContentOffset:contentOffset];
- }
- #pragma mark - UIView
- - (instancetype)initWithFrame:(CGRect)frame {
- self = [super initWithFrame:frame];
- if (self) {
- [self configure];
- }
- return self;
- }
- - (instancetype)initWithCoder:(NSCoder *)aDecoder {
- self = [super initWithCoder:aDecoder];
- if (self) {
- [self configure];
- }
- return self;
- }
- - (void)layoutSubviews {
- [super layoutSubviews];
- [self setupInitialImageFrame];
- }
- @end
- /////////////////////////////////////////////////////////////////////////////////
- //
- // TUIGroupAvatar
- //
- /////////////////////////////////////////////////////////////////////////////////
- #define groupAvatarWidth (48 * [[UIScreen mainScreen] scale])
- @implementation TUIGroupAvatar
- + (void)createGroupAvatar:(NSArray *)group finished:(void (^)(UIImage *groupAvatar))finished {
- dispatch_async(dispatch_get_global_queue(0, 0), ^{
- NSInteger avatarCount = group.count > 9 ? 9 : group.count;
- CGFloat width = groupAvatarWidth / 3 * 0.90;
- CGFloat space3 = (groupAvatarWidth - width * 3) / 4;
- CGFloat space2 = (groupAvatarWidth - width * 2 + space3) / 2;
- CGFloat space1 = (groupAvatarWidth - width) / 2;
- __block CGFloat y = avatarCount > 6 ? space3 : (avatarCount > 3 ? space2 : space1);
- __block CGFloat x = avatarCount % 3 == 0 ? space3 : (avatarCount % 3 == 2 ? space2 : space1);
- width = avatarCount > 4 ? width : (avatarCount > 1 ? (groupAvatarWidth - 3 * space3) / 2 : groupAvatarWidth);
- if (avatarCount == 1) {
- x = 0;
- y = 0;
- }
- if (avatarCount == 2) {
- x = space3;
- } else if (avatarCount == 3) {
- x = (groupAvatarWidth - width) / 2;
- y = space3;
- } else if (avatarCount == 4) {
- x = space3;
- y = space3;
- }
- dispatch_async(dispatch_get_main_queue(), ^{
- UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, groupAvatarWidth, groupAvatarWidth)];
- [view setBackgroundColor:[UIColor colorWithWhite:0.8 alpha:0.6]];
- view.layer.cornerRadius = 6;
- __block NSInteger count = 0;
- for (NSInteger i = avatarCount - 1; i >= 0; i--) {
- NSString *avatarUrl = [group objectAtIndex:i];
- UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(x, y, width, width)];
- [view addSubview:imageView];
- [imageView sd_setImageWithURL:[NSURL URLWithString:avatarUrl]
- placeholderImage:DefaultAvatarImage
- completed:^(UIImage *_Nullable image, NSError *_Nullable error, SDImageCacheType cacheType, NSURL *_Nullable imageURL) {
- count++;
- if (count == avatarCount) {
- UIGraphicsBeginImageContextWithOptions(view.frame.size, NO, 2.0);
- [view.layer renderInContext:UIGraphicsGetCurrentContext()];
- UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndPDFContext();
- CGImageRef imageRef = image.CGImage;
- CGImageRef imageRefRect =
- CGImageCreateWithImageInRect(imageRef, CGRectMake(0, 0, view.frame.size.width * 2, view.frame.size.height * 2));
- UIImage *ansImage = [[UIImage alloc] initWithCGImage:imageRefRect];
- CGImageRelease(imageRefRect);
- dispatch_async(dispatch_get_main_queue(), ^{
- if (finished) {
- finished(ansImage);
- }
- });
- }
- }];
- if (avatarCount == 3) {
- if (i == 2) {
- y = width + space3 * 2;
- x = space3;
- } else {
- x += width + space3;
- }
- } else if (avatarCount == 4) {
- if (i % 2 == 0) {
- y += width + space3;
- x = space3;
- } else {
- x += width + space3;
- }
- } else {
- if (i % 3 == 0) {
- y += (width + space3);
- x = space3;
- } else {
- x += (width + space3);
- }
- }
- }
- });
- });
- }
- + (void)fetchGroupAvatars:(NSString *)groupID placeholder:(UIImage *)placeholder callback:(void (^)(BOOL success, UIImage *image, NSString *groupID))callback {
- @tui_weakify(self);
- [[V2TIMManager sharedInstance] getGroupMemberList:groupID
- filter:V2TIM_GROUP_MEMBER_FILTER_ALL
- nextSeq:0
- succ:^(uint64_t nextSeq, NSArray<V2TIMGroupMemberFullInfo *> *memberList) {
- @tui_strongify(self);
- int i = 0;
- NSMutableArray *groupMemberAvatars = [NSMutableArray arrayWithCapacity:1];
- for (V2TIMGroupMemberFullInfo *member in memberList) {
- if (member.faceURL.length > 0) {
- [groupMemberAvatars addObject:member.faceURL];
- } else {
- [groupMemberAvatars addObject:@"http://placeholder"];
- }
- if (++i == 9) {
- break;
- }
- }
- if (i <= 1) {
- [self asyncClearCacheAvatarForGroup:groupID];
- if (callback) {
- callback(NO, placeholder, groupID);
- }
- return;
- }
- NSString *key = [NSString stringWithFormat:@"TUIConversationLastGroupMember_%@", groupID];
- [NSUserDefaults.standardUserDefaults setInteger:groupMemberAvatars.count forKey:key];
- [NSUserDefaults.standardUserDefaults synchronize];
- [TUIGroupAvatar createGroupAvatar:groupMemberAvatars
- finished:^(UIImage *groupAvatar) {
- @tui_strongify(self);
- UIImage *avatar = groupAvatar;
- [self cacheGroupAvatar:avatar number:(UInt32)groupMemberAvatars.count groupID:groupID];
- if (callback) {
- callback(YES, avatar, groupID);
- }
- }];
- }
- fail:^(int code, NSString *msg) {
- if (callback) {
- callback(NO, placeholder, groupID);
- }
- }];
- }
- + (void)cacheGroupAvatar:(UIImage *)avatar number:(UInt32)memberNum groupID:(NSString *)groupID {
- dispatch_async(dispatch_get_global_queue(0, 0), ^{
- if (groupID == nil || groupID.length == 0) {
- return;
- }
- NSString *tempPath = NSTemporaryDirectory();
- NSString *filePath = [NSString stringWithFormat:@"%@groupAvatar_%@_%d.png", tempPath, groupID, memberNum];
- NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
- // check to delete old file
- NSNumber *oldValue = [defaults objectForKey:groupID];
- if (oldValue != nil) {
- UInt32 oldMemberNum = [oldValue unsignedIntValue];
- NSString *oldFilePath = [NSString stringWithFormat:@"%@groupAvatar_%@_%d.png", tempPath, groupID, oldMemberNum];
- NSFileManager *fileManager = [NSFileManager defaultManager];
- [fileManager removeItemAtPath:oldFilePath error:nil];
- }
- // Save image.
- BOOL success = [UIImagePNGRepresentation(avatar) writeToFile:filePath atomically:YES];
- if (success) {
- [defaults setObject:@(memberNum) forKey:groupID];
- }
- });
- }
- + (void)getCacheGroupAvatar:(NSString *)groupID callback:(void (^)(UIImage *, NSString *groupID))imageCallBack {
- if (groupID == nil || groupID.length == 0) {
- if (imageCallBack) {
- imageCallBack(nil, groupID);
- }
- return;
- }
- [[V2TIMManager sharedInstance] getGroupsInfo:@[ groupID ]
- succ:^(NSArray<V2TIMGroupInfoResult *> *groupResultList) {
- V2TIMGroupInfoResult *groupInfo = groupResultList.firstObject;
- if (!groupInfo) {
- imageCallBack(nil, groupID);
- return;
- }
- UInt32 memberNum = groupInfo.info.memberCount;
- memberNum = MAX(1, memberNum);
- memberNum = MIN(memberNum, 9);
- ;
- NSString *tempPath = NSTemporaryDirectory();
- NSString *filePath = [NSString stringWithFormat:@"%@groupAvatar_%@_%u.png", tempPath, groupID, (unsigned int)memberNum];
- NSFileManager *fileManager = [NSFileManager defaultManager];
- UIImage *avatar = nil;
- BOOL success = [fileManager fileExistsAtPath:filePath];
- if (success) {
- avatar = [[UIImage alloc] initWithContentsOfFile:filePath];
- NSString *key = [NSString stringWithFormat:@"TUIConversationLastGroupMember_%@", groupID];
- [NSUserDefaults.standardUserDefaults setInteger:memberNum forKey:key];
- [NSUserDefaults.standardUserDefaults synchronize];
- }
- imageCallBack(avatar, groupInfo.info.groupID);
- }
- fail:^(int code, NSString *msg) {
- imageCallBack(nil, groupID);
- }];
- }
- + (UIImage *)getCacheAvatarForGroup:(NSString *)groupId number:(UInt32)memberNum {
- memberNum = MAX(1, memberNum);
- memberNum = MIN(memberNum, 9);
- ;
- NSString *tempPath = NSTemporaryDirectory();
- NSString *filePath = [NSString stringWithFormat:@"%@groupAvatar_%@_%u.png", tempPath, groupId, (unsigned int)memberNum];
- NSFileManager *fileManager = [NSFileManager defaultManager];
- UIImage *avatar = nil;
- BOOL success = [fileManager fileExistsAtPath:filePath];
- if (success) {
- avatar = [[UIImage alloc] initWithContentsOfFile:filePath];
- }
- return avatar;
- }
- + (void)asyncClearCacheAvatarForGroup:(NSString *)groupID {
- dispatch_async(dispatch_get_global_queue(0, 0), ^{
- NSString *tempPath = NSTemporaryDirectory();
- for (int i = 0; i < 9; i++) {
- NSString *filePath = [NSString stringWithFormat:@"%@groupAvatar_%@_%d.png", tempPath, groupID, (i + 1)];
- if ([NSFileManager.defaultManager fileExistsAtPath:filePath]) {
- [NSFileManager.defaultManager removeItemAtPath:filePath error:nil];
- }
- }
- });
- }
- @end
- /////////////////////////////////////////////////////////////////////////////////
- //
- // TUIImageCache
- //
- /////////////////////////////////////////////////////////////////////////////////
- @interface TUIImageCache ()
- @property(nonatomic, strong) NSMutableDictionary *resourceCache;
- @property(nonatomic, strong) NSMutableDictionary *faceCache;
- @end
- @implementation TUIImageCache
- + (instancetype)sharedInstance {
- static dispatch_once_t onceToken;
- static TUIImageCache *instance;
- dispatch_once(&onceToken, ^{
- instance = [[TUIImageCache alloc] init];
- [UIImage d_fixResizableImage];
- });
- return instance;
- }
- - (instancetype)init {
- self = [super init];
- if (self) {
- _resourceCache = [NSMutableDictionary dictionary];
- _faceCache = [NSMutableDictionary dictionary];
- }
- return self;
- }
- - (void)addResourceToCache:(NSString *)path {
- __weak typeof(self) ws = self;
- [TUITool asyncDecodeImage:path
- complete:^(NSString *key, UIImage *image) {
- __strong __typeof(ws) strongSelf = ws;
- if (key && image) {
- [strongSelf.resourceCache setValue:image forKey:key];
- }
- }];
- }
- - (UIImage *)getResourceFromCache:(NSString *)path {
- if (path.length == 0) {
- return nil;
- }
- UIImage *image = [_resourceCache objectForKey:path];
- if (!image) {
- image = [UIImage d_imagePath:path];
- }
- return image;
- }
- - (void)addFaceToCache:(NSString *)path {
- __weak typeof(self) ws = self;
- [TUITool asyncDecodeImage:path
- complete:^(NSString *key, UIImage *image) {
- __strong __typeof(ws) strongSelf = ws;
- if (key && image) {
- [strongSelf.faceCache setValue:image forKey:key];
- }
- }];
- }
- - (UIImage *)getFaceFromCache:(NSString *)path {
- if (path.length == 0) {
- return nil;
- }
- UIImage *image = [_faceCache objectForKey:path];
- if (!image) {
- // gif extion
- if ([path tui_containsString:@".gif"]) {
- image = [UIImage sd_imageWithGIFData:[NSData dataWithContentsOfFile:path]];
- }
- else {
- image = [UIImage imageWithContentsOfFile:path];
- if (!image) {
- // gif
- NSString *formatPath = [path stringByAppendingString:@".gif"];
- image = [UIImage sd_imageWithGIFData:[NSData dataWithContentsOfFile:formatPath]];
- }
- }
- if (!image) {
- image = [_faceCache objectForKey:TUIChatFaceImagePath(@"ic_unknown_image")];
- }
- }
- return image;
- }
- @end
- @interface IUCoreView : UIView
- @property(nonatomic, strong) UIView *view;
- @end
- @implementation IUCoreView
- - (instancetype)init {
- self = [super init];
- if (self) {
- self.view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
- [self addSubview:self.view];
- }
- return self;
- }
- @end
- @implementation TUINavigationController
- - (instancetype)initWithRootViewController:(UIViewController *)rootViewController {
- if (self = [super initWithRootViewController:rootViewController]) {
- self.interactivePopGestureRecognizer.delegate = self;
- self.delegate = self;
- }
- return self;
- }
- - (void)viewWillAppear:(BOOL)animated {
- [super viewWillAppear:animated];
- if (@available(iOS 13.0, *)) {
- UINavigationBarAppearance *appearance = [UINavigationBarAppearance new];
- [appearance configureWithDefaultBackground];
- appearance.shadowColor = nil;
- appearance.backgroundEffect = nil;
- appearance.backgroundColor = self.navigationBackColor;
- self.navigationBar.backgroundColor = self.navigationBackColor;
- self.navigationBar.barTintColor = self.navigationBackColor;
- self.navigationBar.shadowImage = [UIImage new];
- self.navigationBar.standardAppearance = appearance;
- self.navigationBar.scrollEdgeAppearance = appearance;
- } else {
- self.navigationBar.backgroundColor = self.navigationBackColor;
- self.navigationBar.barTintColor = self.navigationBackColor;
- self.navigationBar.shadowImage = [UIImage new];
- }
- }
- - (void)viewDidLoad {
- [super viewDidLoad];
- self.delegate = self;
- }
- - (void)back {
- if ([self.uiNaviDelegate respondsToSelector:@selector(navigationControllerDidClickLeftButton:)]) {
- [self.uiNaviDelegate navigationControllerDidClickLeftButton:self];
- }
- [self popViewControllerAnimated:YES];
- }
- - (UIColor *)navigationBackColor {
- if (!_navigationBackColor) {
- _navigationBackColor = [self tintColor];
- }
- return _navigationBackColor;
- }
- - (UIColor *)tintColor {
- return TUICoreDynamicColor(@"head_bg_gradient_start_color", @"#EBF0F6");
- }
- - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated {
- if (self.viewControllers.count != 0) {
- viewController.hidesBottomBarWhenPushed = YES;
- self.tabBarController.tabBar.hidden = YES;
- UIImage *image = self.navigationItemBackArrowImage;
- image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
- UIBarButtonItem *back = [[UIBarButtonItem alloc] initWithImage:image style:UIBarButtonItemStylePlain target:self action:@selector(back)];
- viewController.navigationItem.leftBarButtonItems = @[ back ];
- viewController.navigationItem.leftItemsSupplementBackButton = NO;
- }
- [super pushViewController:viewController animated:animated];
- }
- - (UIImage *)navigationItemBackArrowImage {
- if (!_navigationItemBackArrowImage) {
- _navigationItemBackArrowImage = TUICoreDynamicImage(@"nav_back_img", [UIImage imageNamed:TUICoreImagePath(@"nav_back")]);
- }
- return _navigationItemBackArrowImage;
- }
- // fix: https://developer.apple.com/forums/thread/660750
- - (NSArray<__kindof UIViewController *> *)popToRootViewControllerAnimated:(BOOL)animated {
- if (@available(iOS 14.0, *)) {
- for (UIViewController *vc in self.viewControllers) {
- vc.hidesBottomBarWhenPushed = NO;
- self.tabBarController.tabBar.hidden = NO;
- }
- }
- return [super popToRootViewControllerAnimated:animated];
- }
- - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
- if (navigationController.viewControllers.count == 1) {
- /**
- * If the number of view controllers in the stack is 1, it means only the root controller, clear the currentShowVC, and disable the swipe gesture for
- * the following method
- */
- self.currentShowVC = Nil;
- } else {
- /**
- * Assign the pushed view controller to currentShowVC
- */
- self.currentShowVC = viewController;
- }
- if ([navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) {
- if (self.viewControllers.count == 1) {
- /**
- * Forbid the sliding back of the home page
- */
- navigationController.interactivePopGestureRecognizer.enabled = NO;
- } else {
- navigationController.interactivePopGestureRecognizer.enabled = YES;
- }
- }
- }
- - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
- /**
- * Listen to the event returned by the side slide
- */
- __weak typeof(self) weakSelf = self;
- if (@available(iOS 10.0, *)) {
- [viewController.transitionCoordinator notifyWhenInteractionChangesUsingBlock:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
- __strong typeof(weakSelf) strongSelf = weakSelf;
- [strongSelf handleSideSlideReturnIfNeeded:context];
- }];
- } else {
- [viewController.transitionCoordinator notifyWhenInteractionEndsUsingBlock:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
- __strong typeof(weakSelf) strongSelf = weakSelf;
- [strongSelf handleSideSlideReturnIfNeeded:context];
- }];
- }
- }
- - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
- if (gestureRecognizer == self.interactivePopGestureRecognizer) {
- if (self.currentShowVC == self.topViewController) {
- /**
- * If currentShowVC exists, it means that the number of controllers in the stack is greater than 1, allowing the side slide gesture to be activated
- */
- return YES;
- }
- return NO;
- }
- return YES;
- }
- - (void)handleSideSlideReturnIfNeeded:(id<UIViewControllerTransitionCoordinatorContext>)context {
- if (context.isCancelled) {
- return;
- }
- UIViewController *fromVc = [context viewControllerForKey:UITransitionContextFromViewControllerKey];
- if ([self.uiNaviDelegate respondsToSelector:@selector(navigationControllerDidSideSlideReturn:fromViewController:)]) {
- [self.uiNaviDelegate navigationControllerDidSideSlideReturn:self fromViewController:fromVc];
- }
- }
- @end
- @implementation UIAlertController (TUITheme)
- - (void)tuitheme_addAction:(UIAlertAction *)action {
- if (action.style == UIAlertActionStyleDefault || action.style == UIAlertActionStyleCancel) {
- UIColor *tempColor = TUICoreDynamicColor(@"primary_theme_color", @"#147AFF");
- [action setValue:tempColor forKey:@"_titleTextColor"];
- }
- [self addAction:action];
- }
- @end
- static const void *tui_valueCallbackKey = @"tui_valueCallbackKey";
- static const void *tui_nonValueCallbackKey = @"tui_nonValueCallbackKey";
- static const void *tui_extValueObjKey = @"tui_extValueObjKey";
- @implementation NSObject (TUIExtValue)
- - (void)setTui_valueCallback:(TUIValueCallbck)tui_valueCallback {
- objc_setAssociatedObject(self, tui_valueCallbackKey, tui_valueCallback, OBJC_ASSOCIATION_COPY_NONATOMIC);
- }
- - (TUIValueCallbck)tui_valueCallback {
- return objc_getAssociatedObject(self, tui_valueCallbackKey);
- }
- - (void)setTui_nonValueCallback:(TUINonValueCallbck)tui_nonValueCallback {
- objc_setAssociatedObject(self, tui_nonValueCallbackKey, tui_nonValueCallback, OBJC_ASSOCIATION_COPY_NONATOMIC);
- }
- - (TUINonValueCallbck)tui_nonValueCallback {
- return objc_getAssociatedObject(self, tui_nonValueCallbackKey);
- }
- - (void)setTui_extValueObj:(id)tui_extValueObj {
- objc_setAssociatedObject(self, tui_extValueObjKey, tui_extValueObj, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- }
- - (id)tui_extValueObj {
- return objc_getAssociatedObject(self, tui_extValueObjKey);
- }
- @end
|