1
@@ -7,6 +7,10 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
04122FAA2EC73C0100EF7AB3 /* KBVipPayHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122FA92EC73C0100EF7AB3 /* KBVipPayHeaderView.m */; };
|
||||
04122FAD2EC73C0100EF7AB3 /* KBVipSubscribeCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122FAC2EC73C0100EF7AB3 /* KBVipSubscribeCell.m */; };
|
||||
04122FB02EC73C0100EF7AB3 /* KBVipReviewItemCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122FAF2EC73C0100EF7AB3 /* KBVipReviewItemCell.m */; };
|
||||
04122FB32EC73C0100EF7AB3 /* KBVipReviewListCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122FB22EC73C0100EF7AB3 /* KBVipReviewListCell.m */; };
|
||||
04122F5D2EC5E5A900EF7AB3 /* KBLoginVM.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122F5B2EC5E5A900EF7AB3 /* KBLoginVM.m */; };
|
||||
04122F622EC5F41D00EF7AB3 /* KBUser.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122F612EC5F41D00EF7AB3 /* KBUser.m */; };
|
||||
04122F6D2EC5F40800EF7AB3 /* NSObject+FGIsNullOrEmpty.m in Sources */ = {isa = PBXBuildFile; fileRef = 04122F6B2EC5F40800EF7AB3 /* NSObject+FGIsNullOrEmpty.m */; };
|
||||
@@ -189,6 +193,14 @@
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
04122FA82EC73C0100EF7AB3 /* KBVipPayHeaderView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBVipPayHeaderView.h; sourceTree = "<group>"; };
|
||||
04122FA92EC73C0100EF7AB3 /* KBVipPayHeaderView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBVipPayHeaderView.m; sourceTree = "<group>"; };
|
||||
04122FAB2EC73C0100EF7AB3 /* KBVipSubscribeCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBVipSubscribeCell.h; sourceTree = "<group>"; };
|
||||
04122FAC2EC73C0100EF7AB3 /* KBVipSubscribeCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBVipSubscribeCell.m; sourceTree = "<group>"; };
|
||||
04122FAE2EC73C0100EF7AB3 /* KBVipReviewItemCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBVipReviewItemCell.h; sourceTree = "<group>"; };
|
||||
04122FAF2EC73C0100EF7AB3 /* KBVipReviewItemCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBVipReviewItemCell.m; sourceTree = "<group>"; };
|
||||
04122FB12EC73C0100EF7AB3 /* KBVipReviewListCell.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBVipReviewListCell.h; sourceTree = "<group>"; };
|
||||
04122FB22EC73C0100EF7AB3 /* KBVipReviewListCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBVipReviewListCell.m; sourceTree = "<group>"; };
|
||||
04122F592EC5D40000EF7AB3 /* KBAPI.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBAPI.h; sourceTree = "<group>"; };
|
||||
04122F5A2EC5E5A900EF7AB3 /* KBLoginVM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KBLoginVM.h; sourceTree = "<group>"; };
|
||||
04122F5B2EC5E5A900EF7AB3 /* KBLoginVM.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KBLoginVM.m; sourceTree = "<group>"; };
|
||||
@@ -552,6 +564,14 @@
|
||||
children = (
|
||||
04122F7B2EC5FC5500EF7AB3 /* KBJfPayCell.h */,
|
||||
04122F7C2EC5FC5500EF7AB3 /* KBJfPayCell.m */,
|
||||
04122FA82EC73C0100EF7AB3 /* KBVipPayHeaderView.h */,
|
||||
04122FA92EC73C0100EF7AB3 /* KBVipPayHeaderView.m */,
|
||||
04122FAB2EC73C0100EF7AB3 /* KBVipSubscribeCell.h */,
|
||||
04122FAC2EC73C0100EF7AB3 /* KBVipSubscribeCell.m */,
|
||||
04122FAE2EC73C0100EF7AB3 /* KBVipReviewItemCell.h */,
|
||||
04122FAF2EC73C0100EF7AB3 /* KBVipReviewItemCell.m */,
|
||||
04122FB12EC73C0100EF7AB3 /* KBVipReviewListCell.h */,
|
||||
04122FB22EC73C0100EF7AB3 /* KBVipReviewListCell.m */,
|
||||
);
|
||||
path = V;
|
||||
sourceTree = "<group>";
|
||||
@@ -1591,6 +1611,7 @@
|
||||
04122F882EC6F07F00EF7AB3 /* KBFullAccessManager.m in Sources */,
|
||||
04122F622EC5F41D00EF7AB3 /* KBUser.m in Sources */,
|
||||
04122F8B2EC6F7C800EF7AB3 /* IAPVerifyTransactionObj.m in Sources */,
|
||||
04122FAD2EC73C0100EF7AB3 /* KBVipSubscribeCell.m in Sources */,
|
||||
049FB31D2EC21BCD00FAB05D /* KBMyKeyboardCell.m in Sources */,
|
||||
048909F62EC0AAAA00FABA60 /* KBCategoryTitleCell.m in Sources */,
|
||||
048909F72EC0AAAA00FABA60 /* KBCategoryTitleView.m in Sources */,
|
||||
@@ -1656,12 +1677,14 @@
|
||||
04122F6E2EC5F40800EF7AB3 /* FGIAPProductsFilter.m in Sources */,
|
||||
04122F6F2EC5F40800EF7AB3 /* FGIAPManager.m in Sources */,
|
||||
04122F702EC5F40800EF7AB3 /* FGIAPService.m in Sources */,
|
||||
04122FB32EC73C0100EF7AB3 /* KBVipReviewListCell.m in Sources */,
|
||||
048908DA2EBF61AF00FABA60 /* UICollectionViewLeftAlignedLayout.m in Sources */,
|
||||
04C6EABF2EAF86530089C901 /* main.m in Sources */,
|
||||
04FC95CC2EB1E780007BD342 /* BaseTabBarController.m in Sources */,
|
||||
047C65502EBCBA9E0035E841 /* KBShopVC.m in Sources */,
|
||||
0477BE042EBC83130055D639 /* HomeMainVC.m in Sources */,
|
||||
0477BDFD2EBC6A170055D639 /* HomeHotVC.m in Sources */,
|
||||
04122FAA2EC73C0100EF7AB3 /* KBVipPayHeaderView.m in Sources */,
|
||||
049FB2432EC4BBB700FAB05D /* KBLoginPopView.m in Sources */,
|
||||
048908CC2EBE373500FABA60 /* KBSearchBarView.m in Sources */,
|
||||
04122F872EC6198C00EF7AB3 /* WMDragView.m in Sources */,
|
||||
@@ -1679,6 +1702,7 @@
|
||||
A1B2C4002EB4A0A100000004 /* KBAuthManager.m in Sources */,
|
||||
047C65532EBCBAC60035E841 /* KBCommunityVC.m in Sources */,
|
||||
A1B2C4212EB4B7A100000001 /* KBKeyboardPermissionManager.m in Sources */,
|
||||
04122FB02EC73C0100EF7AB3 /* KBVipReviewItemCell.m in Sources */,
|
||||
04122F822EC5FC6F00EF7AB3 /* KBJfPay.m in Sources */,
|
||||
04122F5D2EC5E5A900EF7AB3 /* KBLoginVM.m in Sources */,
|
||||
0459D1B42EBA284C00F2D189 /* KBSkinCenterVC.m in Sources */,
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "home_left_bg 1.png",
|
||||
"filename" : "home_left_bg.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "home_left_bg 2.png",
|
||||
"filename" : "home_left_bg 1.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 9.5 KiB |
BIN
keyBoard/Assets.xcassets/Home/home_left_bg.imageset/home_left_bg.png
vendored
Normal file
|
After Width: | Height: | Size: 7.4 KiB |
@@ -5,12 +5,12 @@
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "home_right_bg 1.png",
|
||||
"filename" : "home_right_bg.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "home_right_bg 2.png",
|
||||
"filename" : "home_right_bg 1.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 7.2 KiB |
|
Before Width: | Height: | Size: 9.0 KiB |
BIN
keyBoard/Assets.xcassets/Home/home_right_bg.imageset/home_right_bg.png
vendored
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
@@ -8,7 +8,7 @@
|
||||
#import "HomeHeadView.h"
|
||||
#import "UIImage+KBColor.h"
|
||||
#import "KBTopImageButton.h"
|
||||
#import "KBJfPay.h"
|
||||
#import "KBVipPay.h"
|
||||
|
||||
|
||||
@interface HomeHeadView()
|
||||
@@ -163,7 +163,7 @@
|
||||
#pragma mark - Actions
|
||||
- (void)onTapBuyAction {
|
||||
// if (self.onTapBuy) { self.onTapBuy(); }
|
||||
KBJfPay *vc = [[KBJfPay alloc] init];
|
||||
KBVipPay *vc = [[KBVipPay alloc] init];
|
||||
[KB_CURRENT_NAV pushViewController:vc animated:true];
|
||||
}
|
||||
|
||||
|
||||
@@ -180,11 +180,11 @@
|
||||
|
||||
[self.leftBgImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.top.equalTo(self.secWhiteContentView);
|
||||
// make.bottom.equalTo(self.secWhiteContentView);
|
||||
make.height.mas_equalTo(466);
|
||||
}];
|
||||
[self.rightBgImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.top.equalTo(self.secWhiteContentView);
|
||||
// make.bottom.equalTo(self.secWhiteContentView);
|
||||
make.height.mas_equalTo(466);
|
||||
}];
|
||||
|
||||
|
||||
|
||||
19
keyBoard/Class/Pay/V/KBVipPayHeaderView.h
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// KBVipPayHeaderView.h
|
||||
// keyBoard
|
||||
//
|
||||
// 顶部大头部视图:包含 5 张图片
|
||||
// - 高度:484 + 导航总高度
|
||||
// - 图片资源:pay_vip_icon、pay_ai_icon、pay_keyboard_icon、pay_chat_icon、pay_emotion_icon
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface KBVipPayHeaderView : UICollectionReusableView
|
||||
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@end
|
||||
|
||||
147
keyBoard/Class/Pay/V/KBVipPayHeaderView.m
Normal file
@@ -0,0 +1,147 @@
|
||||
//
|
||||
// KBVipPayHeaderView.m
|
||||
// keyBoard
|
||||
//
|
||||
// 中文注释:顶部头图区域,使用 Masonry 布局,包含 5 张图片。
|
||||
//
|
||||
|
||||
#import "KBVipPayHeaderView.h"
|
||||
|
||||
@interface KBVipPayHeaderView ()
|
||||
// 容器(为了便于以 KB_NAV_TOTAL_HEIGHT 作为内容起点)
|
||||
@property (nonatomic, strong) UIView *containerView;
|
||||
// 顶部大图:pay_vip_icon
|
||||
@property (nonatomic, strong) UIImageView *vipImageView;
|
||||
// 功能图标四宫格
|
||||
@property (nonatomic, strong) UIImageView *aiImageView;
|
||||
@property (nonatomic, strong) UIImageView *keyboardImageView;
|
||||
@property (nonatomic, strong) UIImageView *chatImageView;
|
||||
@property (nonatomic, strong) UIImageView *emotionImageView;
|
||||
@end
|
||||
|
||||
@implementation KBVipPayHeaderView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
|
||||
[self addSubview:self.containerView];
|
||||
[self.containerView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(self);
|
||||
}];
|
||||
|
||||
// 1. 顶部大图(略微下移,避开自定义导航栏)
|
||||
[self.containerView addSubview:self.vipImageView];
|
||||
[self.vipImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.containerView).offset(16);
|
||||
make.right.equalTo(self.containerView).offset(-16);
|
||||
make.top.equalTo(self.containerView).offset(KB_NAV_TOTAL_HEIGHT + 8);
|
||||
make.height.mas_equalTo(KBFit(180));
|
||||
}];
|
||||
|
||||
// 2. 下方四宫格图标(简单示意)
|
||||
UIView *g1 = [self gridItemWithImageView:self.aiImageView];
|
||||
UIView *g2 = [self gridItemWithImageView:self.keyboardImageView];
|
||||
UIView *g3 = [self gridItemWithImageView:self.chatImageView];
|
||||
UIView *g4 = [self gridItemWithImageView:self.emotionImageView];
|
||||
[self.containerView addSubview:g1];
|
||||
[self.containerView addSubview:g2];
|
||||
[self.containerView addSubview:g3];
|
||||
[self.containerView addSubview:g4];
|
||||
|
||||
CGFloat spacing = 12;
|
||||
[g1 mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.vipImageView);
|
||||
make.top.equalTo(self.vipImageView.mas_bottom).offset(18);
|
||||
make.height.mas_equalTo(KBFit(90));
|
||||
}];
|
||||
[g2 mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.equalTo(self.vipImageView);
|
||||
make.top.equalTo(g1);
|
||||
make.height.equalTo(g1);
|
||||
make.left.equalTo(g1.mas_right).offset(spacing);
|
||||
make.width.equalTo(g1);
|
||||
}];
|
||||
[g3 mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(g1);
|
||||
make.top.equalTo(g1.mas_bottom).offset(spacing);
|
||||
make.height.equalTo(g1);
|
||||
make.width.equalTo(g1);
|
||||
}];
|
||||
[g4 mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.right.equalTo(self.vipImageView);
|
||||
make.top.equalTo(g3);
|
||||
make.left.equalTo(g3.mas_right).offset(spacing);
|
||||
make.height.equalTo(g1);
|
||||
make.width.equalTo(g1);
|
||||
make.bottom.lessThanOrEqualTo(self.containerView).offset(-12);
|
||||
}];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Helpers
|
||||
- (UIView *)gridItemWithImageView:(UIImageView *)iv {
|
||||
// 简单白底圆角卡片承载图标
|
||||
UIView *v = [UIView new];
|
||||
v.backgroundColor = [UIColor colorWithWhite:0.97 alpha:1.0];
|
||||
v.layer.cornerRadius = 12;
|
||||
v.layer.masksToBounds = YES;
|
||||
[v addSubview:iv];
|
||||
[iv mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.center.equalTo(v);
|
||||
make.width.height.mas_equalTo(40);
|
||||
}];
|
||||
return v;
|
||||
}
|
||||
|
||||
#pragma mark - Lazy
|
||||
- (UIView *)containerView {
|
||||
if (!_containerView) {
|
||||
_containerView = [UIView new];
|
||||
_containerView.backgroundColor = [UIColor clearColor];
|
||||
}
|
||||
return _containerView;
|
||||
}
|
||||
|
||||
- (UIImageView *)vipImageView {
|
||||
if (!_vipImageView) {
|
||||
_vipImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"pay_vip_icon"]];
|
||||
_vipImageView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
_vipImageView.clipsToBounds = YES;
|
||||
_vipImageView.layer.cornerRadius = 14;
|
||||
}
|
||||
return _vipImageView;
|
||||
}
|
||||
|
||||
- (UIImageView *)aiImageView {
|
||||
if (!_aiImageView) {
|
||||
_aiImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"pay_ai_icon"]];
|
||||
_aiImageView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
}
|
||||
return _aiImageView;
|
||||
}
|
||||
- (UIImageView *)keyboardImageView {
|
||||
if (!_keyboardImageView) {
|
||||
_keyboardImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"pay_keyboard_icon"]];
|
||||
_keyboardImageView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
}
|
||||
return _keyboardImageView;
|
||||
}
|
||||
- (UIImageView *)chatImageView {
|
||||
if (!_chatImageView) {
|
||||
_chatImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"pay_chat_icon"]];
|
||||
_chatImageView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
}
|
||||
return _chatImageView;
|
||||
}
|
||||
- (UIImageView *)emotionImageView {
|
||||
if (!_emotionImageView) {
|
||||
_emotionImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"pay_emotion_icon"]];
|
||||
_emotionImageView.contentMode = UIViewContentModeScaleAspectFit;
|
||||
}
|
||||
return _emotionImageView;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
17
keyBoard/Class/Pay/V/KBVipReviewItemCell.h
Normal file
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// KBVipReviewItemCell.h
|
||||
// keyBoard
|
||||
//
|
||||
// 横向列表中的 item,包含 5 个爱心图标:pay_5aixin_icon
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface KBVipReviewItemCell : UICollectionViewCell
|
||||
- (void)configWithName:(NSString *)name text:(NSString *)text;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
124
keyBoard/Class/Pay/V/KBVipReviewItemCell.m
Normal file
@@ -0,0 +1,124 @@
|
||||
//
|
||||
// KBVipReviewItemCell.m
|
||||
// keyBoard
|
||||
//
|
||||
// 中文注释:简单的好评卡片,顶部头像/昵称,下面 5 个爱心图标,再下一行一段文案。
|
||||
//
|
||||
|
||||
#import "KBVipReviewItemCell.h"
|
||||
|
||||
@interface KBVipReviewItemCell ()
|
||||
@property (nonatomic, strong) UIView *cardView;
|
||||
@property (nonatomic, strong) UIImageView *avatarView;
|
||||
@property (nonatomic, strong) UILabel *nameLabel;
|
||||
@property (nonatomic, strong) UIStackView *heartsStack;
|
||||
@property (nonatomic, strong) UILabel *contentLabel;
|
||||
@end
|
||||
|
||||
@implementation KBVipReviewItemCell
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
self.contentView.backgroundColor = UIColor.clearColor;
|
||||
|
||||
[self.contentView addSubview:self.cardView];
|
||||
[self.cardView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(self.contentView);
|
||||
}];
|
||||
|
||||
[self.cardView addSubview:self.avatarView];
|
||||
[self.cardView addSubview:self.nameLabel];
|
||||
[self.cardView addSubview:self.heartsStack];
|
||||
[self.cardView addSubview:self.contentLabel];
|
||||
|
||||
[self.avatarView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.top.equalTo(self.cardView).offset(12);
|
||||
make.width.height.mas_equalTo(28);
|
||||
}];
|
||||
[self.nameLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerY.equalTo(self.avatarView);
|
||||
make.left.equalTo(self.avatarView.mas_right).offset(8);
|
||||
make.right.lessThanOrEqualTo(self.cardView).offset(-12);
|
||||
}];
|
||||
[self.heartsStack mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.avatarView);
|
||||
make.top.equalTo(self.avatarView.mas_bottom).offset(8);
|
||||
}];
|
||||
[self.contentLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.avatarView);
|
||||
make.right.equalTo(self.cardView).offset(-12);
|
||||
make.top.equalTo(self.heartsStack.mas_bottom).offset(6);
|
||||
make.bottom.lessThanOrEqualTo(self.cardView).offset(-12);
|
||||
}];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
self.cardView.layer.cornerRadius = 12;
|
||||
self.cardView.layer.masksToBounds = YES;
|
||||
}
|
||||
|
||||
- (void)configWithName:(NSString *)name text:(NSString *)text {
|
||||
self.nameLabel.text = name.length ? name : @"User";
|
||||
self.contentLabel.text = text.length ? text : @"I highly recommend this app.";
|
||||
}
|
||||
|
||||
#pragma mark - Lazy
|
||||
- (UIView *)cardView {
|
||||
if (!_cardView) {
|
||||
_cardView = [UIView new];
|
||||
_cardView.backgroundColor = [UIColor whiteColor];
|
||||
}
|
||||
return _cardView;
|
||||
}
|
||||
- (UIImageView *)avatarView {
|
||||
if (!_avatarView) {
|
||||
_avatarView = [UIImageView new];
|
||||
_avatarView.backgroundColor = [UIColor colorWithWhite:0.92 alpha:1.0];
|
||||
_avatarView.layer.cornerRadius = 14;
|
||||
_avatarView.layer.masksToBounds = YES;
|
||||
}
|
||||
return _avatarView;
|
||||
}
|
||||
- (UILabel *)nameLabel {
|
||||
if (!_nameLabel) {
|
||||
_nameLabel = [UILabel new];
|
||||
_nameLabel.textColor = [UIColor colorWithHex:KBBlackValue];
|
||||
_nameLabel.font = [UIFont systemFontOfSize:14 weight:UIFontWeightSemibold];
|
||||
_nameLabel.text = @"Sdsd666";
|
||||
}
|
||||
return _nameLabel;
|
||||
}
|
||||
- (UIStackView *)heartsStack {
|
||||
if (!_heartsStack) {
|
||||
_heartsStack = [[UIStackView alloc] init];
|
||||
_heartsStack.axis = UILayoutConstraintAxisHorizontal;
|
||||
_heartsStack.spacing = 4;
|
||||
_heartsStack.alignment = UIStackViewAlignmentCenter;
|
||||
_heartsStack.distribution = UIStackViewDistributionFillProportionally;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
UIImageView *iv = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"pay_5aixin_icon"]];
|
||||
iv.contentMode = UIViewContentModeScaleAspectFit;
|
||||
[iv mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.height.mas_equalTo(16);
|
||||
}];
|
||||
[_heartsStack addArrangedSubview:iv];
|
||||
}
|
||||
}
|
||||
return _heartsStack;
|
||||
}
|
||||
- (UILabel *)contentLabel {
|
||||
if (!_contentLabel) {
|
||||
_contentLabel = [UILabel new];
|
||||
_contentLabel.textColor = [UIColor colorWithWhite:0.25 alpha:1.0];
|
||||
_contentLabel.font = [UIFont systemFontOfSize:12];
|
||||
_contentLabel.numberOfLines = 2;
|
||||
_contentLabel.text = @"I Highly Recommend This App. It Taught Me How To Chat";
|
||||
}
|
||||
return _contentLabel;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
16
keyBoard/Class/Pay/V/KBVipReviewListCell.h
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// KBVipReviewListCell.h
|
||||
// keyBoard
|
||||
//
|
||||
// 末尾的横向滚动列表 Cell,内部自带一个 UICollectionView。
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface KBVipReviewListCell : UICollectionViewCell
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
82
keyBoard/Class/Pay/V/KBVipReviewListCell.m
Normal file
@@ -0,0 +1,82 @@
|
||||
//
|
||||
// KBVipReviewListCell.m
|
||||
// keyBoard
|
||||
//
|
||||
// 中文注释:底部 Cell,内部是横向滚动的 UICollectionView。
|
||||
//
|
||||
|
||||
#import "KBVipReviewListCell.h"
|
||||
#import "KBVipReviewItemCell.h"
|
||||
|
||||
static NSString * const kKBVipReviewItemCellId = @"kKBVipReviewItemCellId";
|
||||
|
||||
@interface KBVipReviewListCell () <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
|
||||
@property (nonatomic, strong) UICollectionView *collectionView; // 内部横向滚动
|
||||
@property (nonatomic, strong) NSArray<NSDictionary *> *data; // 简单模拟数据
|
||||
@end
|
||||
|
||||
@implementation KBVipReviewListCell
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
self.contentView.backgroundColor = [UIColor clearColor];
|
||||
[self.contentView addSubview:self.collectionView];
|
||||
[self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(self.contentView).insets(UIEdgeInsetsMake(0, 0, 0, 0));
|
||||
}];
|
||||
|
||||
// 模拟数据
|
||||
_data = @[
|
||||
@{@"name":@"Sdsd666", @"text":@"I Highly Recommend This App. It Taught Me How To Chat"},
|
||||
@{@"name":@"Joyce", @"text":@"Great keyboard and AI features!"},
|
||||
@{@"name":@"Luna", @"text":@"Amazing app, love it."},
|
||||
@{@"name":@"Mark", @"text":@"Helps with chat and emotion."},
|
||||
@{@"name":@"Alan", @"text":@"Useful personalized keyboard."},
|
||||
@{@"name":@"Coco", @"text":@"Recommend to friends."},
|
||||
];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - DataSource
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
return self.data.count;
|
||||
}
|
||||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
KBVipReviewItemCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kKBVipReviewItemCellId forIndexPath:indexPath];
|
||||
NSDictionary *d = self.data[indexPath.item];
|
||||
[cell configWithName:d[@"name"] text:d[@"text"]];
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - FlowLayout
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
CGFloat w = floor((KB_SCREEN_WIDTH - 16 - 16 - 10) / 2.0); // 一屏展示两个
|
||||
return CGSizeMake(MAX(120, w), 120);
|
||||
}
|
||||
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section { return 10; }
|
||||
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section { return 10; }
|
||||
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
|
||||
return UIEdgeInsetsMake(0, 16, 0, 16);
|
||||
}
|
||||
|
||||
#pragma mark - Lazy
|
||||
- (UICollectionView *)collectionView {
|
||||
if (!_collectionView) {
|
||||
UICollectionViewFlowLayout *layout = [UICollectionViewFlowLayout new];
|
||||
layout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
|
||||
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||
_collectionView.backgroundColor = UIColor.clearColor;
|
||||
_collectionView.showsHorizontalScrollIndicator = NO;
|
||||
_collectionView.dataSource = self;
|
||||
_collectionView.delegate = self;
|
||||
[_collectionView registerClass:KBVipReviewItemCell.class forCellWithReuseIdentifier:kKBVipReviewItemCellId];
|
||||
if (@available(iOS 11.0, *)) {
|
||||
_collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
||||
}
|
||||
}
|
||||
return _collectionView;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
20
keyBoard/Class/Pay/V/KBVipSubscribeCell.h
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// KBVipSubscribeCell.h
|
||||
// keyBoard
|
||||
//
|
||||
// 订阅选项 Cell:右侧选择按钮(pay_circle_normal / pay_circle_sel)
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface KBVipSubscribeCell : UICollectionViewCell
|
||||
/// 配置展示文案
|
||||
- (void)configTitle:(NSString *)title price:(NSString *)price strike:(nullable NSString *)strike;
|
||||
/// 同步选中态(更新右侧选择图标、边框颜色)
|
||||
- (void)applySelected:(BOOL)selected animated:(BOOL)animated;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
162
keyBoard/Class/Pay/V/KBVipSubscribeCell.m
Normal file
@@ -0,0 +1,162 @@
|
||||
//
|
||||
// KBVipSubscribeCell.m
|
||||
// keyBoard
|
||||
//
|
||||
// 中文注释:订阅选项样式,右侧有选中图标,使用 mas 布局 + 懒加载。
|
||||
//
|
||||
|
||||
#import "KBVipSubscribeCell.h"
|
||||
|
||||
@interface KBVipSubscribeCell ()
|
||||
@property (nonatomic, strong) UIView *cardView; // 白色卡片背景
|
||||
@property (nonatomic, strong) UILabel *titleLabel; // “Monthly Subscription”
|
||||
@property (nonatomic, strong) UILabel *priceLabel; // “$4.49”
|
||||
@property (nonatomic, strong) UILabel *strikeLabel; // 删除线原价
|
||||
@property (nonatomic, strong) UIButton *selectButton; // 右侧选择按钮
|
||||
@property (nonatomic, strong) CAShapeLayer *borderLayer; // 选中边框
|
||||
@end
|
||||
|
||||
@implementation KBVipSubscribeCell
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
self.contentView.backgroundColor = [UIColor clearColor];
|
||||
|
||||
[self.contentView addSubview:self.cardView];
|
||||
[self.cardView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.edges.equalTo(self.contentView);
|
||||
}];
|
||||
|
||||
[self.cardView addSubview:self.titleLabel];
|
||||
[self.cardView addSubview:self.priceLabel];
|
||||
[self.cardView addSubview:self.strikeLabel];
|
||||
[self.cardView addSubview:self.selectButton];
|
||||
|
||||
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.cardView).offset(16);
|
||||
make.top.equalTo(self.cardView).offset(16);
|
||||
}];
|
||||
[self.priceLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.titleLabel);
|
||||
make.top.equalTo(self.titleLabel.mas_bottom).offset(6);
|
||||
}];
|
||||
[self.strikeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.equalTo(self.priceLabel.mas_right).offset(10);
|
||||
make.centerY.equalTo(self.priceLabel);
|
||||
}];
|
||||
[self.selectButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerY.equalTo(self.cardView);
|
||||
make.right.equalTo(self.cardView).offset(-16);
|
||||
make.width.height.mas_equalTo(28);
|
||||
}];
|
||||
|
||||
// 边框层(选中时显示主题绿)
|
||||
self.borderLayer = [CAShapeLayer layer];
|
||||
self.borderLayer.strokeColor = [UIColor colorWithWhite:0.9 alpha:1.0].CGColor;
|
||||
// 使用透明填充,避免遮挡内部子视图;只显示描边
|
||||
self.borderLayer.fillColor = UIColor.clearColor.CGColor;
|
||||
self.borderLayer.lineWidth = 1.5;
|
||||
// 放到底层,避免盖住 label/button(修复滚动后偶现内容被遮挡变空白)
|
||||
[self.cardView.layer insertSublayer:self.borderLayer atIndex:0];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
CGFloat radius = 16;
|
||||
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:self.cardView.bounds cornerRadius:radius];
|
||||
self.cardView.layer.cornerRadius = radius;
|
||||
self.cardView.layer.masksToBounds = YES;
|
||||
self.borderLayer.frame = self.cardView.bounds;
|
||||
self.borderLayer.path = path.CGPath;
|
||||
}
|
||||
|
||||
- (void)prepareForReuse {
|
||||
[super prepareForReuse];
|
||||
[self applySelected:NO animated:NO];
|
||||
}
|
||||
|
||||
- (void)setSelected:(BOOL)selected {
|
||||
[super setSelected:selected];
|
||||
[self applySelected:selected animated:NO];
|
||||
}
|
||||
|
||||
- (void)configTitle:(NSString *)title price:(NSString *)price strike:(nullable NSString *)strike {
|
||||
self.titleLabel.text = title.length ? title : @"Monthly Subscription";
|
||||
self.priceLabel.text = price.length ? price : @"$4.49";
|
||||
self.strikeLabel.hidden = (strike.length == 0);
|
||||
if (strike.length) {
|
||||
// 加删除线
|
||||
NSDictionary *attr = @{
|
||||
NSStrikethroughStyleAttributeName: @(NSUnderlineStyleSingle),
|
||||
NSForegroundColorAttributeName: [UIColor colorWithWhite:0.7 alpha:1.0]
|
||||
};
|
||||
self.strikeLabel.attributedText = [[NSAttributedString alloc] initWithString:strike attributes:attr];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)applySelected:(BOOL)selected animated:(BOOL)animated {
|
||||
UIImage *img = [UIImage imageNamed:(selected ? @"pay_circle_sel" : @"pay_circle_normal")];
|
||||
[self.selectButton setImage:img forState:UIControlStateNormal];
|
||||
CGColorRef color = (selected ? [UIColor colorWithHex:KBColorValue].CGColor : [UIColor colorWithWhite:0.9 alpha:1.0].CGColor);
|
||||
void (^changes)(void) = ^{
|
||||
self.borderLayer.strokeColor = color;
|
||||
self.cardView.layer.shadowOpacity = selected ? 0.12 : 0.0;
|
||||
self.cardView.layer.shadowColor = [UIColor colorWithHex:KBColorValue].CGColor;
|
||||
self.cardView.layer.shadowRadius = selected ? 8 : 0;
|
||||
self.cardView.layer.shadowOffset = CGSizeMake(0, selected ? 4 : 0);
|
||||
};
|
||||
if (animated) {
|
||||
[UIView animateWithDuration:0.15 animations:changes];
|
||||
} else {
|
||||
changes();
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Lazy
|
||||
- (UIView *)cardView {
|
||||
if (!_cardView) {
|
||||
_cardView = [UIView new];
|
||||
_cardView.backgroundColor = [UIColor whiteColor];
|
||||
}
|
||||
return _cardView;
|
||||
}
|
||||
- (UILabel *)titleLabel {
|
||||
if (!_titleLabel) {
|
||||
_titleLabel = [UILabel new];
|
||||
_titleLabel.text = @"Monthly Subscription";
|
||||
_titleLabel.textColor = [UIColor colorWithHex:KBBlackValue];
|
||||
_titleLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightSemibold];
|
||||
}
|
||||
return _titleLabel;
|
||||
}
|
||||
- (UILabel *)priceLabel {
|
||||
if (!_priceLabel) {
|
||||
_priceLabel = [UILabel new];
|
||||
_priceLabel.text = @"$4.49";
|
||||
_priceLabel.textColor = [UIColor colorWithHex:KBBlackValue];
|
||||
_priceLabel.font = [UIFont systemFontOfSize:28 weight:UIFontWeightBold];
|
||||
}
|
||||
return _priceLabel;
|
||||
}
|
||||
- (UILabel *)strikeLabel {
|
||||
if (!_strikeLabel) {
|
||||
_strikeLabel = [UILabel new];
|
||||
_strikeLabel.text = @"$4.49";
|
||||
_strikeLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightSemibold];
|
||||
_strikeLabel.textColor = [UIColor colorWithWhite:0.7 alpha:1.0];
|
||||
}
|
||||
return _strikeLabel;
|
||||
}
|
||||
- (UIButton *)selectButton {
|
||||
if (!_selectButton) {
|
||||
_selectButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_selectButton setImage:[UIImage imageNamed:@"pay_circle_normal"] forState:UIControlStateNormal];
|
||||
_selectButton.userInteractionEnabled = NO; // 由外层控制选中
|
||||
_selectButton.contentMode = UIViewContentModeCenter;
|
||||
}
|
||||
return _selectButton;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -9,8 +9,8 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// VIP 订阅页(整体使用 UICollectionView,上下滚动)
|
||||
@interface KBVipPay : UIViewController
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -6,8 +6,19 @@
|
||||
//
|
||||
|
||||
#import "KBVipPay.h"
|
||||
#import "KBVipPayHeaderView.h"
|
||||
#import "KBVipSubscribeCell.h"
|
||||
#import "KBVipReviewListCell.h"
|
||||
|
||||
@interface KBVipPay ()
|
||||
static NSString * const kKBVipHeaderId = @"kKBVipHeaderId";
|
||||
static NSString * const kKBVipSubscribeCellId = @"kKBVipSubscribeCellId";
|
||||
static NSString * const kKBVipReviewListCellId = @"kKBVipReviewListCellId";
|
||||
|
||||
@interface KBVipPay () <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
|
||||
@property (nonatomic, strong) UICollectionView *collectionView; // 主列表(竖向滚动)
|
||||
@property (nonatomic, strong) NSArray<NSDictionary *> *plans; // 订阅方案数组
|
||||
@property (nonatomic, assign) NSInteger selectedIndex; // 当前选中的方案索引
|
||||
@property (nonatomic, strong) UIButton *closeButton; // 当前选中的方案索引
|
||||
|
||||
@end
|
||||
|
||||
@@ -15,17 +26,168 @@
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view.
|
||||
// 标题与导航样式
|
||||
// self.kb_titleLabel.text = @"VIP";
|
||||
// self.kb_navView.backgroundColor = [UIColor clearColor];
|
||||
|
||||
self.view.backgroundColor = [UIColor colorWithWhite:0.97 alpha:1.0];
|
||||
|
||||
// 初始化数据(简单演示)
|
||||
self.plans = @[
|
||||
@{@"title":@"Monthly Subscription", @"price":@"$4.49", @"strike":@"$4.49"},
|
||||
@{@"title":@"Monthly Subscription", @"price":@"$4.49", @"strike":@"$4.49"},
|
||||
@{@"title":@"Monthly Subscription", @"price":@"$4.49", @"strike":@"$4.49"},
|
||||
];
|
||||
self.selectedIndex = 1; // 默认选中第二项
|
||||
[self.view addSubview:self.closeButton];
|
||||
[self.closeButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.top.equalTo(self.view).offset(KB_NAV_TOTAL_HEIGHT);
|
||||
make.left.equalTo(self.view).offset(15);
|
||||
make.width.height.mas_equalTo(36);
|
||||
}];
|
||||
// 组装主列表
|
||||
[self.view addSubview:self.collectionView];
|
||||
[self.collectionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.left.right.bottom.equalTo(self.view);
|
||||
make.top.equalTo(self.view).offset(KB_NAV_TOTAL_HEIGHT);
|
||||
}];
|
||||
|
||||
[self.collectionView reloadData];
|
||||
}
|
||||
|
||||
/*
|
||||
#pragma mark - Navigation
|
||||
|
||||
// In a storyboard-based application, you will often want to do a little preparation before navigation
|
||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||
// Get the new view controller using [segue destinationViewController].
|
||||
// Pass the selected object to the new view controller.
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
[super viewDidAppear:animated];
|
||||
// 首次进入,确保订阅项保持选中态(避免首屏仅显示 Header,待滚动出现时没有选中样式)
|
||||
NSIndexPath *ip = [NSIndexPath indexPathForItem:self.selectedIndex inSection:1];
|
||||
if (!ip) { return; }
|
||||
// 系统层面也置为选中
|
||||
[self.collectionView selectItemAtIndexPath:ip animated:NO scrollPosition:UICollectionViewScrollPositionNone];
|
||||
// 若此时 cell 不可见,willDisplay 再兜底
|
||||
KBVipSubscribeCell *cell = (KBVipSubscribeCell *)[self.collectionView cellForItemAtIndexPath:ip];
|
||||
if (cell) { [cell applySelected:YES animated:NO]; }
|
||||
}
|
||||
*/
|
||||
|
||||
#pragma mark - UICollectionView DataSource
|
||||
|
||||
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
|
||||
// 0:头部;1:订阅选项;2:底部横滑好评
|
||||
return 3;
|
||||
}
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
if (section == 1) { return self.plans.count; }
|
||||
if (section == 2) { return 1; }
|
||||
return 0; // 头部仅使用 header
|
||||
}
|
||||
|
||||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (indexPath.section == 1) {
|
||||
KBVipSubscribeCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kKBVipSubscribeCellId forIndexPath:indexPath];
|
||||
NSDictionary *plan = self.plans[indexPath.item];
|
||||
[cell configTitle:plan[@"title"] price:plan[@"price"] strike:plan[@"strike"]];
|
||||
[cell applySelected:(indexPath.item == self.selectedIndex) animated:NO];
|
||||
return cell;
|
||||
} else {
|
||||
KBVipReviewListCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kKBVipReviewListCellId forIndexPath:indexPath];
|
||||
return cell;
|
||||
}
|
||||
}
|
||||
|
||||
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath {
|
||||
if (indexPath.section == 0 && [kind isEqualToString:UICollectionElementKindSectionHeader]) {
|
||||
KBVipPayHeaderView *header = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:kKBVipHeaderId forIndexPath:indexPath];
|
||||
return header;
|
||||
}
|
||||
return [UICollectionReusableView new];
|
||||
}
|
||||
|
||||
#pragma mark - UICollectionView Delegate
|
||||
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
if (indexPath.section != 1) { return; }
|
||||
if (self.selectedIndex == indexPath.item) { return; }
|
||||
NSInteger old = self.selectedIndex;
|
||||
self.selectedIndex = indexPath.item;
|
||||
|
||||
KBVipSubscribeCell *newCell = (KBVipSubscribeCell *)[collectionView cellForItemAtIndexPath:indexPath];
|
||||
[newCell applySelected:YES animated:YES];
|
||||
if (old >= 0 && old < self.plans.count) {
|
||||
NSIndexPath *oldIP = [NSIndexPath indexPathForItem:old inSection:1];
|
||||
KBVipSubscribeCell *oldCell = (KBVipSubscribeCell *)[collectionView cellForItemAtIndexPath:oldIP];
|
||||
[oldCell applySelected:NO animated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
// 兜底:当订阅项第一次出现在屏幕上,强制同步选中样式
|
||||
if (indexPath.section == 1 && [cell isKindOfClass:KBVipSubscribeCell.class]) {
|
||||
BOOL sel = (indexPath.item == self.selectedIndex);
|
||||
KBVipSubscribeCell *c = (KBVipSubscribeCell *)cell;
|
||||
if (sel) {
|
||||
[collectionView selectItemAtIndexPath:indexPath animated:NO scrollPosition:UICollectionViewScrollPositionNone];
|
||||
}
|
||||
[c applySelected:sel animated:NO];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - FlowLayout
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
CGFloat w = KB_SCREEN_WIDTH - 32;
|
||||
if (indexPath.section == 1) {
|
||||
return CGSizeMake(w, 106);
|
||||
} else {
|
||||
return CGSizeMake(w, 140);
|
||||
}
|
||||
}
|
||||
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section {
|
||||
if (section == 0) {
|
||||
// 头部高度 = 484 + 导航栏高度
|
||||
return CGSizeMake(KB_SCREEN_WIDTH, 484 + KB_NAV_TOTAL_HEIGHT);
|
||||
}
|
||||
return CGSizeZero;
|
||||
}
|
||||
|
||||
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
|
||||
if (section == 1) { return 14; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
|
||||
if (section == 1) {
|
||||
return UIEdgeInsetsMake(0, 16, 10, 16);
|
||||
} else if (section == 2) {
|
||||
return UIEdgeInsetsMake(10, 16, 20, 16);
|
||||
}
|
||||
return UIEdgeInsetsZero;
|
||||
}
|
||||
|
||||
#pragma mark - Lazy
|
||||
- (UICollectionView *)collectionView {
|
||||
if (!_collectionView) {
|
||||
UICollectionViewFlowLayout *layout = [UICollectionViewFlowLayout new];
|
||||
layout.scrollDirection = UICollectionViewScrollDirectionVertical;
|
||||
_collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||
_collectionView.backgroundColor = [UIColor clearColor];
|
||||
_collectionView.dataSource = self;
|
||||
_collectionView.delegate = self;
|
||||
_collectionView.alwaysBounceVertical = YES;
|
||||
if (@available(iOS 11.0, *)) {
|
||||
_collectionView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
||||
}
|
||||
[_collectionView registerClass:KBVipPayHeaderView.class forSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:kKBVipHeaderId];
|
||||
[_collectionView registerClass:KBVipSubscribeCell.class forCellWithReuseIdentifier:kKBVipSubscribeCellId];
|
||||
[_collectionView registerClass:KBVipReviewListCell.class forCellWithReuseIdentifier:kKBVipReviewListCellId];
|
||||
}
|
||||
return _collectionView;
|
||||
}
|
||||
|
||||
|
||||
- (UIButton *)closeButton {
|
||||
if (!_closeButton) {
|
||||
_closeButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_closeButton setImage:[UIImage imageNamed:@"white_close_icon"] forState:UIControlStateNormal];
|
||||
[_closeButton addTarget:self action:@selector(onTapClose) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _closeButton;
|
||||
}
|
||||
@end
|
||||
|
||||