-
4HC.xcodeproj/project.pbxproj
-
5HC.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
-
16HC.xcodeproj/project.xcworkspace/xcuserdata/huilinli.xcuserdatad/WorkspaceSettings.xcsettings
-
72HC.xcodeproj/xcuserdata/huilinli.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
-
2HC/AppDelegate.h
-
7HC/AppDelegate.m
-
21HC/Assets.xcassets/banner1.imageset/Contents.json
-
BINHC/Assets.xcassets/banner1.imageset/banner1.jpg
-
21HC/Assets.xcassets/banner2.imageset/Contents.json
-
BINHC/Assets.xcassets/banner2.imageset/banner2.jpg
-
21HC/Assets.xcassets/email.imageset/Contents.json
-
BINHC/Assets.xcassets/email.imageset/email.jpg
-
21HC/Assets.xcassets/hqz.imageset/Contents.json
-
BINHC/Assets.xcassets/hqz.imageset/hqz.jpg
-
20HC/Assets.xcassets/image.imageset/Contents.json
-
BINHC/Assets.xcassets/logo.imageset/20251117-225344.jpg
-
21HC/Assets.xcassets/logo.imageset/Contents.json
-
BINHC/Assets.xcassets/logo.jpg
-
21HC/Assets.xcassets/singapore_flag.imageset/Contents.json
-
BINHC/Assets.xcassets/singapore_flag.imageset/singapore_flag.jpg
-
16HC/CNViewController.h
-
12HC/CNViewController.m
-
16HC/ChartViewController.h
-
592HC/ChartViewController.m
-
19HC/CommonTabBar.h
-
94HC/CommonTabBar.m
-
18HC/CountryModel.h
-
20HC/CountryModel.m
-
45HC/HomeViewController.h
-
634HC/HomeViewController.m
-
16HC/MLXYViewController.h
-
442HC/MLXYViewController.m
-
18HC/MyViewController.h
-
390HC/MyViewController.m
-
16HC/QuotationViewController.h
-
258HC/QuotationViewController.m
-
22HC/SceneDelegate.m
-
36HC/StockKLineModel.h
-
21HC/StockKLineModel.m
-
3HC/ViewController.h
-
279HC/ViewController.m
@ -0,0 +1,5 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
|||
<plist version="1.0"> |
|||
<dict/> |
|||
</plist> |
|||
@ -0,0 +1,16 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
|||
<plist version="1.0"> |
|||
<dict> |
|||
<key>BuildLocationStyle</key> |
|||
<string>UseAppPreferences</string> |
|||
<key>CompilationCachingSetting</key> |
|||
<string>Default</string> |
|||
<key>CustomBuildLocationType</key> |
|||
<string>RelativeToDerivedData</string> |
|||
<key>DerivedDataLocationStyle</key> |
|||
<string>Default</string> |
|||
<key>ShowSharedSchemesAutomaticallyEnabled</key> |
|||
<true/> |
|||
</dict> |
|||
</plist> |
|||
@ -0,0 +1,72 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<Bucket |
|||
uuid = "E5AAA2DB-88F5-499D-B52C-3BC768440386" |
|||
type = "1" |
|||
version = "2.0"> |
|||
<Breakpoints> |
|||
<BreakpointProxy |
|||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> |
|||
<BreakpointContent |
|||
uuid = "C0178EEE-BAE9-481C-89D7-E23AE1320BBC" |
|||
shouldBeEnabled = "No" |
|||
ignoreCount = "0" |
|||
continueAfterRunningActions = "No" |
|||
filePath = "HC/ViewController.m" |
|||
startingColumnNumber = "9223372036854775807" |
|||
endingColumnNumber = "9223372036854775807" |
|||
startingLineNumber = "206" |
|||
endingLineNumber = "206" |
|||
landmarkName = "-setupConstraints" |
|||
landmarkType = "7"> |
|||
</BreakpointContent> |
|||
</BreakpointProxy> |
|||
<BreakpointProxy |
|||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> |
|||
<BreakpointContent |
|||
uuid = "E0BA58D2-B977-4CD8-A825-57A0428B1AEA" |
|||
shouldBeEnabled = "No" |
|||
ignoreCount = "0" |
|||
continueAfterRunningActions = "No" |
|||
filePath = "HC/HomeViewController.h" |
|||
startingColumnNumber = "9223372036854775807" |
|||
endingColumnNumber = "9223372036854775807" |
|||
startingLineNumber = "12" |
|||
endingLineNumber = "12" |
|||
landmarkName = "HomeViewController" |
|||
landmarkType = "2"> |
|||
</BreakpointContent> |
|||
</BreakpointProxy> |
|||
<BreakpointProxy |
|||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> |
|||
<BreakpointContent |
|||
uuid = "D5AC1EC8-1AFB-409C-AECD-7665735E5E22" |
|||
shouldBeEnabled = "No" |
|||
ignoreCount = "0" |
|||
continueAfterRunningActions = "No" |
|||
filePath = "HC/HomeViewController.m" |
|||
startingColumnNumber = "9223372036854775807" |
|||
endingColumnNumber = "9223372036854775807" |
|||
startingLineNumber = "399" |
|||
endingLineNumber = "399" |
|||
landmarkName = "-setupConstraints" |
|||
landmarkType = "7"> |
|||
</BreakpointContent> |
|||
</BreakpointProxy> |
|||
<BreakpointProxy |
|||
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> |
|||
<BreakpointContent |
|||
uuid = "F6BBF337-745E-4379-B25C-7E9CA910F97C" |
|||
shouldBeEnabled = "No" |
|||
ignoreCount = "0" |
|||
continueAfterRunningActions = "No" |
|||
filePath = "HC/HomeViewController.m" |
|||
startingColumnNumber = "9223372036854775807" |
|||
endingColumnNumber = "9223372036854775807" |
|||
startingLineNumber = "63" |
|||
endingLineNumber = "63" |
|||
landmarkName = "-setupSubviews" |
|||
landmarkType = "7"> |
|||
</BreakpointContent> |
|||
</BreakpointProxy> |
|||
</Breakpoints> |
|||
</Bucket> |
|||
@ -0,0 +1,21 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"filename" : "banner1.jpg", |
|||
"idiom" : "universal", |
|||
"scale" : "1x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "2x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "3x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"author" : "xcode", |
|||
"version" : 1 |
|||
} |
|||
} |
|||
|
After Width: 1161 | Height: 378 | Size: 21 KiB |
@ -0,0 +1,21 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"filename" : "banner2.jpg", |
|||
"idiom" : "universal", |
|||
"scale" : "1x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "2x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "3x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"author" : "xcode", |
|||
"version" : 1 |
|||
} |
|||
} |
|||
|
After Width: 1161 | Height: 378 | Size: 21 KiB |
@ -0,0 +1,21 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"filename" : "email.jpg", |
|||
"idiom" : "universal", |
|||
"scale" : "1x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "2x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "3x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"author" : "xcode", |
|||
"version" : 1 |
|||
} |
|||
} |
|||
|
After Width: 75 | Height: 55 | Size: 1.4 KiB |
@ -0,0 +1,21 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"filename" : "hqz.jpg", |
|||
"idiom" : "universal", |
|||
"scale" : "1x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "2x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "3x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"author" : "xcode", |
|||
"version" : 1 |
|||
} |
|||
} |
|||
|
After Width: 602 | Height: 582 | Size: 258 KiB |
@ -0,0 +1,20 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "1x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "2x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "3x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"author" : "xcode", |
|||
"version" : 1 |
|||
} |
|||
} |
|||
|
After Width: 143 | Height: 142 | Size: 3.1 KiB |
@ -0,0 +1,21 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"filename" : "20251117-225344.jpg", |
|||
"idiom" : "universal", |
|||
"scale" : "1x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "2x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "3x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"author" : "xcode", |
|||
"version" : 1 |
|||
} |
|||
} |
|||
|
After Width: 143 | Height: 142 | Size: 3.1 KiB |
@ -0,0 +1,21 @@ |
|||
{ |
|||
"images" : [ |
|||
{ |
|||
"filename" : "singapore_flag.jpg", |
|||
"idiom" : "universal", |
|||
"scale" : "1x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "2x" |
|||
}, |
|||
{ |
|||
"idiom" : "universal", |
|||
"scale" : "3x" |
|||
} |
|||
], |
|||
"info" : { |
|||
"author" : "xcode", |
|||
"version" : 1 |
|||
} |
|||
} |
|||
|
After Width: 146 | Height: 87 | Size: 2.1 KiB |
@ -0,0 +1,16 @@ |
|||
// |
|||
// CNViewController.h |
|||
// HC |
|||
// |
|||
// Created by huilinLi on 2025/11/26. |
|||
// |
|||
|
|||
#import <UIKit/UIKit.h> |
|||
|
|||
NS_ASSUME_NONNULL_BEGIN |
|||
|
|||
@interface CNViewController : UIViewController |
|||
|
|||
@end |
|||
|
|||
NS_ASSUME_NONNULL_END |
|||
@ -0,0 +1,12 @@ |
|||
// |
|||
// CNViewController.m |
|||
// HC |
|||
// |
|||
// Created by huilinLi on 2025/11/26. |
|||
// |
|||
|
|||
#import "CNViewController.h" |
|||
|
|||
@implementation CNViewController |
|||
|
|||
@end |
|||
@ -0,0 +1,16 @@ |
|||
// |
|||
// ChartViewController.h |
|||
// HC |
|||
// |
|||
// Created by huilinLi on 2025/11/27. |
|||
// |
|||
|
|||
#import <UIKit/UIKit.h> |
|||
|
|||
NS_ASSUME_NONNULL_BEGIN |
|||
|
|||
@interface ChartViewController : UIViewController |
|||
|
|||
@end |
|||
|
|||
NS_ASSUME_NONNULL_END |
|||
@ -0,0 +1,592 @@ |
|||
// ChartViewController.m |
|||
// HC |
|||
// |
|||
// Created by huilinLi on 2025/11/27. |
|||
// |
|||
|
|||
#import "ChartViewController.h" |
|||
#import "StockKLineModel.h" |
|||
|
|||
@interface ChartViewController () |
|||
|
|||
// 上方卡片容器 |
|||
@property (nonatomic, strong) UIView *cardContainer; |
|||
// k线选择项容器 |
|||
@property (nonatomic, strong) UIView *kSelectContainer; |
|||
// K线图表容器 |
|||
@property (nonatomic, strong) UIView *kLineContainer; |
|||
// K线图表滚动视图 |
|||
@property (nonatomic, strong) UIScrollView *kLineScrollView; |
|||
|
|||
// K线数据 |
|||
@property (nonatomic, strong) NSArray *kLineData; |
|||
// 价格刻度标签 |
|||
@property (nonatomic, strong) NSArray *priceLabels; |
|||
// 日期刻度标签 |
|||
@property (nonatomic, strong) NSArray *dateLabels; |
|||
|
|||
// 默认展示的K线数量 |
|||
@property (nonatomic, assign) NSInteger visibleKLineCount; |
|||
|
|||
@end |
|||
|
|||
@implementation ChartViewController |
|||
|
|||
- (void)viewDidLoad { |
|||
[super viewDidLoad]; |
|||
self.view.backgroundColor = [UIColor blackColor]; |
|||
|
|||
self.visibleKLineCount = 40; |
|||
|
|||
[self generateMockData]; |
|||
[self setupSubviews]; |
|||
[self setupConstraints]; |
|||
|
|||
dispatch_async(dispatch_get_main_queue(), ^{ |
|||
[self drawKLineChart]; |
|||
|
|||
if (self.kLineScrollView.contentSize.width > self.kLineScrollView.bounds.size.width) { |
|||
CGPoint offset = CGPointMake(self.kLineScrollView.contentSize.width - self.kLineScrollView.bounds.size.width, 0); |
|||
[self.kLineScrollView setContentOffset:offset animated:NO]; |
|||
} |
|||
}); |
|||
} |
|||
|
|||
#pragma mark - UI Setup |
|||
-(void) setupSubviews{ |
|||
// 卡片容器 |
|||
_cardContainer = [[UIView alloc] init]; |
|||
_cardContainer.backgroundColor = [UIColor colorWithRed:26.0/255.0 |
|||
green:26.0/255.0 |
|||
blue:2.0/255.0 |
|||
alpha:1.0]; |
|||
_cardContainer.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:_cardContainer]; |
|||
|
|||
UILabel *cardLabel1 = [[UILabel alloc] init]; |
|||
cardLabel1.text = @"1617.060"; |
|||
cardLabel1.textColor = [UIColor redColor]; |
|||
cardLabel1.font = [UIFont systemFontOfSize:15]; |
|||
cardLabel1.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[_cardContainer addSubview:cardLabel1]; |
|||
|
|||
UILabel *cardLabel2 = [[UILabel alloc] init]; |
|||
cardLabel2.text = @"-7.470"; |
|||
cardLabel2.textColor = [UIColor redColor]; |
|||
cardLabel2.font = [UIFont systemFontOfSize:8]; |
|||
cardLabel2.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[_cardContainer addSubview:cardLabel2]; |
|||
|
|||
UILabel *cardLabel3 = [[UILabel alloc] init]; |
|||
cardLabel3.text = @"-0.461%"; |
|||
cardLabel3.textColor = [UIColor redColor]; |
|||
cardLabel3.font = [UIFont systemFontOfSize:8]; |
|||
cardLabel3.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[_cardContainer addSubview:cardLabel3]; |
|||
|
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[cardLabel1.topAnchor constraintEqualToAnchor:_cardContainer.topAnchor constant:25], |
|||
[cardLabel1.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:10], |
|||
|
|||
[cardLabel2.topAnchor constraintEqualToAnchor:_cardContainer.topAnchor constant:50], |
|||
[cardLabel2.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant: 8], |
|||
|
|||
[cardLabel3.topAnchor constraintEqualToAnchor:_cardContainer.topAnchor constant:50], |
|||
[cardLabel3.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant: 45] |
|||
]]; |
|||
|
|||
UILabel *cardLabelHeight = [[UILabel alloc] init]; |
|||
cardLabelHeight.text = @"高"; |
|||
cardLabelHeight.textColor = [UIColor colorWithRed:0.2 green:0.2 blue:0.2 alpha:1]; |
|||
cardLabelHeight.font = [UIFont systemFontOfSize:15]; |
|||
cardLabelHeight.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[_cardContainer addSubview:cardLabelHeight]; |
|||
|
|||
UILabel *cardLabelStart = [[UILabel alloc] init]; |
|||
cardLabelStart.text = @"开"; |
|||
cardLabelStart.textColor = [UIColor colorWithRed:0.2 green:0.2 blue:0.2 alpha:1]; |
|||
cardLabelStart.font = [UIFont systemFontOfSize:15]; |
|||
cardLabelStart.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[_cardContainer addSubview:cardLabelStart]; |
|||
|
|||
UILabel *cardLabelVolume = [[UILabel alloc] init]; |
|||
cardLabelVolume.text = @"量"; |
|||
cardLabelVolume.textColor = [UIColor colorWithRed:0.2 green:0.2 blue:0.2 alpha:1]; |
|||
cardLabelVolume.font = [UIFont systemFontOfSize:15]; |
|||
cardLabelVolume.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[_cardContainer addSubview:cardLabelVolume]; |
|||
|
|||
UILabel *cardLabelLow = [[UILabel alloc] init]; |
|||
cardLabelLow.text = @"低"; |
|||
cardLabelLow.textColor = [UIColor colorWithRed:0.2 green:0.2 blue:0.2 alpha:1]; |
|||
cardLabelLow.font = [UIFont systemFontOfSize:15]; |
|||
cardLabelLow.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[_cardContainer addSubview:cardLabelLow]; |
|||
|
|||
UILabel *cardLabelChange = [[UILabel alloc] init]; |
|||
cardLabelChange.text = @"换"; |
|||
cardLabelChange.textColor = [UIColor colorWithRed:0.2 green:0.2 blue:0.2 alpha:1]; |
|||
cardLabelChange.font = [UIFont systemFontOfSize:15]; |
|||
cardLabelChange.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[_cardContainer addSubview:cardLabelChange]; |
|||
|
|||
UILabel *cardLabelQuota = [[UILabel alloc] init]; |
|||
cardLabelQuota.text = @"额"; |
|||
cardLabelQuota.textColor = [UIColor colorWithRed:0.2 green:0.2 blue:0.2 alpha:1]; |
|||
cardLabelQuota.font = [UIFont systemFontOfSize:15]; |
|||
cardLabelQuota.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[_cardContainer addSubview:cardLabelQuota]; |
|||
|
|||
UILabel *cardNumHeight = [[UILabel alloc] init]; |
|||
cardNumHeight.text = @"1617.260"; |
|||
cardNumHeight.textColor = [UIColor redColor]; |
|||
cardNumHeight.font = [UIFont systemFontOfSize:12]; |
|||
cardNumHeight.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[_cardContainer addSubview:cardNumHeight]; |
|||
|
|||
UILabel *cardNumStart = [[UILabel alloc] init]; |
|||
cardNumStart.text = @"1616.750"; |
|||
cardNumStart.textColor = [UIColor redColor]; |
|||
cardNumStart.font = [UIFont systemFontOfSize:12]; |
|||
cardNumStart.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[_cardContainer addSubview:cardNumStart]; |
|||
|
|||
UILabel *cardNumVolume = [[UILabel alloc] init]; |
|||
cardNumVolume.text = @"1.511亿"; |
|||
cardNumVolume.textColor = [UIColor whiteColor]; |
|||
cardNumVolume.font = [UIFont systemFontOfSize:12]; |
|||
cardNumVolume.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[_cardContainer addSubview:cardNumVolume]; |
|||
|
|||
UILabel *cardNumLow = [[UILabel alloc] init]; |
|||
cardNumLow.text = @"1608.850"; |
|||
cardNumLow.textColor = [UIColor whiteColor]; |
|||
cardNumLow.font = [UIFont systemFontOfSize:12]; |
|||
cardNumLow.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[_cardContainer addSubview:cardNumLow]; |
|||
|
|||
UILabel *cardNumChange = [[UILabel alloc] init]; |
|||
cardNumChange.text = @"--"; |
|||
cardNumChange.textColor = [UIColor whiteColor]; |
|||
cardNumChange.font = [UIFont systemFontOfSize:12]; |
|||
cardNumChange.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[_cardContainer addSubview:cardNumChange]; |
|||
|
|||
UILabel *cardNumQuota = [[UILabel alloc] init]; |
|||
cardNumQuota.text = @"--"; |
|||
cardNumQuota.textColor = [UIColor whiteColor]; |
|||
cardNumQuota.font = [UIFont systemFontOfSize:12]; |
|||
cardNumQuota.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[_cardContainer addSubview:cardNumQuota]; |
|||
|
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[cardLabelHeight.bottomAnchor constraintEqualToAnchor:_cardContainer.bottomAnchor constant:-75], |
|||
|
|||
[cardLabelStart.bottomAnchor constraintEqualToAnchor:cardLabelHeight.bottomAnchor], |
|||
|
|||
[cardLabelVolume.bottomAnchor constraintEqualToAnchor:cardLabelHeight.bottomAnchor], |
|||
|
|||
[cardLabelLow.topAnchor constraintEqualToAnchor:_cardContainer.bottomAnchor constant:-50], |
|||
[cardLabelLow.leadingAnchor constraintEqualToAnchor:cardLabelHeight.leadingAnchor], |
|||
|
|||
[cardLabelChange.topAnchor constraintEqualToAnchor:_cardContainer.bottomAnchor constant:-50], |
|||
[cardLabelChange.leadingAnchor constraintEqualToAnchor:cardLabelStart.leadingAnchor], |
|||
|
|||
[cardLabelQuota.topAnchor constraintEqualToAnchor:_cardContainer.bottomAnchor constant:-50], |
|||
[cardLabelQuota.leadingAnchor constraintEqualToAnchor:cardLabelVolume.leadingAnchor], |
|||
|
|||
[cardNumHeight.bottomAnchor constraintEqualToAnchor:_cardContainer.topAnchor constant:45], |
|||
[cardNumHeight.leadingAnchor constraintEqualToAnchor:cardLabelHeight.leadingAnchor], |
|||
|
|||
[cardNumStart.bottomAnchor constraintEqualToAnchor:cardNumHeight.bottomAnchor], |
|||
[cardNumStart.leadingAnchor constraintEqualToAnchor:cardLabelStart.leadingAnchor], |
|||
|
|||
[cardNumVolume.bottomAnchor constraintEqualToAnchor:cardNumHeight.bottomAnchor], |
|||
[cardNumVolume.leadingAnchor constraintEqualToAnchor:cardLabelVolume.leadingAnchor], |
|||
|
|||
[cardNumLow.bottomAnchor constraintEqualToAnchor:_cardContainer.bottomAnchor constant:-10], |
|||
[cardNumLow.leadingAnchor constraintEqualToAnchor:cardLabelLow.leadingAnchor], |
|||
|
|||
[cardNumChange.bottomAnchor constraintEqualToAnchor:cardNumLow.bottomAnchor], |
|||
[cardNumChange.leadingAnchor constraintEqualToAnchor:cardLabelChange.leadingAnchor], |
|||
|
|||
[cardNumQuota.bottomAnchor constraintEqualToAnchor:cardNumLow.bottomAnchor], |
|||
[cardNumQuota.leadingAnchor constraintEqualToAnchor:cardLabelVolume.leadingAnchor] |
|||
]]; |
|||
|
|||
[NSLayoutConstraint constraintWithItem:cardLabelHeight |
|||
attribute:NSLayoutAttributeLeading |
|||
relatedBy:NSLayoutRelationEqual |
|||
toItem:_cardContainer |
|||
attribute:NSLayoutAttributeTrailing |
|||
multiplier:0.25 |
|||
constant:0].active = YES; |
|||
[NSLayoutConstraint constraintWithItem:cardLabelStart |
|||
attribute:NSLayoutAttributeLeading |
|||
relatedBy:NSLayoutRelationEqual |
|||
toItem:_cardContainer |
|||
attribute:NSLayoutAttributeTrailing |
|||
multiplier:0.5 |
|||
constant:0].active = YES; |
|||
[NSLayoutConstraint constraintWithItem:cardLabelVolume |
|||
attribute:NSLayoutAttributeLeading |
|||
relatedBy:NSLayoutRelationEqual |
|||
toItem:_cardContainer |
|||
attribute:NSLayoutAttributeTrailing |
|||
multiplier:0.75 |
|||
constant:0].active = YES; |
|||
|
|||
// K线选择项容器 |
|||
_kSelectContainer = [[UIView alloc] init]; |
|||
_kSelectContainer.backgroundColor = [UIColor colorWithRed:26.0/255.0 |
|||
green:26.0/255.0 |
|||
blue:2.0/255.0 |
|||
alpha:1.0]; |
|||
_kSelectContainer.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:_kSelectContainer]; |
|||
[self addKSelectOptions]; |
|||
|
|||
// K线图表容器 |
|||
self.kLineContainer = [[UIView alloc] init]; |
|||
self.kLineContainer.backgroundColor = [UIColor colorWithRed:26.0/255.0 green:26.0/255.0 blue:26.0/255.0 alpha:1.0]; |
|||
self.kLineContainer.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:self.kLineContainer]; |
|||
|
|||
// K线图表滚动视图 |
|||
self.kLineScrollView = [[UIScrollView alloc] init]; |
|||
self.kLineScrollView.backgroundColor = [UIColor clearColor]; |
|||
self.kLineScrollView.showsHorizontalScrollIndicator = NO; |
|||
self.kLineScrollView.userInteractionEnabled = YES; |
|||
self.kLineScrollView.translatesAutoresizingMaskIntoConstraints = NO; |
|||
|
|||
[self.kLineContainer addSubview:self.kLineScrollView]; |
|||
|
|||
CGFloat priceLabelAreaWidth = 50.0; |
|||
|
|||
// 滚动视图的约束 |
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[self.kLineScrollView.topAnchor constraintEqualToAnchor:self.kLineContainer.topAnchor], |
|||
[self.kLineScrollView.bottomAnchor constraintEqualToAnchor:self.kLineContainer.bottomAnchor], |
|||
[self.kLineScrollView.leadingAnchor constraintEqualToAnchor:self.kLineContainer.leadingAnchor constant:priceLabelAreaWidth], |
|||
[self.kLineScrollView.trailingAnchor constraintEqualToAnchor:self.kLineContainer.trailingAnchor], |
|||
[self.kLineScrollView.heightAnchor constraintEqualToAnchor:self.kLineContainer.heightAnchor] |
|||
]]; |
|||
|
|||
// 边框 |
|||
UIView *borderView = [[UIView alloc] init]; |
|||
borderView.backgroundColor = [UIColor clearColor]; |
|||
borderView.layer.borderWidth = 1; |
|||
borderView.layer.borderColor = [[UIColor colorWithRed:0.4 green:0.4 blue:0.4 alpha:1.0] CGColor]; |
|||
borderView.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.kLineContainer addSubview:borderView]; |
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[borderView.leadingAnchor constraintEqualToAnchor:self.kLineContainer.leadingAnchor], |
|||
[borderView.trailingAnchor constraintEqualToAnchor:self.kLineContainer.trailingAnchor], |
|||
[borderView.topAnchor constraintEqualToAnchor:self.kLineContainer.topAnchor], |
|||
[borderView.bottomAnchor constraintEqualToAnchor:self.kLineContainer.bottomAnchor] |
|||
]]; |
|||
|
|||
// 动态计算模型数据的价格区间 |
|||
CGFloat maxPrice = 0; |
|||
CGFloat minPrice = CGFLOAT_MAX; |
|||
for (id item in self.kLineData) { |
|||
if ([item isKindOfClass:[StockKLineModel class]]) { |
|||
StockKLineModel *model = (StockKLineModel *)item; |
|||
maxPrice = MAX(maxPrice, model.high); |
|||
minPrice = MIN(minPrice, model.low); |
|||
} else if ([item isKindOfClass:[NSDictionary class]]) { |
|||
NSDictionary *dict = (NSDictionary *)item; |
|||
maxPrice = MAX(maxPrice, [dict[@"high"] floatValue]); |
|||
minPrice = MIN(minPrice, [dict[@"low"] floatValue]); |
|||
} |
|||
} |
|||
maxPrice = maxPrice + (maxPrice - minPrice) * 0.1; |
|||
minPrice = minPrice - (maxPrice - minPrice) * 0.1; |
|||
|
|||
// 价格刻度 |
|||
NSMutableArray *priceLabelArr = [NSMutableArray array]; |
|||
for (NSInteger i = 0; i < 5; i++) { |
|||
CGFloat price = maxPrice - (maxPrice - minPrice) / 4 * i; |
|||
UILabel *label = [[UILabel alloc] init]; |
|||
label.text = [NSString stringWithFormat:@"%.1f", price]; |
|||
label.textColor = [UIColor lightGrayColor]; |
|||
label.font = [UIFont systemFontOfSize:10]; |
|||
label.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.kLineContainer addSubview:label]; |
|||
|
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[label.leadingAnchor constraintEqualToAnchor:self.kLineContainer.leadingAnchor constant:5], |
|||
[label.centerYAnchor constraintEqualToAnchor:self.kLineContainer.centerYAnchor constant:-80 + 40 * i] |
|||
]]; |
|||
[priceLabelArr addObject:label]; |
|||
} |
|||
self.priceLabels = priceLabelArr; |
|||
|
|||
self.dateLabels = @[]; |
|||
} |
|||
|
|||
- (void)addKSelectOptions { |
|||
NSArray *titles = @[@"日k", @"周k", @"月k", @"更多", @"设置"]; |
|||
|
|||
UIStackView *stackView = [[UIStackView alloc] init]; |
|||
stackView.axis = UILayoutConstraintAxisHorizontal; |
|||
stackView.distribution = UIStackViewDistributionFillEqually; |
|||
stackView.alignment = UIStackViewAlignmentCenter; |
|||
stackView.spacing = 5.0; |
|||
stackView.translatesAutoresizingMaskIntoConstraints = NO; |
|||
|
|||
for (NSString *title in titles) { |
|||
UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem]; |
|||
[button setTitle:title forState:UIControlStateNormal]; |
|||
button.titleLabel.font = [UIFont systemFontOfSize:14]; |
|||
[button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; |
|||
|
|||
if ([title isEqualToString:@"日k"]) { |
|||
[button setTitleColor:[UIColor yellowColor] forState:UIControlStateNormal]; |
|||
button.layer.borderColor = [[UIColor yellowColor] CGColor]; |
|||
button.layer.borderWidth = 1.0; |
|||
} else { |
|||
[button setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal]; |
|||
button.layer.borderWidth = 0; |
|||
} |
|||
|
|||
button.layer.cornerRadius = 3.0; |
|||
button.clipsToBounds = YES; |
|||
|
|||
[stackView addArrangedSubview:button]; |
|||
} |
|||
|
|||
[_kSelectContainer addSubview:stackView]; |
|||
|
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[stackView.leadingAnchor constraintEqualToAnchor:_kSelectContainer.leadingAnchor constant:10], |
|||
[stackView.trailingAnchor constraintEqualToAnchor:_kSelectContainer.trailingAnchor constant:-10], |
|||
[stackView.topAnchor constraintEqualToAnchor:_kSelectContainer.topAnchor constant:5], |
|||
[stackView.bottomAnchor constraintEqualToAnchor:_kSelectContainer.bottomAnchor constant:-5] |
|||
]]; |
|||
} |
|||
|
|||
#pragma mark - Constraints |
|||
- (void)setupConstraints{ |
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[_cardContainer.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor], |
|||
[_cardContainer.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], |
|||
[_cardContainer.widthAnchor constraintEqualToAnchor:self.view.widthAnchor], |
|||
[_cardContainer.heightAnchor constraintEqualToConstant:100], |
|||
|
|||
[_kSelectContainer.topAnchor constraintEqualToAnchor:_cardContainer.bottomAnchor constant:5], |
|||
[_kSelectContainer.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], |
|||
[_kSelectContainer.widthAnchor constraintEqualToAnchor:self.view.widthAnchor], |
|||
[_kSelectContainer.heightAnchor constraintEqualToConstant:40], |
|||
|
|||
[self.kLineContainer.topAnchor constraintEqualToAnchor:self.kSelectContainer.bottomAnchor constant:5], |
|||
[self.kLineContainer.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], |
|||
[self.kLineContainer.widthAnchor constraintEqualToAnchor:self.view.widthAnchor], |
|||
[self.kLineContainer.heightAnchor constraintEqualToConstant:200] |
|||
]]; |
|||
} |
|||
|
|||
#pragma mark - KLine Drawing |
|||
- (void)drawKLineChart { |
|||
// 移除旧的 K 线 |
|||
for (UIView *subview in self.kLineScrollView.subviews) { |
|||
if (![subview isKindOfClass:[UILabel class]]) { |
|||
[subview removeFromSuperview]; |
|||
} |
|||
} |
|||
|
|||
CGFloat chartHeight = self.kLineContainer.bounds.size.height; |
|||
if (chartHeight == 0) { |
|||
chartHeight = 200; |
|||
} |
|||
|
|||
// K线宽度计算 |
|||
CGFloat kLineUnitWidth = 5.0; |
|||
CGFloat kLineRatio = 0.8; |
|||
CGFloat kLineWidth = kLineUnitWidth * kLineRatio; |
|||
CGFloat space = kLineUnitWidth * (1.0 - kLineRatio); |
|||
CGFloat totalChartWidth = kLineUnitWidth * self.kLineData.count; |
|||
|
|||
// 设置contentSize |
|||
self.kLineScrollView.contentSize = CGSizeMake(totalChartWidth, chartHeight); |
|||
|
|||
// 动态计算价格区间 |
|||
CGFloat maxPrice = 0; |
|||
CGFloat minPrice = CGFLOAT_MAX; |
|||
for (id item in self.kLineData) { |
|||
if ([item isKindOfClass:[StockKLineModel class]]) { |
|||
StockKLineModel *model = (StockKLineModel *)item; |
|||
maxPrice = MAX(maxPrice, model.high); |
|||
minPrice = MIN(minPrice, model.low); |
|||
} else if ([item isKindOfClass:[NSDictionary class]]) { |
|||
NSDictionary *dict = (NSDictionary *)item; |
|||
maxPrice = MAX(maxPrice, [dict[@"high"] floatValue]); |
|||
minPrice = MIN(minPrice, [dict[@"low"] floatValue]); |
|||
} |
|||
} |
|||
maxPrice = maxPrice + (maxPrice - minPrice) * 0.1; |
|||
minPrice = minPrice - (maxPrice - minPrice) * 0.1; |
|||
CGFloat priceRange = maxPrice - minPrice; |
|||
|
|||
// 绘制K线 |
|||
for (NSInteger i = 0; i < self.kLineData.count; i++) { |
|||
CGFloat open = 0, high = 0, low = 0, close = 0; |
|||
|
|||
if ([self.kLineData[i] isKindOfClass:[StockKLineModel class]]) { |
|||
StockKLineModel *model = (StockKLineModel *)self.kLineData[i]; |
|||
open = model.open; |
|||
high = model.high; |
|||
low = model.low; |
|||
close = model.close; |
|||
} else if ([self.kLineData[i] isKindOfClass:[NSDictionary class]]) { |
|||
NSDictionary *dict = (NSDictionary *)self.kLineData[i]; |
|||
open = [dict[@"open"] floatValue]; |
|||
high = [dict[@"high"] floatValue]; |
|||
low = [dict[@"low"] floatValue]; |
|||
close = [dict[@"close"] floatValue]; |
|||
} |
|||
|
|||
// 坐标转换 |
|||
CGFloat yOpen = chartHeight * (maxPrice - open) / priceRange; |
|||
CGFloat yHigh = chartHeight * (maxPrice - high) / priceRange; |
|||
CGFloat yLow = chartHeight * (maxPrice - low) / priceRange; |
|||
CGFloat yClose = chartHeight * (maxPrice - close) / priceRange; |
|||
|
|||
// 计算X坐标 |
|||
CGFloat xPosition = space/2 + kLineUnitWidth * i; |
|||
|
|||
// 绘制K线实体 |
|||
UIView *bodyView = [[UIView alloc] init]; |
|||
bodyView.backgroundColor = (close >= open) ? [UIColor greenColor] : [UIColor redColor]; |
|||
bodyView.frame = CGRectMake( |
|||
xPosition, |
|||
MIN(yOpen, yClose), |
|||
kLineWidth, |
|||
MAX(1.0, fabs(yClose - yOpen)) |
|||
); |
|||
[self.kLineScrollView addSubview:bodyView]; |
|||
|
|||
// 绘制影线 |
|||
UIView *shadowView = [[UIView alloc] init]; |
|||
shadowView.backgroundColor = bodyView.backgroundColor; |
|||
shadowView.frame = CGRectMake( |
|||
bodyView.center.x - 0.5, |
|||
yHigh, |
|||
1, |
|||
yLow - yHigh |
|||
); |
|||
[self.kLineScrollView addSubview:shadowView]; |
|||
} |
|||
|
|||
// 日期刻度 |
|||
for (UILabel *label in self.dateLabels) { |
|||
[label removeFromSuperview]; |
|||
} |
|||
|
|||
NSMutableArray *dateLabelArr = [NSMutableArray array]; |
|||
NSInteger dateInterval = 10; |
|||
|
|||
for (NSInteger i = 0; i < self.kLineData.count; i += dateInterval) { |
|||
NSString *dateStr = @""; |
|||
if ([self.kLineData[i] isKindOfClass:[StockKLineModel class]]) { |
|||
StockKLineModel *model = (StockKLineModel *)self.kLineData[i]; |
|||
dateStr = model.date; |
|||
} else if ([self.kLineData[i] isKindOfClass:[NSDictionary class]]) { |
|||
NSDictionary *dict = (NSDictionary *)self.kLineData[i]; |
|||
dateStr = dict[@"date"]; |
|||
} |
|||
UILabel *label = [[UILabel alloc] init]; |
|||
label.text = dateStr; |
|||
label.textColor = [UIColor lightGrayColor]; |
|||
label.font = [UIFont systemFontOfSize:10]; |
|||
label.translatesAutoresizingMaskIntoConstraints = YES; |
|||
|
|||
CGFloat xCenter = kLineUnitWidth * (i + 0.5); |
|||
[label sizeToFit]; |
|||
|
|||
label.frame = CGRectMake( |
|||
xCenter - label.bounds.size.width / 2, |
|||
chartHeight - 15, |
|||
label.bounds.size.width, |
|||
label.bounds.size.height |
|||
); |
|||
|
|||
[self.kLineScrollView addSubview:label]; |
|||
[dateLabelArr addObject:label]; |
|||
} |
|||
self.dateLabels = dateLabelArr; |
|||
|
|||
NSLog(@"ScrollView Bounds Width: %f", self.kLineScrollView.bounds.size.width); |
|||
NSLog(@"Content Size Width: %f", self.kLineScrollView.contentSize.width); |
|||
|
|||
if (self.kLineScrollView.contentSize.width <= self.kLineScrollView.bounds.size.width) { |
|||
NSLog(@"⚠️ 警告:ContentSize 不够大,无法滑动。"); |
|||
} |
|||
} |
|||
|
|||
#pragma mark - Mock Data |
|||
- (void) setupData{ |
|||
self.kLineData = @[ |
|||
@{@"date":@"2025/11/18", @"open":@1620.0, @"high":@1643.0, @"low":@1605.0, @"close":@1630.0, @"volume":@2.5}, |
|||
@{@"date":@"2025/11/19", @"open":@1630.0, @"high":@1635.0, @"low":@1615.0, @"close":@1620.0, @"volume":@2.2}, |
|||
@{@"date":@"2025/11/20", @"open":@1620.0, @"high":@1628.0, @"low":@1608.0, @"close":@1615.0, @"volume":@1.8}, |
|||
@{@"date":@"2025/11/21", @"open":@1615.0, @"high":@1625.0, @"low":@1610.0, @"close":@1622.0, @"volume":@2.0}, |
|||
@{@"date":@"2025/11/22", @"open":@1622.0, @"high":@1630.0, @"low":@1618.0, @"close":@1625.0, @"volume":@2.3}, |
|||
@{@"date":@"2025/11/25", @"open":@1625.0, @"high":@1632.0, @"low":@1620.0, @"close":@1628.0, @"volume":@1.9}, |
|||
@{@"date":@"2025/11/26", @"open":@1628.0, @"high":@1635.0, @"low":@1622.0, @"close":@1630.0, @"volume":@2.1}, |
|||
@{@"date":@"2025/11/27", @"open":@1630.0, @"high":@1638.0, @"low":@1625.0, @"close":@1628.0, @"volume":@2.4}, |
|||
@{@"date":@"2025/11/28", @"open":@1628.0, @"high":@1632.0, @"low":@1609.0, @"close":@1610.0, @"volume":@2.6}, |
|||
@{@"date":@"2025/11/29", @"open":@1610.0, @"high":@1620.0, @"low":@1608.0, @"close":@1615.0, @"volume":@1.7} |
|||
]; |
|||
} |
|||
|
|||
- (void)generateMockData { |
|||
NSMutableArray *arr = [NSMutableArray array]; |
|||
CGFloat lastClose = 100.0; |
|||
NSLog(@"生成模拟数据中。。。"); |
|||
|
|||
// 生成200条数据(减少数量,避免contentSize过大) |
|||
for (int i = 0; i < 200; i++) { |
|||
StockKLineModel *model = [[StockKLineModel alloc] init]; |
|||
|
|||
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:-(200 - i) * 24 * 3600]; |
|||
NSDateFormatter *fmt = [[NSDateFormatter alloc] init]; |
|||
[fmt setDateFormat:@"MM-dd"]; |
|||
model.date = [fmt stringFromDate:date]; |
|||
|
|||
// 价格生成逻辑 |
|||
CGFloat volatility = lastClose * 0.02; |
|||
CGFloat randomChange = ((arc4random() % 100) / 100.0 - 0.5) * 2 * volatility; |
|||
|
|||
model.open = lastClose + ((arc4random() % 100) / 100.0 - 0.5) * volatility * 0.5; |
|||
model.close = model.open + randomChange; |
|||
|
|||
CGFloat maxOC = MAX(model.open, model.close); |
|||
CGFloat minOC = MIN(model.open, model.close); |
|||
|
|||
model.high = maxOC + (arc4random() % 100) / 100.0 * 1.0; |
|||
model.low = minOC - (arc4random() % 100) / 100.0 * 1.0; |
|||
|
|||
// 成交量生成逻辑 |
|||
CGFloat baseVolume = 1000000.0; |
|||
CGFloat randomVolFactor = (arc4random() % 200) / 100.0 + 0.5; |
|||
|
|||
if (fabs(model.close - model.open) / model.open > 0.03) { |
|||
randomVolFactor *= 1.5; |
|||
} |
|||
|
|||
model.volume = baseVolume * randomVolFactor; |
|||
|
|||
if (model.low < 0) model.low = 0.01; |
|||
|
|||
[arr addObject:model]; |
|||
|
|||
lastClose = model.close; |
|||
} |
|||
|
|||
NSLog(@"生成模拟数据完毕,共%ld条", arr.count); |
|||
|
|||
self.kLineData = arr; |
|||
} |
|||
|
|||
@end |
|||
@ -0,0 +1,19 @@ |
|||
// |
|||
// CommonTabBar.h |
|||
// HC |
|||
// |
|||
// Created by huilinLi on 2025/11/25. |
|||
// |
|||
|
|||
#import <UIKit/UIKit.h> |
|||
|
|||
@protocol CommonTabBarDelegate <NSObject> |
|||
- (void)tabBarDidSelectIndex:(NSInteger)index; |
|||
@end |
|||
|
|||
@interface CommonTabBar : UIView |
|||
@property (nonatomic, weak) id<CommonTabBarDelegate> delegate; |
|||
@property (nonatomic, assign) NSInteger selectedIndex; // 当前选中的索引 |
|||
|
|||
- (instancetype)initWithTabItems:(NSArray<NSDictionary *> *)tabItems; |
|||
@end |
|||
@ -0,0 +1,94 @@ |
|||
// |
|||
// CommonTabBar.m |
|||
// HC |
|||
// |
|||
// Created by huilinLi on 2025/11/25. |
|||
// |
|||
|
|||
#import "CommonTabBar.h" |
|||
|
|||
@interface CommonTabBar () |
|||
@property (nonatomic, strong) NSArray<UIButton *> *tabButtons; |
|||
@end |
|||
|
|||
@implementation CommonTabBar |
|||
|
|||
- (instancetype)initWithTabItems:(NSArray<NSDictionary *> *)tabItems { |
|||
self = [super init]; |
|||
if (self) { |
|||
self.backgroundColor = [UIColor blackColor]; |
|||
self.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self setupTabButtonsWithItems:tabItems]; |
|||
} |
|||
return self; |
|||
} |
|||
|
|||
- (void)setupTabButtonsWithItems:(NSArray<NSDictionary *> *)tabItems { |
|||
NSMutableArray<UIButton *> *buttons = [NSMutableArray array]; |
|||
|
|||
for (NSInteger i = 0; i < tabItems.count; i++) { |
|||
NSDictionary *item = tabItems[i]; |
|||
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem]; |
|||
|
|||
UIButtonConfiguration *config = [UIButtonConfiguration plainButtonConfiguration]; |
|||
config.image = [UIImage systemImageNamed:item[@"icon"] ?: @""]; |
|||
config.title = item[@"title"]; |
|||
config.imagePlacement = NSDirectionalRectEdgeTop; |
|||
config.imagePadding = 5; |
|||
btn.configuration = config; |
|||
|
|||
BOOL selected = [item[@"selected"] boolValue]; |
|||
btn.tintColor = selected ? [UIColor blueColor] : [UIColor whiteColor]; |
|||
btn.titleLabel.font = [UIFont systemFontOfSize:10]; |
|||
btn.tag = i; |
|||
|
|||
[btn addTarget:self action:@selector(tabButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; |
|||
|
|||
[self addSubview:btn]; |
|||
[buttons addObject:btn]; |
|||
} |
|||
|
|||
self.tabButtons = buttons; |
|||
[self setupTabButtonConstraints]; |
|||
} |
|||
|
|||
- (void)setupTabButtonConstraints { |
|||
for (NSInteger i = 0; i < self.tabButtons.count; i++) { |
|||
UIButton *btn = self.tabButtons[i]; |
|||
btn.translatesAutoresizingMaskIntoConstraints = NO; |
|||
|
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[btn.widthAnchor constraintEqualToAnchor:self.widthAnchor multiplier:1.0/self.tabButtons.count], |
|||
[btn.heightAnchor constraintEqualToAnchor:self.heightAnchor], |
|||
[btn.centerYAnchor constraintEqualToAnchor:self.centerYAnchor], |
|||
|
|||
(i == 0) ? [btn.leadingAnchor constraintEqualToAnchor:self.leadingAnchor] : |
|||
[btn.leadingAnchor constraintEqualToAnchor:self.tabButtons[i-1].trailingAnchor], |
|||
]]; |
|||
} |
|||
|
|||
// TabBar自身高度 |
|||
[self.heightAnchor constraintEqualToConstant:60].active = YES; |
|||
} |
|||
|
|||
- (void)tabButtonTapped:(UIButton *)sender { |
|||
self.selectedIndex = sender.tag; |
|||
|
|||
for (UIButton *btn in self.tabButtons) { |
|||
btn.tintColor = (btn.tag == sender.tag) ? [UIColor blueColor] : [UIColor whiteColor]; |
|||
} |
|||
|
|||
if ([self.delegate respondsToSelector:@selector(tabBarDidSelectIndex:)]) { |
|||
[self.delegate tabBarDidSelectIndex:sender.tag]; |
|||
} |
|||
} |
|||
|
|||
// 外部设置选中索引时更新样式 |
|||
- (void)setSelectedIndex:(NSInteger)selectedIndex { |
|||
_selectedIndex = selectedIndex; |
|||
for (UIButton *btn in self.tabButtons) { |
|||
btn.tintColor = (btn.tag == selectedIndex) ? [UIColor blueColor] : [UIColor whiteColor]; |
|||
} |
|||
} |
|||
|
|||
@end |
|||
@ -0,0 +1,18 @@ |
|||
// |
|||
// CountryModel.h |
|||
// HC |
|||
// |
|||
// Created by huilinLi on 2025/11/26. |
|||
// |
|||
|
|||
#import <Foundation/Foundation.h> |
|||
@interface CountryModel : NSObject |
|||
@property (nonatomic, copy) NSString *code; // 国家代码 |
|||
@property (nonatomic, copy) NSString *name; // 国家名称 |
|||
@property (nonatomic, copy) NSString *vcClassName; // 子控制器名称 |
|||
|
|||
+ (instancetype)modelWithCode:(NSString *)code |
|||
name:(NSString *)name |
|||
vcClassName:(NSString *)vcClassName; |
|||
@end |
|||
|
|||
@ -0,0 +1,20 @@ |
|||
// |
|||
// CountryModel.m |
|||
// HC |
|||
// |
|||
// Created by huilinLi on 2025/11/26. |
|||
// |
|||
|
|||
#import "CountryModel.h" |
|||
|
|||
@implementation CountryModel |
|||
+ (instancetype)modelWithCode:(NSString *)code |
|||
name:(NSString *)name |
|||
vcClassName:(NSString *)vcClassName { |
|||
CountryModel *model = [[self alloc] init]; |
|||
model.code = code; |
|||
model.name = name; |
|||
model.vcClassName = vcClassName; |
|||
return model; |
|||
} |
|||
@end |
|||
@ -0,0 +1,45 @@ |
|||
// |
|||
// HomeViewController.h |
|||
// HC |
|||
// |
|||
// Created by huilinLi on 2025/11/18. |
|||
// |
|||
|
|||
#import <UIKit/UIKit.h> |
|||
#import "CommonTabBar.h" |
|||
|
|||
NS_ASSUME_NONNULL_BEGIN |
|||
|
|||
@interface HomeViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, UIScrollViewDelegate,CommonTabBarDelegate> |
|||
|
|||
@property (nonatomic, strong) UILabel *successLabel; |
|||
@property (nonatomic, strong) UITextField *searchField; |
|||
@property (nonatomic, strong) UIImageView *logoImage; |
|||
@property (nonatomic, strong) UIImageView *flagIcon; |
|||
@property (nonatomic, strong) UIButton *messageBtn; |
|||
@property (nonatomic, strong) UIScrollView *functionScrollView; |
|||
@property (nonatomic, strong) NSMutableArray<UIButton *> *functionBtns; |
|||
@property (nonatomic, strong) UIScrollView *bannerScrollView; |
|||
@property (nonatomic, strong) UIPageControl *bannerPageControl; |
|||
@property (nonatomic, strong) UIView *tabContainer; |
|||
@property (nonatomic, strong) UIButton *courseBtn; // 课程按钮 |
|||
@property (nonatomic, strong) UIButton *infoBtn; // 资讯按钮 |
|||
@property (nonatomic, strong) UIButton *activityBtn; // 活动按钮 |
|||
@property (nonatomic, strong) UIView *courseUnderline; // 课程下划线 |
|||
@property (nonatomic, strong) UIView *infoUnderline; // 资讯下划线 |
|||
@property (nonatomic, strong) UIView *activityUnderline;// 活动下划线 |
|||
@property (nonatomic, strong) UITableView *courseTableView; |
|||
// @property (nonatomic, strong) UIView *commonTabBar; |
|||
@property (nonatomic, strong) CommonTabBar *commonTabBar; |
|||
@property (nonatomic, strong) UIButton *homeTabBtn; |
|||
@property (nonatomic, strong) UIButton *marketTabBtn; |
|||
@property (nonatomic, strong) UIButton *favoritesTabBtn; |
|||
@property (nonatomic, strong) UIButton *mineTabBtn; |
|||
@property (nonatomic, strong) UIImageView *redPacketIcon; |
|||
@property (nonatomic, strong) NSArray *functionIcons; |
|||
@property (nonatomic, strong) NSArray *courseData; |
|||
@property (nonatomic, strong) NSTimer *bannerTimer; // 轮播图的定时器 |
|||
@property (nonatomic, assign) NSInteger currentBannerIndex; // 当前轮播页码 |
|||
@end |
|||
|
|||
NS_ASSUME_NONNULL_END |
|||
@ -0,0 +1,634 @@ |
|||
// |
|||
// HomeViewController.m |
|||
// HC |
|||
// |
|||
// Created by huilinLi on 2025/11/18. |
|||
// |
|||
#import <UIKit/UIKit.h> |
|||
#import "HomeViewController.h" |
|||
#import "MyViewController.h" |
|||
#import "CommonTabBar.h" |
|||
#import "QuotationViewController.h" |
|||
|
|||
|
|||
@implementation HomeViewController |
|||
|
|||
- (void)viewDidLoad { |
|||
self.view.backgroundColor = [UIColor blackColor]; |
|||
|
|||
[self setupData]; |
|||
[self setupSubviews]; |
|||
[self setupConstraints]; |
|||
|
|||
[self selectButton:self.courseBtn];// 课程 |
|||
} |
|||
|
|||
-(void) setupSubviews{ |
|||
// 搜索框左边logo |
|||
_logoImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"logo"]]; |
|||
_logoImage.contentMode = UIViewContentModeScaleAspectFit;// 保持比例 |
|||
_logoImage.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:_logoImage]; |
|||
|
|||
// 搜索框 |
|||
_searchField = [[UITextField alloc] init]; |
|||
_searchField.placeholder = @"股票名称/代码"; |
|||
NSAttributedString *placeholder = [[NSAttributedString alloc] initWithString:@"股票名称/代码" attributes:@{ |
|||
NSForegroundColorAttributeName: [UIColor whiteColor] |
|||
}]; |
|||
_searchField.attributedPlaceholder = placeholder; |
|||
_searchField.textColor = [UIColor whiteColor]; |
|||
_searchField.backgroundColor = [UIColor colorWithRed:0.2 green:0.2 blue:0.2 alpha:1]; |
|||
_searchField.layer.cornerRadius = 15; |
|||
_searchField.leftView = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:@"magnifyingglass"]]; |
|||
_searchField.leftViewMode = UITextFieldViewModeAlways; |
|||
_searchField.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:_searchField]; |
|||
|
|||
// 市场配置 |
|||
_flagIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"singapore_flag"]]; |
|||
_flagIcon.contentMode = UIViewContentModeScaleAspectFit; |
|||
_flagIcon.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:_flagIcon]; |
|||
|
|||
// 消息 |
|||
_messageBtn = [UIButton buttonWithType:UIButtonTypeSystem]; |
|||
UIButtonConfiguration *config = [UIButtonConfiguration plainButtonConfiguration]; |
|||
config.image = [UIImage systemImageNamed:@"message"]; |
|||
config.baseForegroundColor = [UIColor whiteColor]; |
|||
// 富文本 |
|||
NSAttributedString *attributedTitle = [[NSAttributedString alloc] initWithString:@"15" attributes:@{ |
|||
NSFontAttributeName: [UIFont systemFontOfSize:10], |
|||
NSForegroundColorAttributeName: [UIColor whiteColor] |
|||
}]; |
|||
config.attributedTitle = attributedTitle; |
|||
config.imagePadding = -5; |
|||
config.contentInsets = NSDirectionalEdgeInsetsMake(0, 0, 0, 0);// 内容边距 |
|||
[_messageBtn setConfiguration:config]; |
|||
_messageBtn.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:_messageBtn]; |
|||
|
|||
// 功能按钮数组初始化 |
|||
_functionBtns = [NSMutableArray array]; |
|||
for (NSDictionary *dict in _functionIcons) { |
|||
UIButtonConfiguration *config = [UIButtonConfiguration plainButtonConfiguration]; |
|||
|
|||
UIImage *logoImage = [UIImage imageNamed:@"logo"]; |
|||
UIGraphicsBeginImageContextWithOptions(CGSizeMake(40, 40), NO, 0);// 开启图形上下文,((尺寸,尺寸),是否不透明,缩放因子) |
|||
[logoImage drawInRect:CGRectMake(0, 0, 40, 40)];// 调整,等比缩放 |
|||
UIImage *resizedLogo = UIGraphicsGetImageFromCurrentImageContext();// 获得调整后的 |
|||
UIGraphicsEndImageContext();// 关闭图形上下文 |
|||
|
|||
config.image = resizedLogo; |
|||
// 按钮文字,富文本 |
|||
NSAttributedString *titleAttr = [[NSAttributedString alloc] initWithString:dict[@"title"] attributes:@{ |
|||
NSFontAttributeName: [UIFont systemFontOfSize:13], |
|||
NSForegroundColorAttributeName: [UIColor whiteColor] |
|||
}]; |
|||
config.attributedTitle = titleAttr; |
|||
config.imagePlacement = NSDirectionalRectEdgeTop; |
|||
config.imagePadding = 5; |
|||
config.baseForegroundColor = [UIColor whiteColor]; |
|||
|
|||
UIButton *btn = [UIButton buttonWithConfiguration:config primaryAction:nil]; |
|||
btn.titleLabel.font = [UIFont systemFontOfSize:12]; |
|||
btn.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:btn]; |
|||
[_functionBtns addObject:btn]; |
|||
} |
|||
|
|||
// 轮播图视图 |
|||
_bannerScrollView = [[UIScrollView alloc] init]; |
|||
_bannerScrollView.showsHorizontalScrollIndicator = NO;// 隐藏水平滚动条 |
|||
_bannerScrollView.pagingEnabled = YES;// 分页 |
|||
_bannerScrollView.delegate = self; |
|||
_bannerScrollView.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:_bannerScrollView]; |
|||
|
|||
// 轮播图内容容器 |
|||
UIView *bannerContentView = [[UIView alloc] init]; |
|||
bannerContentView.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[_bannerScrollView addSubview:bannerContentView]; |
|||
|
|||
// 轮播图片 |
|||
NSArray *bannerImageNames = @[@"banner2", @"banner1", @"banner2", @"banner1"]; |
|||
NSMutableArray *bannerImages = [NSMutableArray array]; |
|||
|
|||
for (int i = 0; i < bannerImageNames.count; i++) { |
|||
UIImageView *bannerImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:bannerImageNames[i]]]; |
|||
bannerImage.contentMode = UIViewContentModeScaleAspectFill;// 填充 |
|||
bannerImage.clipsToBounds = YES;// 裁剪超出的 |
|||
bannerImage.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[bannerContentView addSubview:bannerImage]; |
|||
[bannerImages addObject:bannerImage]; |
|||
|
|||
[bannerImage.heightAnchor constraintEqualToAnchor:bannerContentView.heightAnchor].active = YES; |
|||
[bannerImage.widthAnchor constraintEqualToAnchor:self.view.widthAnchor].active = YES; |
|||
|
|||
if (i == 0) { |
|||
[bannerImage.leadingAnchor constraintEqualToAnchor:bannerContentView.leadingAnchor].active = YES; |
|||
} else { |
|||
UIImageView *prevImage = bannerImages[i-1]; |
|||
[bannerImage.leadingAnchor constraintEqualToAnchor:prevImage.trailingAnchor].active = YES; |
|||
} |
|||
} |
|||
|
|||
// 内容视图宽度(总图片数 * 屏幕宽度) |
|||
[bannerContentView.widthAnchor constraintEqualToConstant:self.view.bounds.size.width * bannerImages.count].active = YES; |
|||
|
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[bannerContentView.leadingAnchor constraintEqualToAnchor:_bannerScrollView.leadingAnchor], |
|||
[bannerContentView.trailingAnchor constraintEqualToAnchor:_bannerScrollView.trailingAnchor], |
|||
[bannerContentView.topAnchor constraintEqualToAnchor:_bannerScrollView.topAnchor], |
|||
[bannerContentView.bottomAnchor constraintEqualToAnchor:_bannerScrollView.bottomAnchor], |
|||
[bannerContentView.heightAnchor constraintEqualToAnchor:_bannerScrollView.heightAnchor], |
|||
]]; |
|||
|
|||
// 初始第一张 |
|||
[_bannerScrollView setContentOffset:CGPointMake(self.view.bounds.size.width, 0) animated:NO]; |
|||
|
|||
// 页码 |
|||
_bannerPageControl = [[UIPageControl alloc] init]; |
|||
_bannerPageControl.currentPageIndicatorTintColor = [UIColor blueColor]; |
|||
_bannerPageControl.pageIndicatorTintColor = [UIColor lightGrayColor];// 其他页码 |
|||
_bannerPageControl.numberOfPages = 2; |
|||
_bannerPageControl.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:_bannerPageControl]; |
|||
|
|||
// 初始化定时器(2秒一切) |
|||
_bannerTimer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(autoScrollBanner) userInfo:nil repeats:YES]; |
|||
[[NSRunLoop mainRunLoop] addTimer:_bannerTimer forMode:NSRunLoopCommonModes]; |
|||
_currentBannerIndex = 0; |
|||
|
|||
// 课程咨询活动的容器 |
|||
self.tabContainer = [[UIView alloc] init]; |
|||
self.tabContainer.backgroundColor = [UIColor blackColor]; |
|||
self.tabContainer.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:self.tabContainer]; |
|||
|
|||
// 课程 |
|||
_courseBtn = [UIButton buttonWithType:UIButtonTypeSystem]; |
|||
[_courseBtn setTitle:@"课程" forState:UIControlStateNormal]; |
|||
_courseBtn.titleLabel.font = [UIFont systemFontOfSize:14]; |
|||
[_courseBtn setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal]; |
|||
[_courseBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateSelected]; |
|||
_courseBtn.backgroundColor = [UIColor blackColor]; |
|||
//[_courseBtn setBackgroundColor:[UIColor blackColor]]; |
|||
[_courseBtn addTarget:self action:@selector(tabButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; |
|||
_courseBtn.tag = 100; |
|||
_courseBtn.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.tabContainer addSubview:_courseBtn]; |
|||
|
|||
// 资讯 |
|||
_infoBtn = [UIButton buttonWithType:UIButtonTypeSystem]; |
|||
[_infoBtn setTitle:@"资讯" forState:UIControlStateNormal]; |
|||
_infoBtn.titleLabel.font = [UIFont systemFontOfSize:14]; |
|||
//_infoBtn.backgroundColor = [UIColor blackColor]; |
|||
[_infoBtn setBackgroundColor:[UIColor blackColor]]; |
|||
[_infoBtn setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal]; |
|||
[_infoBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateSelected]; |
|||
[_infoBtn addTarget:self action:@selector(tabButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; |
|||
_infoBtn.tag = 101; |
|||
_infoBtn.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.tabContainer addSubview:_infoBtn]; |
|||
|
|||
// 活动 |
|||
_activityBtn = [UIButton buttonWithType:UIButtonTypeSystem]; |
|||
[_activityBtn setTitle:@"活动" forState:UIControlStateNormal]; |
|||
_activityBtn.titleLabel.font = [UIFont systemFontOfSize:14]; |
|||
//_activityBtn.backgroundColor = [UIColor blackColor]; |
|||
[_activityBtn setBackgroundColor:[UIColor blackColor]]; |
|||
[_activityBtn setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal]; |
|||
[_activityBtn setTitleColor:[UIColor whiteColor] forState:UIControlStateSelected]; |
|||
[_activityBtn addTarget:self action:@selector(tabButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; |
|||
_activityBtn.tag = 102; |
|||
_activityBtn.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.tabContainer addSubview:_activityBtn]; |
|||
|
|||
// 课程下划线 |
|||
_courseUnderline = [[UIView alloc] init]; |
|||
_courseUnderline.backgroundColor = [UIColor blueColor]; |
|||
_courseUnderline.hidden = YES; |
|||
_courseUnderline.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.tabContainer addSubview:_courseUnderline]; |
|||
|
|||
// 资讯下划线 |
|||
_infoUnderline = [[UIView alloc] init]; |
|||
_infoUnderline.backgroundColor = [UIColor blueColor]; |
|||
_infoUnderline.hidden = YES; |
|||
_infoUnderline.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.tabContainer addSubview:_infoUnderline]; |
|||
|
|||
// 活动下划线 |
|||
_activityUnderline = [[UIView alloc] init]; |
|||
_activityUnderline.backgroundColor = [UIColor blueColor]; |
|||
_activityUnderline.hidden = YES; |
|||
_activityUnderline.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.tabContainer addSubview:_activityUnderline]; |
|||
|
|||
// 课程列表TableView |
|||
_courseTableView = [[UITableView alloc] init]; |
|||
_courseTableView.backgroundColor = [UIColor blackColor]; |
|||
_courseTableView.separatorStyle = UITableViewCellSeparatorStyleNone;// 隐藏分割线 |
|||
[_courseTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"CourseCell"]; |
|||
_courseTableView.delegate = self; |
|||
_courseTableView.dataSource = self;// 数据源 |
|||
_courseTableView.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:_courseTableView]; |
|||
|
|||
// 红包 |
|||
_redPacketIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"logo"]]; |
|||
_redPacketIcon.contentMode = UIViewContentModeScaleAspectFit; |
|||
_redPacketIcon.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:_redPacketIcon]; |
|||
|
|||
NSArray *tabItems = @[ |
|||
@{@"title":@"首页", @"icon":@"house.fill", @"selected":@YES}, |
|||
@{@"title":@"行情", @"icon":@"chart.line.uptrend.xyaxis", @"selected":@NO}, |
|||
@{@"title":@"自选", @"icon":@"plus", @"selected":@NO}, |
|||
@{@"title":@"我的", @"icon":@"person", @"selected":@NO} |
|||
]; |
|||
self.commonTabBar = [[CommonTabBar alloc] initWithTabItems:tabItems]; |
|||
self.commonTabBar.delegate = self; |
|||
[self.view addSubview:self.commonTabBar]; |
|||
|
|||
// 登录提示 |
|||
_successLabel = [[UILabel alloc] init]; |
|||
_successLabel.text = @"登录成功"; |
|||
_successLabel.font = [UIFont systemFontOfSize:20]; |
|||
_successLabel.textColor = [UIColor whiteColor]; |
|||
_successLabel.numberOfLines = 0; |
|||
_successLabel.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:_successLabel]; |
|||
|
|||
|
|||
// 标签容器和按钮约束 |
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
// 标签容器,轮播图下15,左15,右15,高30 |
|||
[self.tabContainer.topAnchor constraintEqualToAnchor: _bannerScrollView.bottomAnchor constant:15], |
|||
[self.tabContainer.leadingAnchor constraintEqualToAnchor: self.view.leadingAnchor constant:15], |
|||
[self.tabContainer.trailingAnchor constraintEqualToAnchor: self.view.trailingAnchor constant:-15], |
|||
[self.tabContainer.heightAnchor constraintEqualToConstant:30], |
|||
|
|||
// 按钮均分宽度 |
|||
// 课程左齐容器,垂直居中,宽度1/3 |
|||
[_courseBtn.leadingAnchor constraintEqualToAnchor: self.tabContainer.leadingAnchor], |
|||
[_courseBtn.centerYAnchor constraintEqualToAnchor: self.tabContainer.centerYAnchor], |
|||
[_courseBtn.widthAnchor constraintEqualToAnchor: self.tabContainer.widthAnchor multiplier:1.0/3.0], |
|||
|
|||
// 咨询左对齐课程右侧 |
|||
[_infoBtn.leadingAnchor constraintEqualToAnchor: _courseBtn.trailingAnchor], |
|||
[_infoBtn.centerYAnchor constraintEqualToAnchor: self.tabContainer.centerYAnchor], |
|||
[_infoBtn.widthAnchor constraintEqualToAnchor: self.tabContainer.widthAnchor multiplier:1.0/3.0], |
|||
|
|||
// 活动左对齐咨询右侧 |
|||
[_activityBtn.leadingAnchor constraintEqualToAnchor: _infoBtn.trailingAnchor], |
|||
[_activityBtn.trailingAnchor constraintEqualToAnchor: self.tabContainer.trailingAnchor], |
|||
[_activityBtn.centerYAnchor constraintEqualToAnchor: self.tabContainer.centerYAnchor], |
|||
|
|||
// 下划线约束 |
|||
// 底部对齐容器,在button下方正中,宽30高2 |
|||
[_courseUnderline.bottomAnchor constraintEqualToAnchor: self.tabContainer.bottomAnchor], |
|||
[_courseUnderline.centerXAnchor constraintEqualToAnchor: _courseBtn.centerXAnchor], |
|||
[_courseUnderline.widthAnchor constraintEqualToConstant:30], |
|||
[_courseUnderline.heightAnchor constraintEqualToConstant:2], |
|||
|
|||
[_infoUnderline.bottomAnchor constraintEqualToAnchor: self.tabContainer.bottomAnchor], |
|||
[_infoUnderline.centerXAnchor constraintEqualToAnchor: _infoBtn.centerXAnchor], |
|||
[_infoUnderline.widthAnchor constraintEqualToConstant:30], |
|||
[_infoUnderline.heightAnchor constraintEqualToConstant:2], |
|||
|
|||
[_activityUnderline.bottomAnchor constraintEqualToAnchor: self.tabContainer.bottomAnchor], |
|||
[_activityUnderline.centerXAnchor constraintEqualToAnchor: _activityBtn.centerXAnchor], |
|||
[_activityUnderline.widthAnchor constraintEqualToConstant:30], |
|||
[_activityUnderline.heightAnchor constraintEqualToConstant:2], |
|||
]]; |
|||
} |
|||
|
|||
-(void) setupConstraints{ |
|||
// 登录成功提示 |
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[_successLabel.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor],// 水平居中 |
|||
[_successLabel.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor],// 垂直居中 |
|||
[_successLabel.widthAnchor constraintEqualToConstant:80], |
|||
[_successLabel.heightAnchor constraintEqualToConstant:30], |
|||
]]; |
|||
|
|||
// Logo图标 搜索框高度下垂直居中,左边距15,宽40高40 |
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[_logoImage.centerYAnchor constraintEqualToAnchor: _searchField.centerYAnchor], |
|||
[_logoImage.leadingAnchor constraintEqualToAnchor: self.view.leadingAnchor constant:15], |
|||
[_logoImage.widthAnchor constraintEqualToConstant:40], |
|||
[_logoImage.heightAnchor constraintEqualToConstant:40], |
|||
]]; |
|||
|
|||
// 搜索栏 父视图下50,logo左10,国旗左10,高30 |
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[_searchField.topAnchor constraintEqualToAnchor: self.view.topAnchor constant:50], |
|||
[_searchField.leadingAnchor constraintEqualToAnchor: _logoImage.trailingAnchor constant:10], |
|||
[_searchField.trailingAnchor constraintEqualToAnchor: _flagIcon.leadingAnchor constant:-10], |
|||
[_searchField.heightAnchor constraintEqualToConstant:30], |
|||
]]; |
|||
|
|||
// 国旗图标 |
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[_flagIcon.centerYAnchor constraintEqualToAnchor: _searchField.centerYAnchor], |
|||
[_flagIcon.trailingAnchor constraintEqualToAnchor: _messageBtn.leadingAnchor constant:-10], |
|||
[_flagIcon.widthAnchor constraintEqualToConstant:40], |
|||
[_flagIcon.heightAnchor constraintEqualToConstant:40], |
|||
]]; |
|||
|
|||
// 消息按钮 |
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[_messageBtn.centerYAnchor constraintEqualToAnchor: _searchField.centerYAnchor], |
|||
[_messageBtn.trailingAnchor constraintEqualToAnchor: self.view.trailingAnchor constant:-15], |
|||
[_messageBtn.widthAnchor constraintEqualToConstant:40], |
|||
[_messageBtn.heightAnchor constraintEqualToConstant:40], |
|||
]]; |
|||
|
|||
// 功能按钮(两行四列,均匀占满整行) |
|||
for (int i = 0; i < _functionBtns.count; i++) { |
|||
UIButton *btn = _functionBtns[i]; |
|||
NSLayoutConstraint *topConstraint; |
|||
NSLayoutConstraint *widthConstraint = [btn.widthAnchor constraintEqualToAnchor: self.view.widthAnchor multiplier:0.25 constant:-15]; |
|||
NSLayoutConstraint *heightConstraint = [btn.heightAnchor constraintEqualToConstant:70]; |
|||
|
|||
if (i < 4) { |
|||
topConstraint = [btn.topAnchor constraintEqualToAnchor: _searchField.bottomAnchor constant:20]; |
|||
NSLayoutConstraint *leadingConstraint; |
|||
if (i == 0) { |
|||
leadingConstraint = [btn.leadingAnchor constraintEqualToAnchor: self.view.leadingAnchor constant:15]; |
|||
} else { |
|||
leadingConstraint = [btn.leadingAnchor constraintEqualToAnchor: _functionBtns[i-1].trailingAnchor constant:0]; |
|||
} |
|||
[NSLayoutConstraint activateConstraints:@[topConstraint, leadingConstraint, widthConstraint, heightConstraint]]; |
|||
} else { |
|||
topConstraint = [btn.topAnchor constraintEqualToAnchor: _functionBtns[i-4].bottomAnchor constant:10]; |
|||
NSLayoutConstraint *leadingConstraint; |
|||
if (i == 4) { |
|||
leadingConstraint = [btn.leadingAnchor constraintEqualToAnchor: self.view.leadingAnchor constant:15]; |
|||
} else { |
|||
leadingConstraint = [btn.leadingAnchor constraintEqualToAnchor: _functionBtns[i-1].trailingAnchor constant:0]; |
|||
} |
|||
[NSLayoutConstraint activateConstraints:@[topConstraint, leadingConstraint, widthConstraint, heightConstraint]]; |
|||
} |
|||
} |
|||
|
|||
// 轮播图ScrollView 顶部距离最后一个功能按钮20,左右对齐父视图,高150 |
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[_bannerScrollView.topAnchor constraintEqualToAnchor: _functionBtns.lastObject.bottomAnchor constant:20], |
|||
[_bannerScrollView.leadingAnchor constraintEqualToAnchor: self.view.leadingAnchor], |
|||
[_bannerScrollView.trailingAnchor constraintEqualToAnchor: self.view.trailingAnchor], |
|||
[_bannerScrollView.heightAnchor constraintEqualToConstant:150], |
|||
]]; |
|||
|
|||
// 轮播图PageControl,底部距离轮播图5 |
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[_bannerPageControl.bottomAnchor constraintEqualToAnchor: _bannerScrollView.bottomAnchor constant:-5], |
|||
[_bannerPageControl.centerXAnchor constraintEqualToAnchor: self.view.centerXAnchor], |
|||
]]; |
|||
|
|||
// 课程列表 顶部距离标签容器20,左右对齐父视图,底部tabBar |
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[_courseTableView.topAnchor constraintEqualToAnchor: self.tabContainer.bottomAnchor constant:20], |
|||
[_courseTableView.leadingAnchor constraintEqualToAnchor: self.view.leadingAnchor], |
|||
[_courseTableView.trailingAnchor constraintEqualToAnchor: self.view.trailingAnchor], |
|||
[_courseTableView.bottomAnchor constraintEqualToAnchor: _commonTabBar.topAnchor] |
|||
]]; |
|||
|
|||
// 红包图标 |
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[_redPacketIcon.bottomAnchor constraintEqualToAnchor: _courseTableView.bottomAnchor constant:-200], |
|||
[_redPacketIcon.trailingAnchor constraintEqualToAnchor: self.view.trailingAnchor constant:-20], |
|||
[_redPacketIcon.widthAnchor constraintEqualToConstant:60], |
|||
[_redPacketIcon.heightAnchor constraintEqualToConstant:60], |
|||
]]; |
|||
|
|||
// 底部页面按钮 底部对齐安全区域,左右对齐父视图 |
|||
[_commonTabBar.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor].active = YES; |
|||
[_commonTabBar.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; |
|||
[_commonTabBar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; |
|||
} |
|||
|
|||
- (void)setupData { |
|||
_functionIcons = @[// 先都用logo |
|||
@{@"title":@"全球指数"}, |
|||
@{@"title":@"浏览历史"}, |
|||
@{@"title":@"机构"}, |
|||
@{@"title":@"弘历学堂"}, |
|||
@{@"title":@"自选"}, |
|||
@{@"title":@"商店"}, |
|||
@{@"title":@"猎庄选股"}, |
|||
@{@"title":@"智能机器人"} |
|||
]; |
|||
|
|||
_courseData = @[ |
|||
@{@"cover":@"course1", @"title":@"John Lu & Robert Xu “发财线”课程回顾!", @"lecturer":@"Homily Lecturer"}, |
|||
@{@"cover":@"event2", @"title":@"孩子炒股老亏钱,多半是废了", @"lecturer":@"kaslana"}, |
|||
@{@"cover":@"course3", @"title":@"论持久战", @"lecturer":@"教员先生"} |
|||
]; |
|||
} |
|||
|
|||
#pragma mark - 标签方法 |
|||
- (void)tabButtonTapped:(UIButton *)sender { |
|||
[self selectButton:sender]; |
|||
|
|||
// 根据标签切换 |
|||
switch (sender.tag) { |
|||
case 100: |
|||
_courseData = @[ |
|||
@{@"cover":@"course1", @"title":@"John Lu & Robert Xu “发财线”课程回顾!", @"lecturer":@"Homily Lecturer"}, |
|||
@{@"cover":@"event2", @"title":@"孩子炒股老亏钱,多半是废了", @"lecturer":@"kaslana"}, |
|||
@{@"cover":@"course3", @"title":@"论持久战", @"lecturer":@"教员先生"} |
|||
]; |
|||
break; |
|||
|
|||
case 101: |
|||
_courseData = @[ |
|||
@{@"cover":@"news1", @"title":@"objective-c从入门到入土", @"lecturer":@"财经资讯"}, |
|||
@{@"cover":@"news2", @"title":@"线程池核心参数详解", @"lecturer":@"财经资讯"}, |
|||
@{@"cover":@"news3", @"title":@"redis集群-主从、哨兵、分片", @"lecturer":@"财经资讯"} |
|||
]; |
|||
break; |
|||
|
|||
case 102: |
|||
_courseData = @[ |
|||
@{@"cover":@"event1", @"title":@"SpringCloud入门到放弃", @"lecturer":@"活动预告"}, |
|||
@{@"cover":@"event2", @"title":@"孩子炒股老亏钱,多半是废了", @"lecturer":@"活动预告"}, |
|||
@{@"cover":@"event3", @"title":@"mySQL:从删库到跑路", @"lecturer":@"活动预告"} |
|||
]; |
|||
break; |
|||
} |
|||
|
|||
[_courseTableView reloadData]; |
|||
} |
|||
|
|||
- (void) pushMine { |
|||
MyViewController *myViewController = [[MyViewController alloc] init]; |
|||
[self.navigationController pushViewController:myViewController animated:YES]; |
|||
} |
|||
|
|||
- (void)selectButton:(UIButton *)selectedButton { |
|||
_courseBtn.selected = NO; |
|||
_infoBtn.selected = NO; |
|||
_activityBtn.selected = NO; |
|||
|
|||
_courseBtn.titleLabel.font = [UIFont systemFontOfSize:14]; |
|||
_infoBtn.titleLabel.font = [UIFont systemFontOfSize:14]; |
|||
_activityBtn.titleLabel.font = [UIFont systemFontOfSize:14]; |
|||
|
|||
_courseUnderline.hidden = YES; |
|||
_infoUnderline.hidden = YES; |
|||
_activityUnderline.hidden = YES; |
|||
|
|||
// 设置选中按钮状态 |
|||
selectedButton.selected = YES; |
|||
selectedButton.titleLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightMedium]; |
|||
|
|||
// 显示对应下划线 |
|||
if (selectedButton == _courseBtn) { |
|||
_courseUnderline.hidden = NO; |
|||
} else if (selectedButton == _infoBtn) { |
|||
_infoUnderline.hidden = NO; |
|||
} else if (selectedButton == _activityBtn) { |
|||
_activityUnderline.hidden = NO; |
|||
} |
|||
} |
|||
|
|||
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView { |
|||
if (scrollView == _bannerScrollView) { |
|||
CGFloat screenWidth = self.view.bounds.size.width; |
|||
NSInteger currentOffsetX = scrollView.contentOffset.x; |
|||
NSInteger page = currentOffsetX / screenWidth; |
|||
|
|||
// 首尾拼接图无缝跳转 |
|||
if (page == 0) { |
|||
page = 2; |
|||
[scrollView setContentOffset:CGPointMake(screenWidth * page, 0) animated:NO]; |
|||
} else if (page == 3) { |
|||
page = 1; |
|||
[scrollView setContentOffset:CGPointMake(screenWidth * page, 0) animated:NO]; |
|||
} |
|||
|
|||
_currentBannerIndex = (page - 1) % 2; |
|||
_bannerPageControl.currentPage = _currentBannerIndex; |
|||
|
|||
// 重启定时器 |
|||
[_bannerTimer invalidate]; |
|||
_bannerTimer = [NSTimer scheduledTimerWithTimeInterval:3.0 |
|||
target:self |
|||
selector:@selector(autoScrollBanner) |
|||
userInfo:nil |
|||
repeats:YES]; |
|||
} |
|||
} |
|||
|
|||
- (void)autoScrollBanner { |
|||
CGFloat screenWidth = self.view.bounds.size.width; |
|||
|
|||
// 直接基于真实索引计算下一页,避免contentOffset的延迟问题 |
|||
_currentBannerIndex = (_currentBannerIndex + 1) % 2; // 0→1→0循环 |
|||
NSInteger targetPage = _currentBannerIndex + 1; // 对应拼接后的页面(1/2) |
|||
|
|||
// 处理尾部拼接图的无缝跳转 |
|||
if (targetPage > 2) { |
|||
targetPage = 1; |
|||
[_bannerScrollView setContentOffset:CGPointMake(screenWidth * targetPage, 0) animated:NO]; |
|||
} |
|||
|
|||
[_bannerScrollView setContentOffset:CGPointMake(screenWidth * targetPage, 0) animated:YES]; |
|||
_bannerPageControl.currentPage = _currentBannerIndex; |
|||
} |
|||
|
|||
- (void) pushQuotation { |
|||
QuotationViewController *quotationViewController = [[QuotationViewController alloc] init]; |
|||
[self.navigationController pushViewController:quotationViewController animated:YES]; |
|||
} |
|||
|
|||
- (void)tabBarDidSelectIndex:(NSInteger)index { |
|||
if (index == 3) { |
|||
[self pushMine]; |
|||
} |
|||
else if (index == 0) { |
|||
|
|||
} |
|||
else if (index == 1) { |
|||
[self pushQuotation]; |
|||
} |
|||
else if (index == 2) { |
|||
// 自选 |
|||
} |
|||
} |
|||
|
|||
#pragma mark - 视图即将消失 |
|||
- (void)viewWillDisappear:(BOOL)animated { |
|||
[super viewWillDisappear:animated]; |
|||
[_bannerTimer invalidate];// 销毁定时器 |
|||
_bannerTimer = nil; |
|||
} |
|||
|
|||
- (void)viewDidAppear:(BOOL)animated { |
|||
[super viewDidAppear:animated]; |
|||
|
|||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ |
|||
[UIView animateWithDuration:0.3 animations:^{ |
|||
self->_successLabel.alpha = 0; |
|||
} completion:^(BOOL finished) { |
|||
[self->_successLabel removeFromSuperview]; |
|||
}]; |
|||
}); |
|||
} |
|||
|
|||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { |
|||
return _courseData.count; |
|||
} |
|||
|
|||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { |
|||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CourseCell" forIndexPath:indexPath]; |
|||
cell.backgroundColor = [UIColor blackColor]; |
|||
cell.selectionStyle = UITableViewCellSelectionStyleNone; |
|||
|
|||
for (UIView *subview in cell.contentView.subviews) { |
|||
[subview removeFromSuperview]; |
|||
} |
|||
|
|||
NSDictionary *course = _courseData[indexPath.row]; |
|||
UIImageView *coverView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:course[@"cover"]]]; |
|||
coverView.contentMode = UIViewContentModeScaleAspectFill; |
|||
coverView.clipsToBounds = YES; |
|||
coverView.frame = CGRectMake(15, 10, 140, 100); |
|||
[cell.contentView addSubview:coverView]; |
|||
|
|||
UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(170, 10, 220, 60)]; |
|||
titleLabel.text = course[@"title"]; |
|||
titleLabel.textColor = [UIColor whiteColor]; |
|||
titleLabel.font = [UIFont systemFontOfSize:14]; |
|||
titleLabel.numberOfLines = 3; |
|||
[cell.contentView addSubview:titleLabel]; |
|||
|
|||
UILabel *lecturerLabel = [[UILabel alloc] initWithFrame:CGRectMake(170, 75, 120, 30)]; |
|||
lecturerLabel.text = course[@"lecturer"]; |
|||
lecturerLabel.textColor = [UIColor lightGrayColor]; |
|||
lecturerLabel.font = [UIFont systemFontOfSize:14]; |
|||
[cell.contentView addSubview:lecturerLabel]; |
|||
|
|||
UIView *bottomLine = [[UIView alloc] init]; |
|||
bottomLine.backgroundColor = [UIColor lightGrayColor]; |
|||
bottomLine.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[cell.contentView addSubview:bottomLine]; |
|||
|
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[bottomLine.leadingAnchor constraintEqualToAnchor:cell.contentView.leadingAnchor constant:20], // 左边距15 |
|||
[bottomLine.trailingAnchor constraintEqualToAnchor:cell.contentView.trailingAnchor constant:-20], // 右边距15 |
|||
[bottomLine.bottomAnchor constraintEqualToAnchor:cell.contentView.bottomAnchor], |
|||
[bottomLine.heightAnchor constraintEqualToConstant:0.2] |
|||
]]; |
|||
|
|||
return cell; |
|||
} |
|||
|
|||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { |
|||
return 120; |
|||
} |
|||
|
|||
@end |
|||
@ -0,0 +1,16 @@ |
|||
// |
|||
// MLXYViewController.h |
|||
// HC |
|||
// |
|||
// Created by huilinLi on 2025/11/26. |
|||
// |
|||
|
|||
#import <UIKit/UIKit.h> |
|||
|
|||
NS_ASSUME_NONNULL_BEGIN |
|||
|
|||
@interface MLXYViewController : UIViewController |
|||
|
|||
@end |
|||
|
|||
NS_ASSUME_NONNULL_END |
|||
@ -0,0 +1,442 @@ |
|||
// |
|||
// MLXYViewController.m |
|||
// HC |
|||
// |
|||
// Created by huilinLi on 2025/11/26. |
|||
// |
|||
#import "MLXYViewController.h" |
|||
#import "ChartViewController.h" |
|||
|
|||
@interface MLXYViewController () <UITableViewDataSource, UITableViewDelegate> |
|||
@property (nonatomic, strong) UIButton *mlxyButton; |
|||
// 大盘指数 |
|||
@property (nonatomic, strong) UILabel *marketTitleLabel; |
|||
@property (nonatomic, strong) UIView *marketView; |
|||
@property (nonatomic, strong) UILabel *marketLine1; |
|||
@property (nonatomic, strong) UILabel *marketLine2; |
|||
@property (nonatomic, strong) UILabel *marketLine3; |
|||
// 板块 |
|||
@property (nonatomic, strong) UILabel *sectorTitleLabel; |
|||
@property (nonatomic, strong) UIButton *sectorBtn; |
|||
// 三个板块卡片(分别配置) |
|||
@property (nonatomic, strong) UIView *sectorCard1; |
|||
@property (nonatomic, strong) UIView *sectorCard2; |
|||
@property (nonatomic, strong) UIView *sectorCard3; |
|||
// 股票 |
|||
@property (nonatomic, strong) UIView *stockContainer; |
|||
@property (nonatomic, strong) UITableView *stockTableView; |
|||
// 股票表头 |
|||
@property (nonatomic, strong) UIView *stockHeaderView; |
|||
// 按钮配置 |
|||
@property (nonatomic, strong) UIButtonConfiguration *buttonConfig; |
|||
// 板块数据配置 |
|||
@property (nonatomic, strong) NSArray *sectorDataConfig; |
|||
@end |
|||
|
|||
@implementation MLXYViewController |
|||
|
|||
- (void)viewDidLoad { |
|||
[super viewDidLoad]; |
|||
self.view.backgroundColor = [UIColor blackColor]; |
|||
|
|||
[self setupButtonConfig]; |
|||
[self setupSectorDataConfig]; |
|||
|
|||
[self setupSubviews]; |
|||
[self setupConstraints]; |
|||
|
|||
[self marketViewClick]; |
|||
} |
|||
|
|||
-(void) marketViewClick{ |
|||
_marketView.userInteractionEnabled = YES; |
|||
UITapGestureRecognizer *click = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(marketViewPush)]; |
|||
[_marketView addGestureRecognizer:click]; |
|||
} |
|||
|
|||
-(void) marketViewPush{ |
|||
ChartViewController *chartViewController = [[ChartViewController alloc] init]; |
|||
[self.navigationController pushViewController:chartViewController animated:YES]; |
|||
} |
|||
|
|||
- (void)setupButtonConfig { |
|||
UIButtonConfiguration *config = [UIButtonConfiguration plainButtonConfiguration]; |
|||
config.title = @"更多"; |
|||
config.attributedTitle = [[NSAttributedString alloc] initWithString:@"更多" attributes:@{ |
|||
NSFontAttributeName: [UIFont systemFontOfSize:14], |
|||
NSForegroundColorAttributeName: [UIColor lightGrayColor] |
|||
}]; |
|||
|
|||
UIImage *image = [[UIImage systemImageNamed:@"chevron.right"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; |
|||
config.image = image; |
|||
config.imagePlacement = NSDirectionalRectEdgeTrailing; // 图片在文字右侧 |
|||
config.imagePadding = 1; |
|||
|
|||
config.baseForegroundColor = [UIColor lightGrayColor]; |
|||
|
|||
_buttonConfig = config; |
|||
} |
|||
|
|||
- (void)setupSectorDataConfig { |
|||
_sectorDataConfig = @[ |
|||
@{@"name":@"Health", @"value1":@"1099.683", @"value2":@"27.236",@"value3":@"2.270%"}, |
|||
@{@"name":@"Others", @"value1":@"2083.783", @"value2":@"0.000",@"value3":@"0.000%"}, |
|||
@{@"name":@"HLKLI", @"value1":@"987.895", @"value2":@"-1.854",@"value3":@"-0.230%"} |
|||
]; |
|||
} |
|||
|
|||
- (void)setupSubviews { |
|||
// 马来西亚按钮 |
|||
_mlxyButton = [UIButton buttonWithType:UIButtonTypeSystem]; |
|||
[_mlxyButton setTitle:@"马来西亚" forState:UIControlStateNormal]; |
|||
[_mlxyButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; |
|||
[_mlxyButton setBackgroundColor:[UIColor blueColor]]; |
|||
_mlxyButton.layer.cornerRadius = 15; |
|||
_mlxyButton.titleLabel.font = [UIFont systemFontOfSize:14]; |
|||
_mlxyButton.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:_mlxyButton]; |
|||
|
|||
// 大盘指数 |
|||
_marketTitleLabel = [[UILabel alloc] init]; |
|||
_marketTitleLabel.text = @"大盘指数"; |
|||
_marketTitleLabel.textColor = [UIColor whiteColor]; |
|||
_marketTitleLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightMedium]; |
|||
_marketTitleLabel.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:_marketTitleLabel]; |
|||
|
|||
// 绿色卡片 |
|||
_marketView = [[UIView alloc] init]; |
|||
_marketView.backgroundColor = [UIColor greenColor]; |
|||
_marketView.layer.cornerRadius = 8; |
|||
_marketView.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:_marketView]; |
|||
|
|||
_marketLine1 = [[UILabel alloc] init]; |
|||
_marketLine1.text = @"富时马来西亚KLCI"; |
|||
_marketLine1.textColor = [UIColor whiteColor]; |
|||
_marketLine1.font = [UIFont fontWithName:@"Helvetica-Bold" size:12]; |
|||
_marketLine1.textAlignment = NSTextAlignmentCenter; |
|||
_marketLine1.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[_marketView addSubview:_marketLine1]; |
|||
|
|||
_marketLine2 = [[UILabel alloc] init]; |
|||
_marketLine2.text = @"1624.500"; |
|||
_marketLine2.textColor = [UIColor whiteColor]; |
|||
_marketLine2.font = [UIFont boldSystemFontOfSize:17]; |
|||
_marketLine2.textAlignment = NSTextAlignmentCenter; |
|||
_marketLine2.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[_marketView addSubview:_marketLine2]; |
|||
|
|||
_marketLine3 = [[UILabel alloc] init]; |
|||
_marketLine3.text = @"12.760 0.792%"; |
|||
_marketLine3.textColor = [UIColor whiteColor]; |
|||
_marketLine3.font = [UIFont boldSystemFontOfSize:12]; |
|||
_marketLine3.textAlignment = NSTextAlignmentCenter; |
|||
_marketLine3.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[_marketView addSubview:_marketLine3]; |
|||
|
|||
// 板块 |
|||
_sectorTitleLabel = [[UILabel alloc] init]; |
|||
_sectorTitleLabel.text = @"板块"; |
|||
_sectorTitleLabel.textColor = [UIColor whiteColor]; |
|||
_sectorTitleLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightMedium]; |
|||
_sectorTitleLabel.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:_sectorTitleLabel]; |
|||
|
|||
_sectorBtn = [UIButton buttonWithConfiguration:self.buttonConfig primaryAction:nil]; |
|||
_sectorBtn.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:_sectorBtn]; |
|||
|
|||
_sectorCard1 = [self createSectorCardWithData:self.sectorDataConfig[0]]; |
|||
[self.view addSubview:_sectorCard1]; |
|||
|
|||
_sectorCard2 = [self createSectorCardWithData:self.sectorDataConfig[1]]; |
|||
[self.view addSubview:_sectorCard2]; |
|||
|
|||
_sectorCard3 = [self createSectorCardWithData:self.sectorDataConfig[2]]; |
|||
[self.view addSubview:_sectorCard3]; |
|||
|
|||
// 股票容器 |
|||
_stockContainer = [[UIView alloc] init]; |
|||
_stockContainer.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:_stockContainer]; |
|||
|
|||
UILabel *stockTitleLabel = [[UILabel alloc] init]; |
|||
stockTitleLabel.text = @"股票"; |
|||
stockTitleLabel.textColor = [UIColor whiteColor]; |
|||
stockTitleLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightMedium]; |
|||
stockTitleLabel.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[_stockContainer addSubview:stockTitleLabel]; |
|||
|
|||
UIButton *stockBtn = [UIButton buttonWithConfiguration:self.buttonConfig primaryAction:nil]; |
|||
stockBtn.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[_stockContainer addSubview:stockBtn]; |
|||
|
|||
// 股票列表表头 |
|||
_stockHeaderView = [[UIView alloc] init]; |
|||
_stockHeaderView.backgroundColor = [UIColor blackColor]; |
|||
_stockHeaderView.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[_stockContainer addSubview:_stockHeaderView]; |
|||
|
|||
NSArray *headerTitles = @[@"名称", @"最新", @"涨幅"]; |
|||
for (NSInteger i = 0; i < headerTitles.count; i++) { |
|||
UILabel *headerLabel = [[UILabel alloc] init]; |
|||
headerLabel.text = headerTitles[i]; |
|||
headerLabel.textColor = [UIColor lightGrayColor]; |
|||
headerLabel.font = [UIFont systemFontOfSize:12]; |
|||
headerLabel.textAlignment = (i == 0) ? NSTextAlignmentLeft : NSTextAlignmentRight; |
|||
headerLabel.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[_stockHeaderView addSubview:headerLabel]; |
|||
|
|||
if (i == 0) { |
|||
[headerLabel.leadingAnchor constraintEqualToAnchor:_stockHeaderView.leadingAnchor constant:15].active = YES; |
|||
} else if (i == 1) { |
|||
[headerLabel.widthAnchor constraintEqualToConstant:60].active = YES; |
|||
[headerLabel.trailingAnchor constraintEqualToAnchor:_stockHeaderView.trailingAnchor constant:-110].active = YES; |
|||
} else { |
|||
[headerLabel.widthAnchor constraintEqualToConstant:80].active = YES; |
|||
[headerLabel.trailingAnchor constraintEqualToAnchor:_stockHeaderView.trailingAnchor constant:-30].active = YES; |
|||
} |
|||
[headerLabel.centerYAnchor constraintEqualToAnchor:_stockHeaderView.centerYAnchor].active = YES; |
|||
} |
|||
|
|||
_stockTableView = [[UITableView alloc] init]; |
|||
_stockTableView.backgroundColor = [UIColor blackColor]; |
|||
_stockTableView.separatorStyle = UITableViewCellSeparatorStyleNone;// 隐藏单元格之间的分隔线 |
|||
//SingleLine 默认,1px的分割线 |
|||
_stockTableView.delegate = self; |
|||
_stockTableView.dataSource = self; |
|||
[_stockTableView registerClass:[UITableViewCell class]// 单元格复用类 |
|||
forCellReuseIdentifier:@"StockCell"];// 复用标识 |
|||
_stockTableView.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[_stockContainer addSubview:_stockTableView]; |
|||
} |
|||
|
|||
- (UIView *)createSectorCardWithData:(NSDictionary *)data { |
|||
UIView *card = [[UIView alloc] init]; |
|||
card.backgroundColor = [UIColor darkGrayColor]; |
|||
card.layer.cornerRadius = 8; |
|||
card.translatesAutoresizingMaskIntoConstraints = NO; |
|||
|
|||
// 名称 |
|||
UILabel *nameLabel = [[UILabel alloc] init]; |
|||
nameLabel.text = data[@"name"]; |
|||
nameLabel.textColor = [UIColor whiteColor]; |
|||
nameLabel.font = [UIFont systemFontOfSize:14]; |
|||
nameLabel.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[card addSubview:nameLabel]; |
|||
|
|||
// 数值 |
|||
UILabel *value1Label = [[UILabel alloc] init]; |
|||
value1Label.text = data[@"value1"]; |
|||
value1Label.textColor = [UIColor greenColor]; |
|||
value1Label.font = [UIFont systemFontOfSize:16 weight:UIFontWeightBold]; |
|||
value1Label.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[card addSubview:value1Label]; |
|||
|
|||
// 涨幅 |
|||
UILabel *value2Label = [[UILabel alloc] init]; |
|||
value2Label.text = data[@"value2"]; |
|||
value2Label.textColor = [UIColor greenColor]; |
|||
value2Label.font = [UIFont systemFontOfSize:12]; |
|||
value2Label.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[card addSubview:value2Label]; |
|||
|
|||
UILabel *value3Label = [[UILabel alloc] init]; |
|||
value3Label.text = data[@"value3"]; |
|||
value3Label.textColor = [UIColor greenColor]; |
|||
value3Label.font = [UIFont systemFontOfSize:12]; |
|||
value3Label.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[card addSubview:value3Label]; |
|||
|
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[nameLabel.topAnchor constraintEqualToAnchor:card.topAnchor constant:7], |
|||
[nameLabel.leadingAnchor constraintEqualToAnchor:card.leadingAnchor constant:10], |
|||
|
|||
[value1Label.topAnchor constraintEqualToAnchor:nameLabel.bottomAnchor constant:10], |
|||
[value1Label.leadingAnchor constraintEqualToAnchor:card.leadingAnchor constant:10], |
|||
|
|||
[value2Label.topAnchor constraintEqualToAnchor:value1Label.bottomAnchor constant:7], |
|||
[value2Label.leadingAnchor constraintEqualToAnchor:card.leadingAnchor constant:10], |
|||
|
|||
[value3Label.topAnchor constraintEqualToAnchor:value2Label.bottomAnchor constant:6], |
|||
[value3Label.leadingAnchor constraintEqualToAnchor:card.leadingAnchor constant:10] |
|||
]]; |
|||
|
|||
return card; |
|||
} |
|||
|
|||
- (void)setupConstraints { |
|||
// 马来西亚按钮 |
|||
NSLayoutConstraint *btnTop = [_mlxyButton.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor]; |
|||
NSLayoutConstraint *btnLeft = [_mlxyButton.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:15]; |
|||
NSLayoutConstraint *btnWidth = [_mlxyButton.widthAnchor constraintEqualToConstant:90]; |
|||
NSLayoutConstraint *btnHeight = [_mlxyButton.heightAnchor constraintEqualToConstant:30]; |
|||
[NSLayoutConstraint activateConstraints:@[btnTop, btnLeft, btnWidth, btnHeight]]; |
|||
|
|||
// 大盘 |
|||
NSLayoutConstraint *marketTitleTop = [_marketTitleLabel.topAnchor constraintEqualToAnchor:_mlxyButton.bottomAnchor constant:10]; |
|||
NSLayoutConstraint *marketTitleLeft = [_marketTitleLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:15]; |
|||
[NSLayoutConstraint activateConstraints:@[marketTitleTop, marketTitleLeft]]; |
|||
|
|||
NSLayoutConstraint *marketCardTop = [_marketView.topAnchor constraintEqualToAnchor:_marketTitleLabel.bottomAnchor constant:10]; |
|||
NSLayoutConstraint *marketCardLeft = [_marketView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:15]; |
|||
NSLayoutConstraint *marketCardWidth = [_marketView.widthAnchor constraintEqualToAnchor:self.view.widthAnchor multiplier:0.3]; |
|||
NSLayoutConstraint *marketCardHeight = [_marketView.heightAnchor constraintEqualToConstant:100]; |
|||
[NSLayoutConstraint activateConstraints:@[marketCardTop, marketCardLeft, marketCardWidth, marketCardHeight]]; |
|||
|
|||
NSLayoutConstraint *line1Top = [_marketLine1.topAnchor constraintEqualToAnchor:_marketView.topAnchor constant:10]; |
|||
NSLayoutConstraint *line1CenterX = [_marketLine1.centerXAnchor constraintEqualToAnchor:_marketView.centerXAnchor]; |
|||
|
|||
NSLayoutConstraint *line2Top = [_marketLine2.topAnchor constraintEqualToAnchor:_marketLine1.bottomAnchor constant:15]; |
|||
NSLayoutConstraint *line2CenterX = [_marketLine2.centerXAnchor constraintEqualToAnchor:_marketView.centerXAnchor]; |
|||
|
|||
NSLayoutConstraint *line3Top = [_marketLine3.topAnchor constraintEqualToAnchor:_marketLine2.bottomAnchor constant:12]; |
|||
NSLayoutConstraint *line3CenterX = [_marketLine3.centerXAnchor constraintEqualToAnchor:_marketView.centerXAnchor]; |
|||
|
|||
[NSLayoutConstraint activateConstraints:@[line1Top, line1CenterX, line2Top, line2CenterX, line3Top, line3CenterX]]; |
|||
|
|||
// 板块 |
|||
NSLayoutConstraint *sectorTitleTop = [_sectorTitleLabel.topAnchor constraintEqualToAnchor:_marketView.bottomAnchor constant:20]; |
|||
NSLayoutConstraint *sectorTitleLeft = [_sectorTitleLabel.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:15]; |
|||
[NSLayoutConstraint activateConstraints:@[sectorTitleTop, sectorTitleLeft]]; |
|||
|
|||
NSLayoutConstraint *sectorBtnTop = [_sectorBtn.centerYAnchor constraintEqualToAnchor:_sectorTitleLabel.centerYAnchor]; |
|||
NSLayoutConstraint *sectorBtnRight = [_sectorBtn.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-15]; |
|||
[NSLayoutConstraint activateConstraints:@[sectorBtnTop, sectorBtnRight]]; |
|||
|
|||
NSLayoutConstraint *card1Top = [_sectorCard1.topAnchor constraintEqualToAnchor:_sectorTitleLabel.bottomAnchor constant:10]; |
|||
NSLayoutConstraint *card1Left = [_sectorCard1.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:8]; |
|||
NSLayoutConstraint *card1Width = [_sectorCard1.widthAnchor constraintEqualToAnchor:self.view.widthAnchor multiplier:0.3]; |
|||
NSLayoutConstraint *card1Height = [_sectorCard1.heightAnchor constraintEqualToConstant:100]; |
|||
[NSLayoutConstraint activateConstraints:@[card1Top, card1Left, card1Width, card1Height]]; |
|||
|
|||
NSLayoutConstraint *card2Top = [_sectorCard2.topAnchor constraintEqualToAnchor:_sectorCard1.topAnchor]; |
|||
NSLayoutConstraint *card2Left = [_sectorCard2.leadingAnchor constraintEqualToAnchor:_sectorCard1.trailingAnchor constant:8]; |
|||
NSLayoutConstraint *card2Width = [_sectorCard2.widthAnchor constraintEqualToAnchor:_sectorCard1.widthAnchor]; |
|||
NSLayoutConstraint *card2Height = [_sectorCard2.heightAnchor constraintEqualToAnchor:_sectorCard1.heightAnchor]; |
|||
[NSLayoutConstraint activateConstraints:@[card2Top, card2Left, card2Width, card2Height]]; |
|||
|
|||
NSLayoutConstraint *card3Top = [_sectorCard3.topAnchor constraintEqualToAnchor:_sectorCard1.topAnchor]; |
|||
NSLayoutConstraint *card3Left = [_sectorCard3.leadingAnchor constraintEqualToAnchor:_sectorCard2.trailingAnchor constant:8]; |
|||
NSLayoutConstraint *card3Right = [_sectorCard3.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-16]; |
|||
// *card3Width = [_sectorCard3.widthAnchor constraintEqualToAnchor:_sectorCard1.widthAnchor];都行 |
|||
NSLayoutConstraint *card3Height = [_sectorCard3.heightAnchor constraintEqualToAnchor:_sectorCard1.heightAnchor]; |
|||
[NSLayoutConstraint activateConstraints:@[card3Top, card3Left, card3Right, card3Height]]; |
|||
|
|||
// 股票容器 |
|||
NSLayoutConstraint *stockTop = [_stockContainer.topAnchor constraintEqualToAnchor:_sectorCard1.bottomAnchor constant:20]; |
|||
NSLayoutConstraint *stockLeft = [_stockContainer.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor]; |
|||
NSLayoutConstraint *stockRight = [_stockContainer.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor]; |
|||
NSLayoutConstraint *stockBottom = [_stockContainer.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor]; |
|||
[NSLayoutConstraint activateConstraints:@[stockTop, stockLeft, stockRight, stockBottom]]; |
|||
|
|||
UILabel *stockTitleLabel = _stockContainer.subviews[0]; |
|||
UIButton *stockBtn = _stockContainer.subviews[1]; |
|||
|
|||
NSLayoutConstraint *stockTitleTop = [stockTitleLabel.topAnchor constraintEqualToAnchor:_stockContainer.topAnchor constant:15]; |
|||
NSLayoutConstraint *stockTitleLeft = [stockTitleLabel.leadingAnchor constraintEqualToAnchor:_stockContainer.leadingAnchor constant:15]; |
|||
|
|||
NSLayoutConstraint *stockBtnTop = [stockBtn.centerYAnchor constraintEqualToAnchor:stockTitleLabel.centerYAnchor]; |
|||
NSLayoutConstraint *stockBtnRight = [stockBtn.trailingAnchor constraintEqualToAnchor:_stockContainer.trailingAnchor constant:-15]; |
|||
|
|||
[NSLayoutConstraint activateConstraints:@[stockTitleTop, stockTitleLeft, stockBtnTop, stockBtnRight]]; |
|||
|
|||
// 股票表头 |
|||
NSLayoutConstraint *headerTop = [_stockHeaderView.topAnchor constraintEqualToAnchor:stockTitleLabel.bottomAnchor constant:10]; |
|||
NSLayoutConstraint *headerLeft = [_stockHeaderView.leadingAnchor constraintEqualToAnchor:_stockContainer.leadingAnchor]; |
|||
NSLayoutConstraint *headerRight = [_stockHeaderView.trailingAnchor constraintEqualToAnchor:_stockContainer.trailingAnchor]; |
|||
NSLayoutConstraint *headerHeight = [_stockHeaderView.heightAnchor constraintEqualToConstant:30]; |
|||
[NSLayoutConstraint activateConstraints:@[headerTop, headerLeft, headerRight, headerHeight]]; |
|||
|
|||
// 股票列表 |
|||
NSLayoutConstraint *tableTop = [_stockTableView.topAnchor constraintEqualToAnchor:_stockHeaderView.bottomAnchor]; |
|||
NSLayoutConstraint *tableLeft = [_stockTableView.leadingAnchor constraintEqualToAnchor:_stockContainer.leadingAnchor]; |
|||
NSLayoutConstraint *tableRight = [_stockTableView.trailingAnchor constraintEqualToAnchor:_stockContainer.trailingAnchor]; |
|||
NSLayoutConstraint *tableBottom = [_stockTableView.bottomAnchor constraintEqualToAnchor:_stockContainer.bottomAnchor]; |
|||
[NSLayoutConstraint activateConstraints:@[tableTop, tableLeft, tableRight, tableBottom]]; |
|||
} |
|||
|
|||
#pragma mark - UITableView |
|||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { |
|||
return 4; |
|||
} |
|||
|
|||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { |
|||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"StockCell" forIndexPath:indexPath]; |
|||
cell.backgroundColor = [UIColor blackColor]; |
|||
cell.selectionStyle = UITableViewCellSelectionStyleNone; |
|||
|
|||
// 清空复用内容 |
|||
[cell.contentView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; |
|||
|
|||
NSArray *stocks = @[ |
|||
@{@"name":@"PEGASUS HEIGHTS BERHAD", @"code":@"4464", @"price":@"0.010", @"value2":@"100.000%"}, |
|||
@{@"name":@"SMTRACK BERHAD", @"code":@"0169", @"price":@"0.010", @"value2":@"100.000%"}, |
|||
@{@"name":@"TXCD BERHAD - ICPS 2020/2030", @"code":@"7145PA", @"price":@"0.020", @"value2":@"33.333%"}, |
|||
@{@"name":@"DNONCE TECHNOLOGY BHD", @"code":@"7114", @"price":@"0.040", @"value2":@"33.333%"} |
|||
]; |
|||
NSDictionary *stock = stocks[indexPath.row]; |
|||
|
|||
// 名称 |
|||
UILabel *nameLabel = [[UILabel alloc] init]; |
|||
nameLabel.text = stock[@"name"]; |
|||
nameLabel.textColor = [UIColor whiteColor]; |
|||
nameLabel.font = [UIFont systemFontOfSize:14]; |
|||
nameLabel.numberOfLines = 1; |
|||
nameLabel.lineBreakMode = NSLineBreakByTruncatingTail; |
|||
nameLabel.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[cell.contentView addSubview:nameLabel]; |
|||
|
|||
// 代码 |
|||
UILabel *codeLabel = [[UILabel alloc] init]; |
|||
codeLabel.text = stock[@"code"]; |
|||
codeLabel.textColor = [UIColor lightGrayColor]; |
|||
codeLabel.font = [UIFont systemFontOfSize:12]; |
|||
codeLabel.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[cell.contentView addSubview:codeLabel]; |
|||
|
|||
// 价格 |
|||
UILabel *priceLabel = [[UILabel alloc] init]; |
|||
priceLabel.text = stock[@"price"]; |
|||
priceLabel.textColor = [UIColor greenColor]; |
|||
priceLabel.font = [UIFont systemFontOfSize:14]; |
|||
priceLabel.textAlignment = NSTextAlignmentRight; |
|||
priceLabel.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[cell.contentView addSubview:priceLabel]; |
|||
|
|||
// 涨幅 |
|||
UILabel *value2Label = [[UILabel alloc] init]; |
|||
value2Label.text = stock[@"value2"]; |
|||
value2Label.textColor = [UIColor greenColor]; |
|||
value2Label.font = [UIFont systemFontOfSize:14]; |
|||
value2Label.textAlignment = NSTextAlignmentRight; |
|||
value2Label.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[cell.contentView addSubview:value2Label]; |
|||
|
|||
// 约束 |
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[nameLabel.leadingAnchor constraintEqualToAnchor:cell.contentView.leadingAnchor constant:15], |
|||
[nameLabel.topAnchor constraintEqualToAnchor:cell.contentView.topAnchor constant:10], |
|||
[nameLabel.trailingAnchor constraintLessThanOrEqualToAnchor:priceLabel.leadingAnchor constant:-10], |
|||
|
|||
[codeLabel.leadingAnchor constraintEqualToAnchor:cell.contentView.leadingAnchor constant:15], |
|||
[codeLabel.topAnchor constraintEqualToAnchor:nameLabel.bottomAnchor constant:5], |
|||
|
|||
[priceLabel.widthAnchor constraintEqualToConstant:60], |
|||
[priceLabel.trailingAnchor constraintEqualToAnchor:value2Label.leadingAnchor constant:-10], |
|||
[priceLabel.centerYAnchor constraintEqualToAnchor:cell.contentView.centerYAnchor], |
|||
|
|||
[value2Label.widthAnchor constraintEqualToConstant:80], |
|||
[value2Label.trailingAnchor constraintEqualToAnchor:cell.contentView.trailingAnchor constant:-15], |
|||
[value2Label.centerYAnchor constraintEqualToAnchor:cell.contentView.centerYAnchor] |
|||
]]; |
|||
|
|||
return cell; |
|||
} |
|||
|
|||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { |
|||
return 60; |
|||
} |
|||
|
|||
@end |
|||
@ -0,0 +1,18 @@ |
|||
// |
|||
// MyViewController.h |
|||
// HC |
|||
// |
|||
// Created by huilinLi on 2025/11/25. |
|||
// |
|||
|
|||
#import <UIKit/UIKit.h> |
|||
|
|||
NS_ASSUME_NONNULL_BEGIN |
|||
|
|||
@class CommonTabBar; |
|||
|
|||
@interface MyViewController : UIViewController |
|||
@property (nonatomic, strong) CommonTabBar *tabBar; |
|||
@property (nonatomic, strong) UIView *lastSettingItem; |
|||
@end |
|||
NS_ASSUME_NONNULL_END |
|||
@ -0,0 +1,390 @@ |
|||
// |
|||
// MyViewController.m |
|||
// HC |
|||
// |
|||
// Created by huilinLi on 2025/11/25. |
|||
// |
|||
|
|||
#import "MyViewController.h" |
|||
#import <UIKit/UIKit.h> |
|||
#import "CommonTabBar.h" |
|||
#import "HomeViewController.h" |
|||
#import "ViewController.h" |
|||
#import "QuotationViewController.h" |
|||
|
|||
@implementation MyViewController |
|||
|
|||
- (void)viewDidLoad { |
|||
[super viewDidLoad]; |
|||
self.view.backgroundColor = [UIColor blackColor]; |
|||
|
|||
[self setupUI]; |
|||
} |
|||
|
|||
- (void)setupUI { |
|||
UIScrollView *scrollView = [[UIScrollView alloc] init]; |
|||
scrollView.translatesAutoresizingMaskIntoConstraints = NO; |
|||
scrollView.backgroundColor = [UIColor blackColor]; |
|||
[self.view addSubview:scrollView]; |
|||
|
|||
UIView *contentView = [[UIView alloc] init]; |
|||
contentView.translatesAutoresizingMaskIntoConstraints = NO; |
|||
contentView.backgroundColor = [UIColor blackColor]; |
|||
[scrollView addSubview:contentView]; |
|||
|
|||
[self setupUserHeaderInContentView:contentView]; |
|||
[self setupCoinDiamondInContentView:contentView]; |
|||
[self setupSettingListInContentView:contentView]; |
|||
[self setupLogoutButtonInContentView:contentView]; |
|||
[self setupTabBar]; |
|||
|
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[scrollView.topAnchor constraintEqualToAnchor:self.view.topAnchor], |
|||
[scrollView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], |
|||
[scrollView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], |
|||
[scrollView.bottomAnchor constraintEqualToAnchor:self.tabBar.topAnchor], |
|||
|
|||
[contentView.topAnchor constraintEqualToAnchor:scrollView.topAnchor], |
|||
[contentView.leadingAnchor constraintEqualToAnchor:scrollView.leadingAnchor], |
|||
[contentView.trailingAnchor constraintEqualToAnchor:scrollView.trailingAnchor], |
|||
[contentView.bottomAnchor constraintEqualToAnchor:scrollView.bottomAnchor], |
|||
[contentView.widthAnchor constraintEqualToAnchor:scrollView.widthAnchor] |
|||
]]; |
|||
} |
|||
|
|||
#pragma mark - 上边儿 |
|||
- (void)setupUserHeaderInContentView:(UIView *)contentView { |
|||
UIButton *settingBtn = [UIButton buttonWithType:UIButtonTypeSystem]; |
|||
[settingBtn setImage:[UIImage systemImageNamed:@"gearshape"] forState:UIControlStateNormal]; |
|||
settingBtn.tintColor = [UIColor whiteColor]; |
|||
settingBtn.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[contentView addSubview:settingBtn]; |
|||
|
|||
UIImageView *avatar = [self createImageViewWithImage:@"hqz" contentMode:UIViewContentModeScaleAspectFill cornerRadius:40]; |
|||
[contentView addSubview:avatar]; |
|||
|
|||
UILabel *nameLabel = [self createLabelWithText:@"演示机李慧琳" fontSize:18 textColor:[UIColor whiteColor]]; |
|||
[contentView addSubview:nameLabel]; |
|||
|
|||
UILabel *idLabel = [self createLabelWithText:@"ID: 90047681" fontSize:14 textColor:[UIColor whiteColor]]; |
|||
[contentView addSubview:idLabel]; |
|||
|
|||
UIButton *signBtn = [self createButtonWithTitle:@"已签到" bgColor:[UIColor whiteColor] cornerRadius:15]; |
|||
[signBtn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; |
|||
[contentView addSubview:signBtn]; |
|||
|
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[avatar.topAnchor constraintEqualToAnchor:contentView.topAnchor constant:20], |
|||
[avatar.leadingAnchor constraintEqualToAnchor:contentView.leadingAnchor constant:20], |
|||
[avatar.widthAnchor constraintEqualToConstant:80], |
|||
[avatar.heightAnchor constraintEqualToConstant:80], |
|||
|
|||
[nameLabel.centerYAnchor constraintEqualToAnchor:avatar.centerYAnchor constant:-10], |
|||
[nameLabel.leadingAnchor constraintEqualToAnchor:avatar.trailingAnchor constant:15], |
|||
|
|||
[idLabel.topAnchor constraintEqualToAnchor:nameLabel.bottomAnchor constant:5], |
|||
[idLabel.leadingAnchor constraintEqualToAnchor:nameLabel.leadingAnchor], |
|||
|
|||
[signBtn.centerYAnchor constraintEqualToAnchor:avatar.centerYAnchor], |
|||
[signBtn.trailingAnchor constraintEqualToAnchor:contentView.trailingAnchor constant:-20], |
|||
[signBtn.widthAnchor constraintEqualToConstant:90], |
|||
[signBtn.heightAnchor constraintEqualToConstant:30], |
|||
|
|||
[settingBtn.topAnchor constraintEqualToAnchor:contentView.topAnchor constant:-35], |
|||
[settingBtn.trailingAnchor constraintEqualToAnchor:contentView.trailingAnchor constant:-20], |
|||
[settingBtn.widthAnchor constraintEqualToConstant:24], |
|||
[settingBtn.heightAnchor constraintEqualToConstant:24] |
|||
]]; |
|||
} |
|||
|
|||
#pragma mark - 金币钻石 |
|||
- (void)setupCoinDiamondInContentView:(UIView *)contentView { |
|||
NSArray *itemConfigs = @[ |
|||
@{@"icon":@"hqz", @"text":@"6011.56"}, |
|||
@{@"icon":@"hqz", @"text":@"0"} |
|||
]; |
|||
|
|||
UIView *containerView = [[UIView alloc] init]; |
|||
containerView.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[contentView addSubview:containerView]; |
|||
|
|||
for (int i = 0; i < itemConfigs.count; i++) { |
|||
NSDictionary *config = itemConfigs[i]; |
|||
UIButton *btn = [self createInfoButtonWithConfig:config]; |
|||
btn.tag = 100 + i; |
|||
[containerView addSubview:btn]; |
|||
|
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[btn.topAnchor constraintEqualToAnchor:containerView.topAnchor], |
|||
[btn.bottomAnchor constraintEqualToAnchor:containerView.bottomAnchor], |
|||
[btn.widthAnchor constraintEqualToAnchor:containerView.widthAnchor multiplier:0.5], |
|||
(i == 0) ? [btn.leadingAnchor constraintEqualToAnchor:containerView.leadingAnchor] : [btn.trailingAnchor constraintEqualToAnchor:containerView.trailingAnchor] |
|||
]]; |
|||
} |
|||
|
|||
UIView *verticalDivider = [self createVerticalDivider]; |
|||
[containerView addSubview:verticalDivider]; |
|||
|
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[containerView.topAnchor constraintEqualToAnchor:contentView.subviews[1].bottomAnchor constant:20], |
|||
[containerView.leadingAnchor constraintEqualToAnchor:contentView.leadingAnchor], |
|||
[containerView.trailingAnchor constraintEqualToAnchor:contentView.trailingAnchor], |
|||
[containerView.heightAnchor constraintEqualToConstant:80], |
|||
|
|||
[verticalDivider.centerXAnchor constraintEqualToAnchor:containerView.centerXAnchor], |
|||
[verticalDivider.topAnchor constraintEqualToAnchor:containerView.topAnchor constant:10], |
|||
[verticalDivider.bottomAnchor constraintEqualToAnchor:containerView.bottomAnchor constant:-10], |
|||
[verticalDivider.widthAnchor constraintEqualToConstant:0.5] |
|||
]]; |
|||
} |
|||
|
|||
#pragma mark - 设置列表 |
|||
- (void)setupSettingListInContentView:(UIView *)contentView { |
|||
NSArray *rowTexts = @[ |
|||
@"账号与安全", |
|||
@"服务期限", |
|||
@"行情设置", |
|||
@"通用设置", |
|||
@"金币记录", |
|||
@"分享奖励", |
|||
@"联系我们", |
|||
@"新版本更新", |
|||
@"意见反馈", |
|||
@"关于Homily Chart" |
|||
]; |
|||
|
|||
// 金币钻石容器 |
|||
UIView *coinContainer = contentView.subviews.lastObject; |
|||
CGFloat topOffset = 0; |
|||
|
|||
for (int i = 0; i < rowTexts.count; i++) { |
|||
UIView *itemView = [self createCommonRowWithText:rowTexts[i]]; |
|||
[contentView addSubview:itemView]; |
|||
|
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[itemView.topAnchor constraintEqualToAnchor:coinContainer.bottomAnchor constant:topOffset + 20], |
|||
[itemView.leadingAnchor constraintEqualToAnchor:contentView.leadingAnchor], |
|||
[itemView.trailingAnchor constraintEqualToAnchor:contentView.trailingAnchor], |
|||
[itemView.heightAnchor constraintEqualToConstant:60] |
|||
]]; |
|||
|
|||
if (i < rowTexts.count - 1) { |
|||
UIView *divider = [self createDividerWithLeading:20]; |
|||
[contentView addSubview:divider]; |
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[divider.topAnchor constraintEqualToAnchor:itemView.bottomAnchor], |
|||
[divider.leadingAnchor constraintEqualToAnchor:contentView.leadingAnchor constant:20], |
|||
[divider.trailingAnchor constraintEqualToAnchor:contentView.trailingAnchor], |
|||
[divider.heightAnchor constraintEqualToConstant:0.5] |
|||
]]; |
|||
} |
|||
|
|||
topOffset += 60; |
|||
} |
|||
|
|||
self.lastSettingItem = contentView.subviews.lastObject; |
|||
} |
|||
|
|||
#pragma mark - 退出登录 |
|||
- (void)setupLogoutButtonInContentView:(UIView *)contentView { |
|||
UIButton *logoutBtn = [UIButton buttonWithType:UIButtonTypeSystem]; |
|||
[logoutBtn setTitle:@"退出登录" forState:UIControlStateNormal]; |
|||
[logoutBtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal]; |
|||
logoutBtn.titleLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightMedium]; |
|||
logoutBtn.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[logoutBtn addTarget:self action:@selector(logoutTapped) forControlEvents:UIControlEventTouchUpInside]; |
|||
[contentView addSubview:logoutBtn]; |
|||
|
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[logoutBtn.topAnchor constraintEqualToAnchor:self.lastSettingItem.bottomAnchor constant:20], |
|||
[logoutBtn.centerXAnchor constraintEqualToAnchor:contentView.centerXAnchor], |
|||
[logoutBtn.widthAnchor constraintEqualToConstant:120], |
|||
[logoutBtn.heightAnchor constraintEqualToConstant:40], |
|||
|
|||
[contentView.bottomAnchor constraintEqualToAnchor:logoutBtn.bottomAnchor constant:20] |
|||
]]; |
|||
} |
|||
|
|||
#pragma mark - 退出登录方法 |
|||
- (void)logoutTapped { |
|||
ViewController *loginVC = [[ViewController alloc] init]; |
|||
loginVC.hidesBottomBarWhenPushed = YES; // 隐藏TabBar |
|||
[self.navigationController pushViewController:loginVC animated:YES]; |
|||
} |
|||
|
|||
#pragma mark - 底部TabBar |
|||
- (void)setupTabBar { |
|||
NSArray *tabItems = @[ |
|||
@{@"title":@"首页", @"icon":@"house.fill", @"selected":@NO}, |
|||
@{@"title":@"行情", @"icon":@"chart.line.uptrend.xyaxis", @"selected":@NO}, |
|||
@{@"title":@"自选", @"icon":@"plus", @"selected":@NO}, |
|||
@{@"title":@"我的", @"icon":@"person", @"selected":@YES} |
|||
]; |
|||
self.tabBar = [[CommonTabBar alloc] initWithTabItems:tabItems]; |
|||
self.tabBar.delegate = self; |
|||
self.tabBar.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:self.tabBar]; |
|||
|
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[self.tabBar.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor], |
|||
[self.tabBar.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], |
|||
[self.tabBar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], |
|||
[self.tabBar.heightAnchor constraintEqualToConstant:49] |
|||
]]; |
|||
} |
|||
|
|||
#pragma mark - 工具方法 |
|||
- (UIButton *)createInfoButtonWithConfig:(NSDictionary *)config { |
|||
UIButtonConfiguration *btnConfig = [UIButtonConfiguration plainButtonConfiguration]; |
|||
|
|||
NSString *iconName = config[@"icon"]; |
|||
UIImage *iconImage = [UIImage imageNamed:iconName]; |
|||
|
|||
if (!iconImage) { |
|||
UIImageSymbolConfiguration *symbolConfig = [UIImageSymbolConfiguration configurationWithPointSize:24 weight:UIFontWeightRegular]; |
|||
iconImage = [UIImage systemImageNamed:@"dollarsign.circle" withConfiguration:symbolConfig]; |
|||
} else { |
|||
UIGraphicsBeginImageContextWithOptions(CGSizeMake(40, 40), NO, 0); |
|||
[iconImage drawInRect:CGRectMake(0, 0, 40, 40)]; |
|||
iconImage = UIGraphicsGetImageFromCurrentImageContext(); |
|||
UIGraphicsEndImageContext(); |
|||
} |
|||
|
|||
btnConfig.image = iconImage; |
|||
btnConfig.imagePlacement = NSDirectionalRectEdgeTop; |
|||
btnConfig.imagePadding = 15; |
|||
|
|||
// 富文本吧 |
|||
NSAttributedString *titleAttr = [[NSAttributedString alloc] initWithString:config[@"text"] attributes:@{ |
|||
NSFontAttributeName: [UIFont systemFontOfSize:14], |
|||
NSForegroundColorAttributeName: [UIColor whiteColor] |
|||
}]; |
|||
btnConfig.attributedTitle = titleAttr; |
|||
|
|||
btnConfig.baseBackgroundColor = [UIColor clearColor]; |
|||
btnConfig.baseForegroundColor = [UIColor whiteColor]; |
|||
|
|||
UIButton *btn = [UIButton buttonWithConfiguration:btnConfig primaryAction:nil]; |
|||
btn.translatesAutoresizingMaskIntoConstraints = NO; |
|||
|
|||
[btn addTarget:self action:@selector(infoButtonTapped:) forControlEvents:UIControlEventTouchUpInside]; |
|||
|
|||
return btn; |
|||
} |
|||
|
|||
- (void)infoButtonTapped:(UIButton *)sender { |
|||
if (sender.tag == 100) { |
|||
NSLog(@"金币按钮被点击"); |
|||
} else if (sender.tag == 101) { |
|||
NSLog(@"钻石按钮被点击"); |
|||
} |
|||
} |
|||
|
|||
- (UIView *)createVerticalDivider { |
|||
UIView *divider = [[UIView alloc] init]; |
|||
divider.backgroundColor = [UIColor colorWithRed:0.3 green:0.3 blue:0.3 alpha:1]; |
|||
divider.translatesAutoresizingMaskIntoConstraints = NO; |
|||
return divider; |
|||
} |
|||
|
|||
- (UIImageView *)createImageViewWithImage:(NSString *)imageName contentMode:(UIViewContentMode)mode cornerRadius:(CGFloat)radius { |
|||
UIImageView *uiImageView = [[UIImageView alloc] init]; |
|||
uiImageView.image = [UIImage imageNamed:imageName]; |
|||
uiImageView.contentMode = mode; |
|||
uiImageView.layer.cornerRadius = radius; |
|||
uiImageView.clipsToBounds = YES; |
|||
uiImageView.translatesAutoresizingMaskIntoConstraints = NO; |
|||
return uiImageView; |
|||
} |
|||
|
|||
- (UILabel *)createLabelWithText:(NSString *)text fontSize:(CGFloat)size textColor:(UIColor *)color { |
|||
UILabel *label = [[UILabel alloc] init]; |
|||
label.text = text; |
|||
label.font = [UIFont systemFontOfSize:size weight:UIFontWeightMedium]; |
|||
label.textColor = color; |
|||
label.translatesAutoresizingMaskIntoConstraints = NO; |
|||
return label; |
|||
} |
|||
|
|||
- (UIButton *)createButtonWithTitle:(NSString *)title bgColor:(UIColor *)bgColor cornerRadius:(CGFloat)radius { |
|||
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem]; |
|||
[btn setTitle:title forState:UIControlStateNormal]; |
|||
[btn setTitleColor:[UIColor lightGrayColor] forState:UIControlStateNormal]; |
|||
btn.backgroundColor = bgColor; |
|||
btn.layer.cornerRadius = radius; |
|||
btn.translatesAutoresizingMaskIntoConstraints = NO; |
|||
return btn; |
|||
} |
|||
|
|||
- (UIView *)createDividerWithLeading:(CGFloat)leading { |
|||
UIView *divider = [[UIView alloc] init]; |
|||
divider.backgroundColor = [UIColor colorWithRed:0.3 green:0.3 blue:0.3 alpha:1]; |
|||
divider.translatesAutoresizingMaskIntoConstraints = NO; |
|||
return divider; |
|||
} |
|||
|
|||
- (UIView *)createCommonRowWithText:(NSString *)text { |
|||
UIView *rowView = [[UIView alloc] init]; |
|||
rowView.translatesAutoresizingMaskIntoConstraints = NO; |
|||
rowView.backgroundColor = [UIColor clearColor]; |
|||
|
|||
UIImageView *logoView = [self createImageViewWithImage:@"hqz" |
|||
contentMode:UIViewContentModeScaleAspectFit |
|||
cornerRadius:0]; |
|||
logoView.tintColor = [UIColor blueColor]; |
|||
[rowView addSubview:logoView]; |
|||
|
|||
UILabel *textLabel = [self createLabelWithText:text |
|||
fontSize:16 |
|||
textColor:[UIColor whiteColor]]; |
|||
[rowView addSubview:textLabel]; |
|||
|
|||
UIButton *arrowBtn = [UIButton buttonWithType:UIButtonTypeSystem]; |
|||
[arrowBtn setImage:[UIImage systemImageNamed:@"chevron.right"] forState:UIControlStateNormal]; |
|||
[arrowBtn setTintColor:[UIColor lightGrayColor]]; |
|||
arrowBtn.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[rowView addSubview:arrowBtn]; |
|||
|
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
// logo左侧固定 |
|||
[logoView.centerYAnchor constraintEqualToAnchor:rowView.centerYAnchor], |
|||
[logoView.leadingAnchor constraintEqualToAnchor:rowView.leadingAnchor constant:20], |
|||
[logoView.widthAnchor constraintEqualToConstant:24], |
|||
[logoView.heightAnchor constraintEqualToConstant:24], |
|||
|
|||
// 文字 logo右侧 |
|||
[textLabel.centerYAnchor constraintEqualToAnchor:logoView.centerYAnchor], |
|||
[textLabel.leadingAnchor constraintEqualToAnchor:logoView.trailingAnchor constant:15], |
|||
|
|||
// 箭头 右侧固定 |
|||
[arrowBtn.centerYAnchor constraintEqualToAnchor:logoView.centerYAnchor], |
|||
[arrowBtn.trailingAnchor constraintEqualToAnchor:rowView.trailingAnchor constant:-20] |
|||
]]; |
|||
|
|||
return rowView; |
|||
} |
|||
|
|||
#pragma mark - TabBar |
|||
- (void) pushHome { |
|||
HomeViewController *homeViewController = [[HomeViewController alloc] init]; |
|||
[self.navigationController pushViewController:homeViewController animated:YES]; |
|||
} |
|||
|
|||
- (void) pushQuotation { |
|||
QuotationViewController *quotationViewController = [[QuotationViewController alloc] init]; |
|||
[self.navigationController pushViewController:quotationViewController animated:YES]; |
|||
} |
|||
|
|||
- (void)tabBarDidSelectIndex:(NSInteger)index { |
|||
if (index == 3) { |
|||
|
|||
} else if (index == 0) { |
|||
[self pushHome]; |
|||
} else if (index == 1) { |
|||
[self pushQuotation]; |
|||
} else if (index == 2) { |
|||
// 自选 |
|||
} |
|||
} |
|||
|
|||
@end |
|||
@ -0,0 +1,16 @@ |
|||
// |
|||
// QuotationViewController.h |
|||
// HC |
|||
// |
|||
// Created by huilinLi on 2025/11/26. |
|||
// |
|||
|
|||
#import <UIKit/UIKit.h> |
|||
#import "MLXYViewController.h" |
|||
|
|||
NS_ASSUME_NONNULL_BEGIN |
|||
|
|||
@interface QuotationViewController : UIViewController |
|||
@end |
|||
|
|||
NS_ASSUME_NONNULL_END |
|||
@ -0,0 +1,258 @@ |
|||
// |
|||
// QuotationViewController.m |
|||
// HC |
|||
// |
|||
// Created by huilinLi on 2025/11/26. |
|||
// |
|||
|
|||
#import "QuotationViewController.h" |
|||
#import "CountryModel.h" |
|||
#import "MLXYViewController.h" // 马来西亚 |
|||
#import "CNViewController.h" // 中国 |
|||
#import "CommonTabBar.h" |
|||
#import "HomeViewController.h" |
|||
#import "MyViewController.h" |
|||
|
|||
@interface QuotationViewController () <UICollectionViewDelegate, UICollectionViewDataSource> |
|||
@property (nonatomic, strong) CommonTabBar *commonTabBar; |
|||
@property (nonatomic, strong) NSArray<CountryModel *> *countries; // 国家列表 |
|||
@property (nonatomic, strong) UIViewController *currentChildVC; // 当前显示的子控制器 |
|||
@property (nonatomic, strong) UICollectionView *countryTabBar; // 国家选择标签栏 |
|||
@property (nonatomic, strong) UIView *contentContainer; // 子控制器容器 |
|||
@property (nonatomic, assign) NSInteger selectedIndex; // 当前选中的国家索引 |
|||
|
|||
// 顶部 |
|||
@property (nonatomic, strong) UIImageView *logoImage; // logo |
|||
@property (nonatomic, strong) UITextField *searchField; // 搜索框 |
|||
@property (nonatomic, strong) UIImageView *flagIcon; // 国旗 |
|||
@end |
|||
|
|||
@implementation QuotationViewController |
|||
|
|||
- (void)viewDidLoad { |
|||
[super viewDidLoad]; |
|||
self.view.backgroundColor = [UIColor blackColor]; |
|||
|
|||
[self initCountries]; |
|||
[self setupSubviews]; |
|||
[self setupConstraints]; |
|||
|
|||
// 默认选中第一个 |
|||
self.selectedIndex = 0; |
|||
[self switchToCountryAtIndex:self.selectedIndex]; |
|||
} |
|||
|
|||
#pragma mark - 初始化国家数据 |
|||
- (void)initCountries { |
|||
self.countries = @[ |
|||
[CountryModel modelWithCode:@"MY" |
|||
name:@"马来西亚" |
|||
vcClassName:NSStringFromClass([MLXYViewController class])], |
|||
[CountryModel modelWithCode:@"CN" |
|||
name:@"中国" |
|||
vcClassName:NSStringFromClass([CNViewController class])] |
|||
]; |
|||
} |
|||
|
|||
#pragma mark - 创建子视图 |
|||
- (void)setupSubviews { |
|||
self.logoImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"logo"]]; |
|||
self.logoImage.contentMode = UIViewContentModeScaleAspectFit; |
|||
self.logoImage.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:self.logoImage]; |
|||
|
|||
self.searchField = [[UITextField alloc] init]; |
|||
self.searchField.placeholder = @"股票名称/代码"; |
|||
NSAttributedString *placeholder = [[NSAttributedString alloc] initWithString:@"股票名称/代码" attributes:@{ |
|||
NSForegroundColorAttributeName: [UIColor whiteColor] |
|||
}]; |
|||
self.searchField.attributedPlaceholder = placeholder; |
|||
self.searchField.textColor = [UIColor whiteColor]; |
|||
self.searchField.backgroundColor = [UIColor colorWithRed:0.2 green:0.2 blue:0.2 alpha:1]; |
|||
self.searchField.layer.cornerRadius = 15; |
|||
self.searchField.leftView = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:@"magnifyingglass"]]; |
|||
self.searchField.leftViewMode = UITextFieldViewModeAlways; |
|||
self.searchField.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:self.searchField]; |
|||
|
|||
self.flagIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"logo"]]; |
|||
self.flagIcon.contentMode = UIViewContentModeScaleAspectFit; |
|||
self.flagIcon.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:self.flagIcon]; |
|||
|
|||
UICollectionViewFlowLayout *tabLayout = [[UICollectionViewFlowLayout alloc] init]; |
|||
tabLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;// 横向滚动 |
|||
tabLayout.itemSize = CGSizeMake(100, 40); // 每个标签宽100,高40 |
|||
tabLayout.minimumInteritemSpacing = 0; |
|||
|
|||
self.countryTabBar = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:tabLayout]; |
|||
self.countryTabBar.backgroundColor = [UIColor blackColor]; |
|||
self.countryTabBar.delegate = self; |
|||
self.countryTabBar.dataSource = self; |
|||
[self.countryTabBar registerClass:[UICollectionViewCell class]// 单元格复用类 |
|||
forCellWithReuseIdentifier:@"CountryTabCell"]; |
|||
self.countryTabBar.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:self.countryTabBar]; |
|||
|
|||
// 5. 内容容器,这个承接子视图 |
|||
self.contentContainer = [[UIView alloc] init]; |
|||
self.contentContainer.backgroundColor = [UIColor blackColor]; |
|||
self.contentContainer.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:self.contentContainer]; |
|||
|
|||
NSArray *tabItems = @[ |
|||
@{@"title":@"首页", @"icon":@"house.fill", @"selected":@NO}, |
|||
@{@"title":@"行情", @"icon":@"chart.line.uptrend.xyaxis", @"selected":@YES}, |
|||
@{@"title":@"自选", @"icon":@"plus", @"selected":@NO}, |
|||
@{@"title":@"我的", @"icon":@"person", @"selected":@NO} |
|||
]; |
|||
self.commonTabBar = [[CommonTabBar alloc] initWithTabItems:tabItems]; |
|||
self.commonTabBar.delegate = self; |
|||
self.commonTabBar.translatesAutoresizingMaskIntoConstraints = NO; |
|||
[self.view addSubview:self.commonTabBar]; |
|||
} |
|||
|
|||
#pragma mark - 布局约束 |
|||
- (void)setupConstraints { |
|||
// Logo |
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[self.logoImage.centerYAnchor constraintEqualToAnchor:self.searchField.centerYAnchor], |
|||
[self.logoImage.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor constant:15], |
|||
[self.logoImage.widthAnchor constraintEqualToConstant:40], |
|||
[self.logoImage.heightAnchor constraintEqualToConstant:40] |
|||
]]; |
|||
|
|||
// 搜索框 |
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[self.searchField.topAnchor constraintEqualToAnchor:self.view.topAnchor constant:50], |
|||
[self.searchField.leadingAnchor constraintEqualToAnchor:self.logoImage.trailingAnchor constant:10], |
|||
[self.searchField.trailingAnchor constraintEqualToAnchor:self.flagIcon.leadingAnchor constant:-10], |
|||
[self.searchField.heightAnchor constraintEqualToConstant:30] |
|||
]]; |
|||
|
|||
// 国旗 |
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[self.flagIcon.centerYAnchor constraintEqualToAnchor:self.searchField.centerYAnchor], |
|||
[self.flagIcon.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor constant:-15], |
|||
[self.flagIcon.widthAnchor constraintEqualToConstant:40], |
|||
[self.flagIcon.heightAnchor constraintEqualToConstant:40] |
|||
]]; |
|||
|
|||
// 国家 |
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[self.countryTabBar.topAnchor constraintEqualToAnchor:self.searchField.bottomAnchor constant:15], |
|||
[self.countryTabBar.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], |
|||
[self.countryTabBar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], |
|||
[self.countryTabBar.heightAnchor constraintEqualToConstant:40] |
|||
]]; |
|||
|
|||
// 子视图容器 |
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[self.contentContainer.topAnchor constraintEqualToAnchor:self.countryTabBar.bottomAnchor], |
|||
[self.contentContainer.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], |
|||
[self.contentContainer.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], |
|||
[self.contentContainer.bottomAnchor constraintEqualToAnchor:self.commonTabBar.topAnchor] |
|||
]]; |
|||
|
|||
// 底部TabBar |
|||
[NSLayoutConstraint activateConstraints:@[ |
|||
[self.commonTabBar.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor], |
|||
[self.commonTabBar.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], |
|||
[self.commonTabBar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor] |
|||
]]; |
|||
} |
|||
|
|||
#pragma mark - 切换子控制器 |
|||
- (void)switchToCountryAtIndex:(NSInteger)index { |
|||
// 先移除 |
|||
if (self.currentChildVC) { |
|||
[self.currentChildVC willMoveToParentViewController:nil]; |
|||
[self.currentChildVC.view removeFromSuperview]; |
|||
[self.currentChildVC removeFromParentViewController]; |
|||
self.currentChildVC = nil; |
|||
} |
|||
|
|||
// 创建新的 |
|||
CountryModel *selectedCountry = self.countries[index]; |
|||
Class childVCClass = NSClassFromString(selectedCountry.vcClassName);// 字符串转Class???? |
|||
UIViewController *childVC = [[childVCClass alloc] init]; |
|||
|
|||
// 添加 |
|||
[self addChildViewController:childVC]; |
|||
childVC.view.frame = self.contentContainer.bounds;// 适配容器 |
|||
childVC.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;// 自适应容器大小 |
|||
[self.contentContainer addSubview:childVC.view]; |
|||
[childVC didMoveToParentViewController:self]; |
|||
|
|||
self.currentChildVC = childVC; |
|||
} |
|||
|
|||
#pragma mark - 国家数据源 |
|||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { |
|||
return self.countries.count; |
|||
} |
|||
|
|||
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { |
|||
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CountryTabCell" forIndexPath:indexPath]; |
|||
cell.backgroundColor = [UIColor blackColor]; |
|||
|
|||
// 国家名称 |
|||
UILabel *nameLabel = [cell viewWithTag:100]; |
|||
if (!nameLabel) { |
|||
nameLabel = [[UILabel alloc] init]; |
|||
nameLabel.tag = 100; |
|||
nameLabel.textColor = [UIColor whiteColor]; |
|||
nameLabel.font = [UIFont systemFontOfSize:15]; |
|||
nameLabel.textAlignment = NSTextAlignmentCenter; |
|||
[cell.contentView addSubview:nameLabel]; |
|||
nameLabel.frame = cell.contentView.bounds;// 撑满单元格 |
|||
} |
|||
nameLabel.text = self.countries[indexPath.item].name; |
|||
|
|||
// 选中下划线 |
|||
UIView *selectedLine = [cell viewWithTag:101]; |
|||
if (!selectedLine) { |
|||
selectedLine = [[UIView alloc] init]; |
|||
selectedLine.tag = 101; |
|||
selectedLine.backgroundColor = [UIColor blueColor]; |
|||
[cell.contentView addSubview:selectedLine]; |
|||
selectedLine.frame = CGRectMake(30, cell.contentView.bounds.size.height - 7, 40, 4); |
|||
} |
|||
selectedLine.hidden = !(indexPath.item == self.selectedIndex); |
|||
|
|||
return cell; |
|||
} |
|||
|
|||
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath { |
|||
self.selectedIndex = indexPath.item; |
|||
[self.countryTabBar reloadData]; // 刷新标签选中状态 |
|||
[self switchToCountryAtIndex:indexPath.item]; // 切换到对应国家页面 |
|||
} |
|||
|
|||
#pragma mark - 底部跳转方法 |
|||
- (void)tabBarDidSelectIndex:(NSInteger)index { |
|||
switch (index) { |
|||
case 0: |
|||
[self pushHome]; |
|||
break; |
|||
case 1: |
|||
break; |
|||
case 2: |
|||
break; |
|||
case 3: |
|||
[self pushMine]; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
- (void) pushMine { |
|||
MyViewController *myViewController = [[MyViewController alloc] init]; |
|||
[self.navigationController pushViewController:myViewController animated:YES]; |
|||
} |
|||
|
|||
- (void) pushHome { |
|||
HomeViewController *myViewController = [[HomeViewController alloc] init]; |
|||
[self.navigationController pushViewController:myViewController animated:YES]; |
|||
} |
|||
|
|||
@end |
|||
@ -0,0 +1,36 @@ |
|||
// |
|||
// StockKLineModel.h |
|||
// HomilyChartFake |
|||
// |
|||
// Created by 洪锡林 on 2025/11/28. |
|||
// |
|||
|
|||
|
|||
#import <Foundation/Foundation.h> |
|||
|
|||
|
|||
NS_ASSUME_NONNULL_BEGIN |
|||
|
|||
|
|||
@interface StockKLineModel : NSObject |
|||
|
|||
|
|||
@property (nonatomic, copy) NSString *date; // 时间,如 "2025-11-27" |
|||
@property (nonatomic, assign) CGFloat open; // 开盘价 |
|||
@property (nonatomic, assign) CGFloat close;// 收盘价 |
|||
@property (nonatomic, assign) CGFloat high; // 最高价 |
|||
@property (nonatomic, assign) CGFloat low; // 最低价 |
|||
@property (nonatomic, assign) CGFloat volume; // 成交量 |
|||
|
|||
// 预留给MA均线(后面章节会用到) |
|||
@property (nonatomic, assign) CGFloat ma5; |
|||
@property (nonatomic, assign) CGFloat ma10; |
|||
@property (nonatomic, assign) CGFloat ma20; |
|||
|
|||
// 辅助方法:判断是否是阳线(涨) |
|||
- (BOOL)isUp; |
|||
|
|||
@end |
|||
|
|||
|
|||
NS_ASSUME_NONNULL_END |
|||
@ -0,0 +1,21 @@ |
|||
// |
|||
// StockKLineModel.m |
|||
// HomilyChartFake |
|||
// |
|||
// Created by 洪锡林 on 2025/11/28. |
|||
// |
|||
|
|||
|
|||
#import "StockKLineModel.h" |
|||
|
|||
|
|||
@implementation StockKLineModel |
|||
|
|||
|
|||
- (BOOL)isUp { |
|||
// 在A股,收盘 >= 开盘 认为是阳线(红色),这里包含平盘情况 |
|||
return self.close >= self.open; |
|||
} |
|||
|
|||
|
|||
@end |
|||