1. 이전 포스팅 확인하기
https://growingsaja.tistory.com/898
2. CRTSystem 파일에서 현재 시간 가져오는 메소드 수정
이전 코드와 크게 달라진 부분은 없습니다.
// vim CRTSystem.h
@interface CRTSystem : NSObject
-(NSString *)NowDateTimeUTC;
-(NSString *)NowDateTimeKST;
@end
// vim CRTSystem.m
#import <Foundation/Foundation.h>
#import "CRTSystem.h"
@implementation CRTSystem
NSString *normalFormatDateTime = @"yyyy-MM-dd (E) kk:mm:ss";
-(NSString *)NowDateTimeUTC {
// [현재 UTC 날짜 얻어 오기]
NSDate *nowUTCDateRaw = [NSDate date];
// [날짜 형식 포맷 + UTC 세팅 :: 24시간 형태]
NSDateFormatter *dateFormatterUTC = [[NSDateFormatter alloc] init];
[dateFormatterUTC setDateFormat:normalFormatDateTime];
NSTimeZone *utcTimeZone = [NSTimeZone timeZoneWithName:@"UTC"];
[dateFormatterUTC setTimeZone:utcTimeZone];
// [현재 UTC 일시 출력]
NSString *nowUTCString = @"";
nowUTCString = [dateFormatterUTC stringFromDate:nowUTCDateRaw];
return nowUTCString;
}
-(NSString *)NowDateTimeKST {
// [현재 UTC 날짜 얻어 오기]
NSDate *nowUTCDateRaw = [NSDate date];
// [날짜 형식 포맷 + KST 세팅 :: 24시간 형태
NSDateFormatter *dateFormatterKST = [[NSDateFormatter alloc] init];
[dateFormatterKST setDateFormat:normalFormatDateTime];
NSTimeZone *kstTimeZone = [NSTimeZone timeZoneWithName:@"Asia/Seoul"];
[dateFormatterKST setTimeZone:kstTimeZone];
// [현재 KST 일시 출력]
NSString *nowKSTString = @"";
nowKSTString = [dateFormatterKST stringFromDate:nowUTCDateRaw];
return nowKSTString;
}
@end
3. 태극기, 지구본 이모티콘 확보 (기타 필요시 활용)
- Korean Flag
🇰🇷
- USA Flag
🇺🇸
- Global (Earth)
🗺️ 🌐 🌍 🌏 🌎
- 기타 돈 관련 이모티콘
💵 💲 💰 🏦 💸 💱
💴 💶 💷 🧧 🪙 🏧
- 시간 관련 이모티콘
⏳ ⏱️ 🕰️ ⌚ ⏰ ⏲️ 🕜 🔃
- 알림, 주의, 오류, 소리 이모티콘
⚠️ 💣 🔴 🚨 🚧 ❕ ❗
📴 🔕 🔇 🔈 🔉 🔊 📢
- 정상 확인 이모티콘
🆗 ☑️ ✔️ 👌🏻
4. FavoriteAssetTeackerListVC 파일 수정 - 주요 부분만 발췌
// ****************************** [Start] 최상단에 최근 업데이트 시간 띄우기위한 공간 설정 ****************************** //
UIView *topInfoTab = [[UIView alloc] initWithFrame:CGRectMake(cardViewXPosition, cardViewTopStartMargin - (cardViewSpacing + cardViewHeight), cardViewWidth, cardViewHeight)];
// 국기 너비 길이 (좌우 길이) 설정
CGFloat flagWidth = 24.0;
/* #################### 글로벌 지구 이모티콘 및 시간 설정 #################### */
UILabel *earthLabel = [[UILabel alloc] initWithFrame:CGRectMake(basicMarginInCard, basicMarginInCard, flagWidth, 20)];
earthLabel.text = @"🌍";
// 표준 시간 = 그리니치 표준시 : 더블린, 에든버러, 리스본, 런던, 카사블랑카, 몬로비아
UILabel *liveGMTLabel = [[UILabel alloc] initWithFrame:CGRectMake(basicMarginInCard + flagWidth, basicMarginInCard, cardViewWidth / 2, 20)];
// 레이블의 텍스트를 설정합니다. 여기에서는 sortedArray 배열의 i 번째 요소를 사용합니다.
liveGMTLabel.text = [[CRTSystem alloc] init].NowDateTimeUTC;
liveGMTLabel.font = [UIFont fontWithName:@"Pretendard-Regular" size:defaultFontSize];
/* #################### 한국 이모티콘 및 시간 설정 #################### */
// 태극기
UILabel *koreanFlagLabel = [[UILabel alloc] initWithFrame:CGRectMake(basicMarginInCard, basicMarginInCard + cardViewHeight / 2, flagWidth, 20)];
koreanFlagLabel.text = @"🇰🇷";
// 한국 시간
UILabel *liveKSTLabel = [[UILabel alloc] initWithFrame:CGRectMake(basicMarginInCard + flagWidth, basicMarginInCard + cardViewHeight / 2, cardViewWidth / 2, 20)];
// 레이블의 텍스트를 설정합니다. 여기에서는 sortedArray 배열의 i 번째 요소를 사용합니다.
liveKSTLabel.text = [[CRTSystem alloc] init].NowDateTimeKST;
liveKSTLabel.font = [UIFont fontWithName:@"Pretendard-Regular" size:defaultFontSize];
/* #################### cardView를 self.scrollView에 추가 #################### */
// global 적용
[topInfoTab addSubview:earthLabel];
[topInfoTab addSubview:liveGMTLabel];
// korea 적용
[topInfoTab addSubview:koreanFlagLabel];
[topInfoTab addSubview:liveKSTLabel];
[self.scrollView addSubview:topInfoTab];
5. FavoriteAssetTeackerListVC 파일 수정 - 전체 발췌
// vim Controller/FavoriteAssetTeackerListVC.h
#import <UIKit/UIKit.h>
// FavoriteAssetTeackerListVC라는 이름의 뷰 컨트롤러 클래스를 선언합니다.
@interface FavoriteAssetTeackerListVC : UIViewController
@property (readwrite, strong, nonatomic) UIScrollView *scrollView;
@property (readwrite, strong, nonatomic) UIStackView *stackView;
@end
// vim Controller/FavoriteAssetTeackerListVC.m
#import <Foundation/Foundation.h>
#import "FavoriteAssetTeackerListVC.h"
// api 통신 용도
#import "CRTConnect.h"
// default.json 파일 읽기 용도
#import "CRTJSONReader.h"
// 현재 시간 가져오는 용도
#import "CRTSystem.h"
@implementation FavoriteAssetTeackerListVC {
// json에서 가져온 favoriteList 데이터 각각의 마지막에 append해서 price 기재
int priceIndexOfFavoriteGoods;
// json에서 가져온 favoriteList raw 데이터
NSMutableArray *favoriteListFullInfo;
}
- (void)viewDidLoad {
[super viewDidLoad];
// 스크롤 뷰 생성 및 초기화
self.scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
self.scrollView.backgroundColor = [UIColor clearColor];
[self.view addSubview:self.scrollView];
// 스택 뷰 생성 및 초기화
self.stackView = [[UIStackView alloc] initWithFrame:self.scrollView.bounds];
self.stackView.axis = UILayoutConstraintAxisVertical;
self.stackView.distribution = UIStackViewDistributionEqualSpacing;
self.stackView.alignment = UIStackViewAlignmentFill;
self.stackView.spacing = 12;
[self.scrollView addSubview:self.stackView];
// default.json의 favoriteList 데이터 가져오기
[self loadFavoriteList];
// NSTimer 생성 및 메서드 호출 설정 - 매 특정시간마다 호출
[NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:@selector(updateDataAndView)
userInfo:nil
repeats:YES];
}
- (void)updateDataAndView {
// 데이터 가져오기 및 뷰 업데이트 코드
// ****************************** [Start] Bybit 데이터 가져오기 ****************************** //
CRTConnect* tryApiCall = [[CRTConnect alloc] init];
NSString *apiURL = @"https://api.bybit.com/spot/quote/v1/ticker/price";
[tryApiCall fetchDataFromAPI:apiURL withCompletionHandler:^(NSDictionary *jsonResponse, NSError *error) {
if (error) {
NSLog(@"Error: %@", error.localizedDescription);
} else {
// 여기에서 jsonResponse를 가공 한 후 앱에서 사용하실 수 있습니다.
// result 안의 value만 추출
NSArray* resultOfApi = jsonResponse[@"result"];
// Bybit Api 결과를 Array에서 깔끔한 Dict로 가공하기 위한 데이터 선언
NSMutableDictionary *allBybitDictTmp = [@{} mutableCopy];
// api로 받은 데이터 깔끔한 dictionary로 가공하기
for (int i=0; i<resultOfApi.count; i++) {
NSString *keyTmp = resultOfApi[i][@"symbol"];
NSString *valueTmp = resultOfApi[i][@"price"];
allBybitDictTmp[keyTmp] = valueTmp;
}
// favorite List에 가격 append하기
NSString *indexKey = [[NSString alloc] init];
for (int i=0; i<self->favoriteListFullInfo.count; i++) {
indexKey = self->favoriteListFullInfo[i][4];
// 추후 json에는 있는데, bybit api에는 없는 경우에 대한 오류 해결 if문 추가 필요
self->favoriteListFullInfo[i][self->priceIndexOfFavoriteGoods] = allBybitDictTmp[indexKey];
}
// 메인 스레드에서만 UI 업데이트 수행
dispatch_async(dispatch_get_main_queue(), ^{
[self updateView];
});
}
}];
// ****************************** [End] Bybit 데이터 가져오기 ****************************** //
}
// default.json 파일의 favoriteList 데이터 읽기
-(void) loadFavoriteList {
CRTJSONReader *tryReadingDefaultJsonFile = [[CRTJSONReader alloc] init];
NSDictionary *defaultData = [tryReadingDefaultJsonFile loadJSONFromFile:@"default"];
favoriteListFullInfo = defaultData[@"favoriteList"];
int checkDefaultJsonFile = 0;
for (int i=0; i<favoriteListFullInfo.count-1; i++) {
if ([favoriteListFullInfo[i] count] == [favoriteListFullInfo[i+1] count]) {
checkDefaultJsonFile += 1;
}
}
if (checkDefaultJsonFile == [favoriteListFullInfo count]-1) {
// default.json파일의 favoriteList 안에 있는 Array들 중 길이가 모두 같으면
priceIndexOfFavoriteGoods = (int)[favoriteListFullInfo[0] count];
} else {
// default.json파일의 favoriteList 안에 있는 Array들 중 길이가 다른 것이 1개라도 있으면 WARN 출력 및 앱 dead
priceIndexOfFavoriteGoods = 9999; // for error
NSLog(@"****************************************************");
NSLog(@"[WARN] Check File : default.json - favoriteList");
NSLog(@"****************************************************");
}
}
-(void) updateView {
// ****************************** [Start] 뷰 그리기 ****************************** //
// 기존 뷰 삭제
for (UIView *subview in self.scrollView.subviews) {
[subview removeFromSuperview];
}
// viewDidLoad 메서드에서 스크롤 뷰를 초기화하고 설정합니다.
self.scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
self.scrollView.backgroundColor = [UIColor clearColor];
[self.view addSubview:self.scrollView];
//카드뷰 배치에 필요한 변수를 설정합니다.
// 카드 목록 나열될 공간 세팅
// ****************************** //
// 목록 상단 공백 margin 설정
CGFloat cardViewTopStartMargin = 10.0;
// 카드 목록의 좌우 공백 각각의 margin
CGFloat horizontalMargin = 2;
// 카드와 카드 사이의 공백
CGFloat cardViewSpacing = 4.0;
// 카드뷰 목록 노출 시작 x축 위치 자동 설정
CGFloat cardViewXPosition = horizontalMargin;
// ****************************** //
// 카드 자체에 대한 세팅
// 카드 높이 길이 (상하 길이) 설정
CGFloat cardViewHeight = 60.0;
// 카드 좌우 길이 phone size 참조하여 자동 조정
CGFloat cardViewWidth = [UIScreen mainScreen].bounds.size.width - horizontalMargin * 2;
// 카드뷰 안에 내용 들어가는 공간까지의 margin
CGFloat basicMarginInCard = 10.0;
CGFloat defaultFontSize = 16.0;
// ****************************** //
// ****************************** [Start] 최상단에 최근 업데이트 시간 띄우기위한 공간 설정 ****************************** //
UIView *topInfoTab = [[UIView alloc] initWithFrame:CGRectMake(cardViewXPosition, cardViewTopStartMargin - (cardViewSpacing + cardViewHeight), cardViewWidth, cardViewHeight)];
// 국기 너비 길이 (좌우 길이) 설정
CGFloat flagWidth = 24.0;
/* #################### 글로벌 지구 이모티콘 및 시간 설정 #################### */
UILabel *earthLabel = [[UILabel alloc] initWithFrame:CGRectMake(basicMarginInCard, basicMarginInCard, flagWidth, 20)];
earthLabel.text = @"🌍";
// 표준 시간 = 그리니치 표준시 : 더블린, 에든버러, 리스본, 런던, 카사블랑카, 몬로비아
UILabel *liveGMTLabel = [[UILabel alloc] initWithFrame:CGRectMake(basicMarginInCard + flagWidth, basicMarginInCard, cardViewWidth / 2, 20)];
// 레이블의 텍스트를 설정합니다. 여기에서는 sortedArray 배열의 i 번째 요소를 사용합니다.
liveGMTLabel.text = [[CRTSystem alloc] init].NowDateTimeUTC;
liveGMTLabel.font = [UIFont fontWithName:@"Pretendard-Regular" size:defaultFontSize];
/* #################### 한국 이모티콘 및 시간 설정 #################### */
// 태극기
UILabel *koreanFlagLabel = [[UILabel alloc] initWithFrame:CGRectMake(basicMarginInCard, basicMarginInCard + cardViewHeight / 2, flagWidth, 20)];
koreanFlagLabel.text = @"🇰🇷";
// 한국 시간
UILabel *liveKSTLabel = [[UILabel alloc] initWithFrame:CGRectMake(basicMarginInCard + flagWidth, basicMarginInCard + cardViewHeight / 2, cardViewWidth / 2, 20)];
// 레이블의 텍스트를 설정합니다. 여기에서는 sortedArray 배열의 i 번째 요소를 사용합니다.
liveKSTLabel.text = [[CRTSystem alloc] init].NowDateTimeKST;
liveKSTLabel.font = [UIFont fontWithName:@"Pretendard-Regular" size:defaultFontSize];
/* #################### cardView를 self.scrollView에 추가 #################### */
// global 적용
[topInfoTab addSubview:earthLabel];
[topInfoTab addSubview:liveGMTLabel];
// korea 적용
[topInfoTab addSubview:koreanFlagLabel];
[topInfoTab addSubview:liveKSTLabel];
[self.scrollView addSubview:topInfoTab];
// ****************************** [Start] 카드뷰 목록 쭉 만들기 ****************************** //
for (int i=0; i<favoriteListFullInfo.count; i++) {
UIView *cardView = [[UIView alloc] initWithFrame:CGRectMake(cardViewXPosition, cardViewTopStartMargin + i * (cardViewSpacing + cardViewHeight), cardViewWidth, cardViewHeight)];
// 카드뷰 모서리를 둥글게 설정합니다. 조건 1
cardView.layer.cornerRadius = 8.0;
// cardView의 경계를 기준으로 내용물이 보이는 영역을 제한합니다. masksToBounds를 YES로 설정하면, cardView의 경계 밖에 있는 모든 내용물은 자르고 숨깁니다(클립 됩니다). 즉 뷰의 경계 값을 초과한 부분을 자르기 위해 masksToBounds를 YES로 설정합니다. 반면 masksToBounds가 NO인 경우(기본값)에는 뷰의 경계 밖에 있는 내용물이 그대로 보이게 됩니다.
cardView.layer.masksToBounds = YES;
// UILabel의 텍스트 색상 및 배경색 설정
// 카드뷰 배경색을 설정합니다.
if (UITraitCollection.currentTraitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
// 다크모드인 경우
cardView.backgroundColor = [UIColor darkGrayColor];
[self.view addSubview:cardView];
} else {
// 라이트모드인 경우
cardView.backgroundColor = [UIColor lightGrayColor];
[self.view addSubview:cardView];
}
// UILabel 객체를 생성합니다. 이 레이블은 암호화폐의 이름을 표시할 것입니다.
// 따라서 CGRect를 사용하여 레이블의 위치와 크기를 설정하며, 왼쪽 위 모서리에서 시작합니다.
UILabel *cryptoNameLabel = [[UILabel alloc] initWithFrame:CGRectMake(basicMarginInCard, basicMarginInCard, cardViewWidth / 2 - 20, 20)];
// 레이블의 텍스트를 설정합니다. 여기에서는 sortedArray 배열의 i 번째 요소를 사용합니다.
cryptoNameLabel.text = favoriteListFullInfo[i][4];
cryptoNameLabel.font = [UIFont fontWithName:@"Pretendard-Bold" size:defaultFontSize];
// systemFontOfSize:defaultFontSize
// 생성한 cryptoNameLabel을 cardView의 서브뷰로 추가합니다. 이렇게 함으로써 레이블이 카드 뷰에 표시됩니다.
[cardView addSubview:cryptoNameLabel];
// 암호화폐 가격 레이블을 생성하고 카드뷰에 추가합니다. 조건 3
UILabel *cryptoPriceLabel = [[UILabel alloc] initWithFrame:CGRectMake(cardViewWidth / 3, basicMarginInCard, cardViewWidth / 2 - basicMarginInCard, 20)];
cryptoPriceLabel.text = favoriteListFullInfo[i][priceIndexOfFavoriteGoods];
cryptoPriceLabel.textAlignment = NSTextAlignmentRight;
cryptoPriceLabel.font = [UIFont fontWithName:@"Pretendard-ExtraBold" size:defaultFontSize];
[cardView addSubview:cryptoPriceLabel];
// 거래소 이름 레이블을 생성하고 카드뷰에 추가합니다. 조건 5
UILabel *exchangeNameLabel = [[UILabel alloc] initWithFrame:CGRectMake(basicMarginInCard, cardViewHeight - 25, cardViewWidth - 20, 20)];
exchangeNameLabel.text = favoriteListFullInfo[i][0];
exchangeNameLabel.font = [UIFont fontWithName:@"Pretendard-Regular" size:defaultFontSize];
[cardView addSubview:exchangeNameLabel];
// cardView를 self.scrollView에 추가합니다.
[self.scrollView addSubview:cardView];
}
// ****************************** [End] 카드뷰 목록 쭉 만들기 ****************************** //
// 상하 스크롤 최대치 자동 설정
CGFloat contentHeight = favoriteListFullInfo.count * (cardViewHeight + cardViewSpacing);
self.scrollView.contentSize = CGSizeMake(self.view.bounds.size.width, contentHeight);
}
@end
6. 결과물 예제
7. 이미지 저장을 위한 그룹 구조 (폴더 구성)
Resources/Static/image 안에 coin & exchange 그룹 생성
- 해당 그룹 안에 앞으로 coin, exchange, stock의 각각에 대한 대표 이미지를 넣을 예정
8. exchange 폴더에 bybit logo 이미지 넣고 소스코드 작성 - 핵심 부분
UIImageView *exchangeLogo = [[UIImageView alloc] initWithFrame:CGRectMake(basicMarginInCard, cardViewHeight/2, miniImange, miniImange)];
exchangeLogo.image = [UIImage imageNamed:@"bybit_darkBackGround_exchange.jpeg"];
exchangeLogo.contentMode = UIViewContentModeScaleAspectFit; // 해당 옵션을 사용하여 가로세로 비율 유지 크기입니다.
[cardView addSubview:exchangeLogo];
9. 소스코드 작성 - 전체
디자인 변경이 이루어져, 일부 코드가 변경된 점 참고바랍니다.
// vim Controller/FavoriteAssetTeackerListVC.m
#import <Foundation/Foundation.h>
#import "FavoriteAssetTeackerListVC.h"
// api 통신 용도
#import "CRTConnect.h"
// default.json 파일 읽기 용도
#import "CRTJSONReader.h"
// 현재 시간 가져오는 용도
#import "CRTSystem.h"
@implementation FavoriteAssetTeackerListVC {
// json에서 가져온 favoriteList 데이터 각각의 마지막에 append해서 price 기재
int priceIndexOfFavoriteGoods;
// json에서 가져온 favoriteList raw 데이터
NSMutableArray *favoriteListFullInfo;
}
- (void)viewDidLoad {
[super viewDidLoad];
// 스크롤 뷰 생성 및 초기화
self.scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
self.scrollView.backgroundColor = [UIColor clearColor];
[self.view addSubview:self.scrollView];
// 스택 뷰 생성 및 초기화
self.stackView = [[UIStackView alloc] initWithFrame:self.scrollView.bounds];
self.stackView.axis = UILayoutConstraintAxisVertical;
self.stackView.distribution = UIStackViewDistributionEqualSpacing;
self.stackView.alignment = UIStackViewAlignmentFill;
self.stackView.spacing = 0;
[self.scrollView addSubview:self.stackView];
// default.json의 favoriteList 데이터 가져오기
[self loadFavoriteList];
// NSTimer 생성 및 메서드 호출 설정 - 매 특정시간마다 호출
[NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:@selector(updateDataAndView)
userInfo:nil
repeats:YES];
}
- (void)updateDataAndView {
// 데이터 가져오기 및 뷰 업데이트 코드
// ****************************** [Start] Bybit 데이터 가져오기 ****************************** //
CRTConnect* tryApiCall = [[CRTConnect alloc] init];
NSString *apiURL = @"https://api.bybit.com/spot/quote/v1/ticker/price";
[tryApiCall fetchDataFromAPI:apiURL withCompletionHandler:^(NSDictionary *jsonResponse, NSError *error) {
if (error) {
NSLog(@"Error: %@", error.localizedDescription);
} else {
// 여기에서 jsonResponse를 가공 한 후 앱에서 사용하실 수 있습니다.
// result 안의 value만 추출
NSArray* resultOfApi = jsonResponse[@"result"];
// Bybit Api 결과를 Array에서 깔끔한 Dict로 가공하기 위한 데이터 선언
NSMutableDictionary *allBybitDictTmp = [@{} mutableCopy];
// api로 받은 데이터 깔끔한 dictionary로 가공하기
for (int i=0; i<resultOfApi.count; i++) {
NSString *keyTmp = resultOfApi[i][@"symbol"];
NSString *valueTmp = resultOfApi[i][@"price"];
allBybitDictTmp[keyTmp] = valueTmp;
}
// favorite List에 가격 append하기
NSString *indexKey = [[NSString alloc] init];
for (int i=0; i<self->favoriteListFullInfo.count; i++) {
indexKey = self->favoriteListFullInfo[i][4];
// 추후 json에는 있는데, bybit api에는 없는 경우에 대한 오류 해결 if문 추가 필요
self->favoriteListFullInfo[i][self->priceIndexOfFavoriteGoods] = allBybitDictTmp[indexKey];
}
// 메인 스레드에서만 UI 업데이트 수행
dispatch_async(dispatch_get_main_queue(), ^{
[self updateView];
});
}
}];
// ****************************** [End] Bybit 데이터 가져오기 ****************************** //
}
// default.json 파일의 favoriteList 데이터 읽기
-(void) loadFavoriteList {
CRTJSONReader *tryReadingDefaultJsonFile = [[CRTJSONReader alloc] init];
NSDictionary *defaultData = [tryReadingDefaultJsonFile loadJSONFromFile:@"default"];
favoriteListFullInfo = defaultData[@"favoriteList"];
int checkDefaultJsonFile = 0;
for (int i=0; i<favoriteListFullInfo.count-1; i++) {
if ([favoriteListFullInfo[i] count] == [favoriteListFullInfo[i+1] count]) {
checkDefaultJsonFile += 1;
}
}
if (checkDefaultJsonFile == [favoriteListFullInfo count]-1) {
// default.json파일의 favoriteList 안에 있는 Array들 중 길이가 모두 같으면
priceIndexOfFavoriteGoods = (int)[favoriteListFullInfo[0] count];
} else {
// default.json파일의 favoriteList 안에 있는 Array들 중 길이가 다른 것이 1개라도 있으면 WARN 출력 및 앱 dead
priceIndexOfFavoriteGoods = 9999; // for error
NSLog(@"****************************************************");
NSLog(@"[WARN] Check File : default.json - favoriteList");
NSLog(@"****************************************************");
}
}
-(void) updateView {
// ****************************** [Start] 뷰 그리기 ****************************** //
// 기존 뷰 삭제
for (UIView *subview in self.scrollView.subviews) {
[subview removeFromSuperview];
}
// viewDidLoad 메서드에서 스크롤 뷰를 초기화하고 설정합니다.
self.scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
self.scrollView.backgroundColor = [UIColor clearColor];
[self.view addSubview:self.scrollView];
//카드뷰 배치에 필요한 변수를 설정합니다.
// 카드 목록 나열될 공간 세팅
// ****************************** //
// 목록 상단 공백 margin 설정
CGFloat cardViewTopStartMargin = 10.0;
// 카드 목록의 좌우 공백 각각의 margin
CGFloat horizontalMargin = 2.0;
// 카드와 카드 사이의 공백
CGFloat cardViewSpacing = 0.0;
// 카드뷰 목록 노출 시작 x축 위치 자동 설정
CGFloat cardViewXPosition = horizontalMargin;
// ****************************** //
// 카드 자체에 대한 세팅
// 카드 높이 길이 (상하 길이) 설정
CGFloat cardViewHeight = 44.0;
// 카드 좌우 길이 phone size 참조하여 자동 조정
CGFloat cardViewWidth = [UIScreen mainScreen].bounds.size.width - horizontalMargin * 2;
// 카드뷰 안에 내용 들어가는 공간까지의 margin
CGFloat basicMarginInCard = 4.0;
CGFloat defaultFontSize = 16.0;
// ****************************** //
// ****************************** [Start] 최상단에 최근 업데이트 시간 띄우기위한 공간 설정 ****************************** //
UIView *topInfoTab = [[UIView alloc] initWithFrame:CGRectMake(cardViewXPosition, cardViewTopStartMargin - (cardViewSpacing + cardViewHeight), cardViewWidth, cardViewHeight)];
// 국기 너비 길이 (좌우 길이) 설정
CGFloat miniImange = 18.0;
/* #################### 글로벌 지구 이모티콘 및 시간 설정 #################### */
UILabel *earthLabel = [[UILabel alloc] initWithFrame:CGRectMake(basicMarginInCard, basicMarginInCard, miniImange, 20)];
earthLabel.text = @"🌍";
// 표준 시간 = 그리니치 표준시 : 더블린, 에든버러, 리스본, 런던, 카사블랑카, 몬로비아
UILabel *liveGMTLabel = [[UILabel alloc] initWithFrame:CGRectMake(basicMarginInCard + miniImange, basicMarginInCard, cardViewWidth / 2, 20)];
// 레이블의 텍스트를 설정합니다. 여기에서는 sortedArray 배열의 i 번째 요소를 사용합니다.
liveGMTLabel.text = [[CRTSystem alloc] init].NowDateTimeUTC;
liveGMTLabel.font = [UIFont fontWithName:@"Pretendard-Regular" size:defaultFontSize];
/* #################### 한국 이모티콘 및 시간 설정 #################### */
// 태극기
UILabel *koreanFlagLabel = [[UILabel alloc] initWithFrame:CGRectMake(basicMarginInCard, basicMarginInCard + cardViewHeight / 2, miniImange, 20)];
koreanFlagLabel.text = @"🇰🇷";
// 한국 시간
UILabel *liveKSTLabel = [[UILabel alloc] initWithFrame:CGRectMake(basicMarginInCard + miniImange, basicMarginInCard + cardViewHeight / 2, cardViewWidth / 2, 20)];
// 레이블의 텍스트를 설정합니다. 여기에서는 sortedArray 배열의 i 번째 요소를 사용합니다.
liveKSTLabel.text = [[CRTSystem alloc] init].NowDateTimeKST;
liveKSTLabel.font = [UIFont fontWithName:@"Pretendard-Regular" size:defaultFontSize];
/* #################### cardView를 self.scrollView에 추가 #################### */
// global 적용
[topInfoTab addSubview:earthLabel];
[topInfoTab addSubview:liveGMTLabel];
// korea 적용
[topInfoTab addSubview:koreanFlagLabel];
[topInfoTab addSubview:liveKSTLabel];
[self.scrollView addSubview:topInfoTab];
// ****************************** [Start] 카드뷰 목록 쭉 만들기 ****************************** //
for (int i=0; i<favoriteListFullInfo.count; i++) {
UIView *cardView = [[UIView alloc] initWithFrame:CGRectMake(cardViewXPosition, cardViewTopStartMargin + i * (cardViewSpacing + cardViewHeight), cardViewWidth, cardViewHeight)];
// 카드 테두리 하얀색
cardView.layer.borderColor = [UIColor darkGrayColor].CGColor;
cardView.layer.borderWidth = 1.0;
// 카드뷰 모서리를 둥글게 설정합니다. 조건 1
cardView.layer.cornerRadius = 0.0;
// cardView의 경계를 기준으로 내용물이 보이는 영역을 제한합니다. masksToBounds를 YES로 설정하면, cardView의 경계 밖에 있는 모든 내용물은 자르고 숨깁니다(클립 됩니다). 즉 뷰의 경계 값을 초과한 부분을 자르기 위해 masksToBounds를 YES로 설정합니다. 반면 masksToBounds가 NO인 경우(기본값)에는 뷰의 경계 밖에 있는 내용물이 그대로 보이게 됩니다.
cardView.layer.masksToBounds = YES;
// UILabel의 텍스트 색상 및 배경색 설정
// 카드뷰 배경색을 설정합니다.
if (UITraitCollection.currentTraitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
// 다크모드인 경우
cardView.backgroundColor = [UIColor blackColor];
[self.view addSubview:cardView];
} else {
// 라이트모드인 경우
cardView.backgroundColor = [UIColor whiteColor];
[self.view addSubview:cardView];
}
// UILabel 객체를 생성합니다. 이 레이블은 암호화폐의 이름을 표시할 것입니다.
// 따라서 CGRect를 사용하여 레이블의 위치와 크기를 설정하며, 왼쪽 위 모서리에서 시작합니다.
UILabel *cryptoNameLabel = [[UILabel alloc] initWithFrame:CGRectMake(basicMarginInCard, basicMarginInCard, cardViewWidth / 4, 20)];
// 레이블의 텍스트를 설정합니다. 여기에서는 sortedArray 배열의 i 번째 요소를 사용합니다.
cryptoNameLabel.text = favoriteListFullInfo[i][4];
cryptoNameLabel.font = [UIFont fontWithName:@"Pretendard-Bold" size:defaultFontSize];
// systemFontOfSize:defaultFontSize
// 생성한 cryptoNameLabel을 cardView의 서브뷰로 추가합니다. 이렇게 함으로써 레이블이 카드 뷰에 표시됩니다.
[cardView addSubview:cryptoNameLabel];
// 암호화폐 가격 레이블을 생성하고 카드뷰에 추가합니다. 조건 3
UILabel *cryptoPriceLabel = [[UILabel alloc] initWithFrame:CGRectMake(cardViewWidth / 4, basicMarginInCard, cardViewWidth / 2, 20)];
cryptoPriceLabel.text = favoriteListFullInfo[i][priceIndexOfFavoriteGoods];
cryptoPriceLabel.textAlignment = NSTextAlignmentRight;
cryptoPriceLabel.font = [UIFont fontWithName:@"Pretendard-ExtraBold" size:defaultFontSize];
[cardView addSubview:cryptoPriceLabel];
// 거래소 이름 레이블을 생성하고 카드뷰에 추가합니다. 조건 5
UILabel *exchangeNameLabel = [[UILabel alloc] initWithFrame:CGRectMake(basicMarginInCard + miniImange, cardViewHeight/2, cardViewWidth/4, 20)];
exchangeNameLabel.text = favoriteListFullInfo[i][0];
exchangeNameLabel.font = [UIFont fontWithName:@"Pretendard-Regular" size:defaultFontSize];
[cardView addSubview:exchangeNameLabel];
UIImageView *exchangeLogo = [[UIImageView alloc] initWithFrame:CGRectMake(basicMarginInCard, cardViewHeight/2, miniImange, miniImange)];
exchangeLogo.image = [UIImage imageNamed:@"bybit_darkBackGround_exchange.jpeg"];
exchangeLogo.contentMode = UIViewContentModeScaleAspectFit; // 해당 옵션을 사용하여 가로세로 비율 유지 크기입니다.
[cardView addSubview:exchangeLogo];
// cardView를 self.scrollView에 추가합니다.
[self.scrollView addSubview:cardView];
}
// ****************************** [End] 카드뷰 목록 쭉 만들기 ****************************** //
// 상하 스크롤 최대치 자동 설정
CGFloat contentHeight = favoriteListFullInfo.count * (cardViewHeight + cardViewSpacing);
self.scrollView.contentSize = CGSizeMake(self.view.bounds.size.width, contentHeight);
}
@end
10. 결과 예시
'Development > iOS' 카테고리의 다른 글
[Objective-C] 앱 만들기 입문 - 11 : 여러 개의 api call 결과 활용 및 디자인 변경 적용 (0) | 2023.07.13 |
---|---|
[Objective-C] 앱 만들기 입문 - 10 : 앱 카드 디자인 변경 - 테두리 만들기 (0) | 2023.07.12 |
[Objective-C] 앱 만들기 입문 - 8 : 프로젝트에 현재 시간 정보 함께 노출하는 기능 추가하기 (0) | 2023.07.10 |
[Objective-C] 앱 만들기 입문 - 7 : 프로젝트에 custom font 적용하고 사용하기 (0) | 2023.07.10 |
[Objective-C] 앱 만들기 입문 - 6 : file 데이터과 api return 데이터를 함께 활용해보기 (0) | 2023.07.09 |