1. 이전 포스팅 확인하기

 

 

https://growingsaja.tistory.com/890

 

[Objective-C] 앱 만들기 입문 - 3 : 상하(위아래) 스크롤 기능 넣기

1. 이전 포스팅 확인하기 https://growingsaja.tistory.com/888 [Objective-C] 앱 만들기 입문 - 2 : 세로 정렬 카드뷰 만들고 안에 문구 및 활성화 스위치 넣기 1. 이전 포스팅 확인하기 https://growingsaja.tistory.com/88

growingsaja.tistory.com

 

 

 

 

 

2. 본 프로젝트 파일 및 그룹 구성도

 

 - 프로젝트 구조 설명

    Resources/Reference/res 안에 json 파일 등 추후 있을 작거나 주요한 resource들 관리 용도

    CAMS/CamsRuntime 안에 서비스와 거리가 있는 기능을 구현한 파일들 구성 용도

      - ex. JSONReader : json file 읽는 기능 구현

 

필자의 경우, CAMS Run Time -> CRT를 앞에 붙여, 서비스와는 거리가 있는 기능 구현 용도의 파일명을 규칙성 있게 가져갈 예정입니다.

 

 

 

 

 

 

3. 실습을 위한 json 파일 생성 및 내용 작성

 

{
    "favoriteList_description": [
        ["exchangeName", "Fullname", "codeName", "unit", "sort", "isAvailable"],
        ["거래소이름", "전체이름", "코드 또는 축약이름", "단위", "종류", "활성화 여부"]
    ],
    "favoriteList": [
        ["Binance", "Bitcoin", "BTC", "USDT", "coin", "Y"],
        ["Binance", "Ethereum", "ETH", "USDT", "coin", "Y"],
        ["Bitget", "Ripple", "XRP", "USDT", "coin", "N"],
        ["Coinbase", "Litecoin", "LTC", "USDT", "coin", "Y"],
        ["Bybit", "Bitcoin", "BTC", "USDT", "coin", "N"],
        ["Bybit", "Ethereum", "ETH", "USDT", "coin", "N"],
        ["Bybit", "Binance Coin", "BNB", "USDT", "coin", "N"],
        ["Bybit", "Solana", "SOL", "USDT", "coin", "N"],
        ["Bybit", "Cardano", "ADA", "USDT", "coin", "N"],
        ["Bybit", "Ripple", "XRP", "USDT", "coin", "N"],
        ["Bybit", "Terra", "LUNA", "USDT", "coin", "N"],
        ["Bybit", "Polkadot", "DOT", "USDT", "coin", "N"],
        ["Bybit", "Avalanche", "AVAX", "USDT", "coin", "N"],
        ["Bybit", "Chainlink", "LINK", "USDT", "coin", "N"]
    ]
}

 

 

 

 

 

4. CRTJSONReader 파일 작성

 

// vim CRTJSONReader.h

#import <Foundation/Foundation.h>

@interface CRTJSONReader : NSDictionary

// JSON 파일을 읽어오기 위한 메소드 선언
- (NSDictionary*)loadJSONFromFile:(NSString *)fileName;

@end

 

// vim CRTJSONReader.m

#import "CRTJSONReader.h"

@implementation CRTJSONReader

- (NSDictionary *) loadJSONFromFile:(NSString *)jsonFileName {
    NSBundle *mainBundle = [NSBundle mainBundle];
    NSString *jsonFilePath = [mainBundle pathForResource:jsonFileName ofType:@"json"];
    NSError *errorJson = nil;
    // 불러올 객체 없을때 reutrn하는 데이터 생성
    NSDictionary *emptyDictionary = [NSDictionary dictionary];

    // 파일 경로를 확인합니다.
    if (jsonFilePath != nil) {
        NSLog(@"JSON 파일 경로: %@", jsonFilePath);

        // JSON 데이터를 읽어옵니다.
        NSData *jsonData = [NSData dataWithContentsOfFile:jsonFilePath];

        // JSON을 NSDictionary로 파싱합니다.
        NSDictionary *jsonObject = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:&errorJson];
        if (errorJson) {
            NSLog(@"JSON 파싱 오류: %@", [errorJson localizedDescription]);
            return emptyDictionary;
        } else {
            // JSON 데이터를 사용합니다.
//            NSLog(@"JSON 객체: %@", jsonObject);
            return jsonObject;
        }
    } else {
        NSLog(@"JSON 파일을 찾을 수 없습니다.");
        return emptyDictionary;
    }
}

@end

 

 

 

 

 

5. CurrencyTrackerListVC 파일 수정

 

// vim Controller/CurrencyTrackerListVC.h

#import <UIKit/UIKit.h>
#import "CRTJSONReader.h"

// CurrencyTrackerListVC라는 이름의 뷰 컨트롤러 클래스를 선언합니다.
@interface CurrencyTrackerListVC : UIViewController {
    UIScrollView *scrollView;
}

@end

 

// vim Controller/CurrencyTrackerListVC.m

#import <Foundation/Foundation.h>
#import "CurrencyTrackerListVC.h"

@implementation CurrencyTrackerListVC {
    NSDictionary* resultOfBybitAll;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    // ****************************** [Start] 데이터 가져오기 ****************************** //
    // JSONReader 객체를 생성합니다. = 카드뷰에 표시할 데이터를 초기화합니다.
    CRTJSONReader *defaultData = [[CRTJSONReader alloc] init];
    // JSON 파일명을 전달하여 JSON 데이터를 읽어옵니다.
    NSDictionary* resultOfDefaultJsonFile = [defaultData loadJSONFromFile:@"default"];  // example.json 파일을 대상으로 합니다.
    // JSON 데이터를 사용합니다.
    NSArray* favoriteList = resultOfDefaultJsonFile[@"favoriteList"];
    NSLog(@"%@", favoriteList);
    // ****************************** [End] 데이터 가져오기 ****************************** //
    
    // ****************************** [Start] 뷰 ****************************** //
    // viewDidLoad 메서드에서 스크롤 뷰를 초기화하고 설정합니다.
    scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
    scrollView.backgroundColor = [UIColor clearColor];
    [self.view addSubview:scrollView];
    
    //카드뷰 배치에 필요한 변수를 설정합니다.
    // 카드 목록 나열될 공간 세팅
    // ****************************** //
    // 목록 상단 공백 margin 설정
    CGFloat cardViewTopStartMargin = 10.0;
    // 카드 목록의 좌우 공백 각각의 margin
    CGFloat horizontalMargin = 2;
    // 카드와 카드 사이의 공백
    CGFloat cardViewSpacing = 12.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;
    // ****************************** //
    // ****************************** [End] 뷰 ****************************** //
    
    // 카드뷰들을 생성하고 뷰에 추가합니다.
    for (int i = 0; i < favoriteList.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)];
        // 레이블의 텍스트를 설정합니다. 여기에서는 favoriteList 배열의 i 번째 요소를 사용합니다.
        cryptoNameLabel.text = [favoriteList[i][2] stringByAppendingString:favoriteList[i][3]];
        cryptoNameLabel.font = [UIFont systemFontOfSize:defaultFontSize];
        // 생성한 cryptoNameLabel을 cardView의 서브뷰로 추가합니다. 이렇게 함으로써 레이블이 카드 뷰에 표시됩니다.
        [cardView addSubview:cryptoNameLabel];


        // 암호화폐 가격 레이블을 생성하고 카드뷰에 추가합니다. 조건 3
        UILabel *cryptoPriceLabel = [[UILabel alloc] initWithFrame:CGRectMake(cardViewWidth / 3, basicMarginInCard, cardViewWidth / 2 - basicMarginInCard, 20)];
        cryptoPriceLabel.text = favoriteList[i][1];
        cryptoPriceLabel.textAlignment = NSTextAlignmentRight;
        cryptoPriceLabel.font = [UIFont systemFontOfSize:defaultFontSize];
        [cardView addSubview:cryptoPriceLabel];

        // 활성화 스위치를 생성하고 카드뷰에 추가합니다. 조건 4
        UISwitch *activationSwitch = [[UISwitch alloc] initWithFrame:CGRectMake(cardViewWidth / 7 * 6, cardViewHeight - 40, 200, 40)];
        [activationSwitch addTarget:self action:@selector(onSwitchValueChanged:) forControlEvents:UIControlEventValueChanged];
        [cardView addSubview:activationSwitch];

        // 거래소 이름 레이블을 생성하고 카드뷰에 추가합니다. 조건 5
        UILabel *exchangeNameLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, cardViewHeight - 25, cardViewWidth - 20, 20)];
        exchangeNameLabel.text = favoriteList[i][0];
        exchangeNameLabel.font = [UIFont systemFontOfSize:defaultFontSize];
        [cardView addSubview:exchangeNameLabel];
        [scrollView addSubview:cardView];
    }
    // 상하 스크롤 최대치 자동 설정
    CGFloat contentHeight = favoriteList.count * (cardViewHeight + cardViewSpacing);
    scrollView.contentSize = CGSizeMake(self.view.bounds.size.width, contentHeight);
}

- (void)onSwitchValueChanged:(UISwitch *)sender {
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"Switch value changed: %@", sender.isOn ? @"ON" : @"OFF");
    });
    
}


@end

 

 

 

 

 

5. 결과 예시

 

 

 

 

+ Recent posts