본문 바로가기

프로그램/iPhone

tableView에서 페이지

안녕하세요. 빡빡한 개발일정에 이리 저리 굴러댕기다 풀리지가 않아
그동안 했던것의 복습겸 해서 간단 강좌를 쓰게 되었습니다.

UITableView는 아이폰의 기본이라 해도 좋을만큼 어떤 어플에서든지 쓰이고, 쓰일수 있는 놈이지요.
하지만 보통 UITableView의 기본 개념만 소개를 해 놓는게 보통이라
요즘 많이쓰이는 페이지 나누기 같은 것을 할려면 좀 골머리를 싸메고 해야하는게 사실이지요.
저도 처음에 할때는 많이 삽질좀 했었지요.
알고나면 언제나 그렇지만 참 쉬운 놈인데 말이지요.

이 강좌는 기본적으로 TableView를 한번이라도 만든 분이 보시면 더 좋을거에요.
중간중간에 띠어먹고 넘어갈만한 것도 있거든요.

여기서 사용된 데이터는 sortednames.plist 라는 놈을 가지고 불러 들여서 읽었습니다.
array를 만들까 했지만, 20개 이상 만들기 귀찮더군요 - _-)

어째든 처음은 프로젝트를 만들어야 겠지요.
Window based던 View Base던 상관이 없으니 하나 만들어 주세요.
이건 강좌용이니 간단히 View Base로 하나 만들어 볼게요.

그다음 기본적인 TableView의 셋팅을 해 볼까요.



rootView.h

#import <UIKit/UIKit.h>


@interface rootView : UIViewController <UITableViewDelegate, UITableViewDataSource> {

NSDictionary *names;

NSArray *keys;

NSMutableArray *namesData;

}


@property (nonatomicretain) NSDictionary *names;

@property (nonatomicretain) NSArray *keys;

@property (nonatomicretain) NSMutableArray *namesData;


@end


헤더 파일에 일단 기본적인 TableView에 대한 delegate, datasource를 선언해 줍니다.

names, keys, namesData는 TableView에 들어갈 데이터를 위한 변수들이죠.





rootView.m


#import "rootView.h"



@implementation rootView


@synthesize names, keys, namesData;


- (void)viewDidLoad {

NSString *path = [[NSBundle mainBundlepathForResource:@"sortednames" ofType:@"plist"];

NSDictionary *dict = [[NSDictionary allocinitWithContentsOfFile:path];

self.names = dict;

[dict release];

NSArray *array = [[names allKeyssortedArrayUsingSelector:@selector(compare:)];

self.keys = array;

self.namesData = [[NSMutableArray allocinit];

for (NSString *key in keys)

{

[namesData addObjectsFromArray:[names objectForKey:key]];

}

pageNumber = 1;

    [super viewDidLoad];

}


- (void)viewDidUnload {

    [super viewDidUnload];

    // Release any retained subviews of the main view.

    // e.g. self.myOutlet = nil;

self.names = nil;

self.keys = nil;

self.namesData = nil;

}


- (void)dealloc {

[names release];

[keys release];

[namesData release];

    [super dealloc];

}


.m에서 수정할 부분은 기본적인

@synthesize 

- (void)viewDidLoad

- (void)viewDidUnload

- (void)dealloc

이 3 함수이겠지요?


synthesize에서 잡아준 변수들 설정해주고, 

viewDidLoad에서 기본 Data를 읽어 들이고, view 종료시 메모리 반환용 viewDidUnlaod와 dealloc의 설정


ViewDidLoad에서 사용한 것은

우선 파일 path를 설정해주고

NSString *path = [[NSBundle mainBundlepathForResource:@"sortednames" ofType:@"plist"];


설정해준 path를 기준으로 Dictionary에 넣은다음

NSDictionary *dict = [[NSDictionary allocinitWithContentsOfFile:path];

self.names = dict;

[dict release];


Dictionary에 넣은 데이터에서 key값들을 array에 넣어주고

NSArray *array = [[names allKeyssortedArrayUsingSelector:@selector(compare:)];

self.keys = array;


dictionary와 key값을 이용해서 하나의 단일 array로 만들어 줘 보았습니다.

self.namesData = [[NSMutableArray allocinit];

for (NSString *key in keys)

{

[namesData addObjectsFromArray:[names objectForKey:key]];

}

section을 나누어도 상관은 없는 이야기지만, 좀 더 알기 쉽게 하기 위해 section을 없애는게 편하다고 생각했거든요




여기까지 기본 설정을 해 준다음 다음은 TableView의 delegate와 datasource를 설정해야겠지요.

#pragma mark -

#pragma mark TableView delegate

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 

{

return namesData.count;

}


- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *tableViewCell = @"tableViewCell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:tableViewCell];

if (cell == nil)

cell = [[[UITableViewCell allocinitWithStyle:UITableViewCellStyleDefault reuseIdentifier:tableViewCell] autorelease];

cell.textLabel.text = [namesData objectAtIndex:indexPath.row];

return cell;

}


TableView의 기본 설정을 이것만으로도 데이터가 출력이 되지요.
일단 확인을 위해 Interface Builder에서 TableView를 넣고 datasource와 delegate를 연결해주고
build and run 해 봅니다.

테이블이 제대로 나오는것을 확인했으면 이제부터, page를 나눠보도록 할게요.

우선 rootView.h 헤더 파일에 한 페이지에 들어갈 목록수를 결정한 변수를 지정해주고

#define kPageDivide 20


@interface rootView : UIViewController <UITableViewDelegate, UITableViewDataSource> 

안에 

NSUInteger pageNumber;

를 추가합니다.


다음, 

rootView.m 으로 돌아와서


- (void)viewDidLoad 앉에 첫 페이지를 설정해줍니다

pageNumber = 1;


tableView delegate로 가서

#pragma mark -

#pragma mark TableView delegate

다음과 같이 코드를 수정합니다.

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {

if ((pageNumber * kPageDivide) < namesData.count)

{

return (pageNumber * kPageDivide) + 1;

}

else {

return namesData.count;

}

}


우선 한 페이지에 보여주는 row의 수를 결정하는것인데, 두가지 분기로 나누어 지게 됩니다.

현제 페이지 수를 확인해서 최대로 보여질수 있는 목록수를 확인하고, 그 목록수가 

namesData가 가지고 있는 데이터의 수보다 적다면 그대로 pageNumber * kPageDivide + 1

을 리턴하게 되겠지요. 여기서 

+1

을 붙인 이유는 테이블 목록에 아직 더 보여줄 목록이 남아있을경우, "Load More" 같이

마지막 셀을 클릭시 페이지를 더 로딩하기 위한 셀을 표시해야 하기 때문이죠.


만약 최대로 보여질수 있는 목록수가 namesData가 들고있는 수보다 많으면 당연히 

namesData.count 

를 리턴하는거죠



- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *tableViewCell = @"tableViewCell";

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:tableViewCell];

if (cell == nil)

cell = [[[UITableViewCell allocinitWithStyle:UITableViewCellStyleDefault reuseIdentifier:tableViewCell] autorelease];

if ((pageNumber * kPageDivide) < namesData.count)

{

if (indexPath.row != (pageNumber * kPageDivide)) {

cell.textLabel.text = [namesData objectAtIndex:indexPath.row];

}

else {

cell.textLabel.text = @"Load More";

}

}

else

{

cell.textLabel.text = [namesData objectAtIndex:indexPath.row];

}

return cell;

}


다음, 각 셀을 표시할때도 마찬가지로, 최대로 보여질수 있는 목록수와 namesData의 목록수를 비교해서

namesData가 클 경우 보통의 cell을 표시해주고, 마지막 cell에 페이지 로딩을 위한

cell.textLabel.text = @"Load More";

를 지정해 주는겁니다.


물론 namesData의 데이터 수가 작을경우는 

평범하게 데이터를 표시하면 되는거죠.


여기까지 하셨다면 Build and Run시에 목록이 20개만 나오고, 마지막 21번재는 Load More 가 표시되겠지요.


 

이제는 Load more를 눌렀을 경우 목록을 더 불러오는 기능을 만들어야겠지요.



- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

{

[tableView deselectRowAtIndexPath:indexPath animated:YES];

if ((pageNumber * kPageDivide) < namesData.count)

{

if (indexPath.row != (pageNumber * kPageDivide)) {

NSString *str = [NSString stringWithFormat:@"you have pushed %@", [tableViewcellForRowAtIndexPath:indexPath].textLabel.text];
UIAlertView *alert = [[UIAlertView allocinitWithTitle:@"Warning" message:str delegate:nil cancelButtonTitle:@"O K"otherButtonTitles:nil];
[alert show];
[alert release];

}

else {

pageNumber++;
[tableView reloadData];
}

}

}


가장 기본이 되는것은 역시 아래쪽의 단 두줄입니다.

pageNumber++;

[tableView reloadData];

if 문을 통해 선택한 셀이 마지막 셀인지 아닌지 체크해서 

if (indexPath.row != (pageNumber * kPageDivide))

마지막 셀이라면 pageNumber count를 1 올려주고,

그저 tableView를 reloadData만 시켜주면 되는거지요.


끝입니다. 엥? 뭐이리 간단해? 이지요?

수정하고 한번 테스트 해 보세요. 광속처럼 페이지가 로딩이 될겁니다.

이상태로도 이제 사용이 가능한거죠.


하지만 이대로 끝내기는 뭔가 찜찜하고 심심하죠. 


그래서 뱅글뱅글 로딩화면을 한번 추가해 볼게요.


rootView.m 으로 가서


UIActivityIndicatorView *activityIndicator;


@property (nonatomicretain) UIActivityIndicatorView *activityIndicator;


- (void)stopAnimation;

이 3개를 추가해 줍니다.


다음 rootView.h에서는


@synthesize activityIndicator;


- (void)viewDidUnload {

    [super viewDidUnload];

    // Release any retained subviews of the main view.

    // e.g. self.myOutlet = nil;

self.names = nil;

self.keys = nil;

self.namesData = nil;

self.activityIndicator = nil;

}


- (void)dealloc {

[names release];

[keys release];

[namesData release];

[activityIndicator release];

    [super dealloc];

}

를 수정해 줍니다.


다음으로 

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

함수에서


else {

pageNumber++;
activityIndicator = [[UIActivityIndicatorView allocinitWithFrame:CGRectMake(003232)];
[activityIndicator setCenter:CGPointMake(160208)];
[activityIndicator setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleGray];
[self.view addSubview:activityIndicator];
[activityIndicator release];
[activityIndicator startAnimating];
[self performSelector:@selector(stopAnimationwithObject:nil afterDelay:2];
[tableView reloadData];

}


이런식으로 수정해 줍니다.

대충 감이 오시지요?

요는 tableView reloadData를 할때

activityIndicator를 돌려주고, 2초후에 activityIndicator를 정지할 함수를 실행해 주는거죠


마지막으로


- (void)stopAnimation {

[activityIndicator stopAnimating];

}

를 추가해 줍니다.


Build and Run을 해보시면 Load More를 눌렀을 경우 뱅글이가 생긴걸 확인하실수 있을거에요.



출처 : http://cafe.naver.com/mcbugi.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=48620