UITableViewCell 클릭시 확장
사용자 정의 UITableViewCell이 있다고 가정 해 보겠습니다.
따라서 셀에서 사용자 지정 버튼을 클릭 할 때마다 어느 정도 확장되어야하며 (40 높이 더 말할 수 있습니다 ...) 동일한 사용자 지정 버튼을 다시 클릭하면 이전 높이로 축소됩니다.
개발자 님 안내해주세요 ..이 작업을 어떻게 수행 할 수 있습니까?
heightForRowAtIndexPath를 구현하여 올바른 높이를 계산합니다. 그런 다음 버튼 코드에서 테이블이 beginUpdates와 endUpdates를 사용하여 각 셀의 높이를 재평가하도록합니다.
[self.tableView beginUpdates];
[self.tableView endUpdates];
tableview 셀의 높이에 대한 변경 사항은 heightForRowAtIndexPath로 자동으로 계산되며 변경 사항도 애니메이션됩니다.
실제로이 작업을 수행하는 셀의 버튼 대신에서 셀을 선택하도록 만들 수도 있습니다 didSelectRowAtIndexPath
.
나는 그것이 완벽하게 옳다는 것을 고려하여 받아 들여진 대답과 모순되는 여기에서 아무것도 말하지 않을 것입니다. 그러나이를 수행하는 방법에 대해 자세히 설명하겠습니다. 이 모든 내용을 읽고 싶지 않고 작업중인 프로젝트에서 소스 코드를 사용하는 데 더 관심이 있다면 예제 프로젝트를 GitHub에 업로드했습니다 .
기본 아이디어는 -tableView: heightForRowAtIndexPath:
현재 셀을 확장해야하는지 여부를 결정 하는 메서드 내부에 조건을 갖는 것 입니다. 이것은 테이블에서 시작 / 종료 업데이트를 호출하여 트리거됩니다 -tableView: didSelectRowAtIndexPath:
.이 예제에서는 한 번에 하나의 셀을 확장 할 수있는 테이블보기를 만드는 방법을 보여줍니다.
가장 먼저해야 할 일은 NSIndexPath 객체에 대한 참조를 선언하는 것입니다. 원하는대로이 작업을 수행 할 수 있지만 다음과 같은 속성 선언을 사용하는 것이 좋습니다.
@property (strong, nonatomic) NSIndexPath *expandedIndexPath;
참고 : viewDidLoad 또는 기타 유사한 메서드 내에서이 인덱스 경로를 만들 필요가 없습니다. 인덱스가 처음에 nil이라는 사실은 테이블에 처음에 확장 된 행이 없다는 것을 의미 할뿐입니다. 선택한 행이 확장 된 상태에서 테이블을 시작하려면 다음과 같이 viewDidLoad 메서드를 추가 할 수 있습니다.
NSInteger row = 1;
NSInteger section = 2;
self.expandedIndexPath = [NSIndexPath indexPathForRow:row inSection:section];
다음 단계는 UITableViewDelegate 메서드 -tableView: didSelectRowAtIndexPath:
로 이동하여 사용자 선택에 따라 확장 된 셀 인덱스를 변경하는 논리를 추가하는 것입니다. 여기서 아이디어는 expandedIndexPath
변수 내부에 저장된 인덱스 경로에 대해 방금 선택한 인덱스 경로를 확인하는 것 입니다. 두 항목이 일치하면 사용자가 확장 된 셀을 선택 취소하려고한다는 것을 알고 있으며이 경우 변수를 nil로 설정합니다. 그렇지 않으면 expandedIndexPath
방금 선택한 인덱스로 변수를 설정합니다 . 이것은 테이블 뷰가 전환 애니메이션을 자동으로 처리 할 수 있도록 beginUpdates / endUpdates 호출 사이에 모두 수행됩니다.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView beginUpdates]; // tell the table you're about to start making changes
// If the index path of the currently expanded cell is the same as the index that
// has just been tapped set the expanded index to nil so that there aren't any
// expanded cells, otherwise, set the expanded index to the index that has just
// been selected.
if ([indexPath compare:self.expandedIndexPath] == NSOrderedSame) {
self.expandedIndexPath = nil;
} else {
self.expandedIndexPath = indexPath;
}
[tableView endUpdates]; // tell the table you're done making your changes
}
그런 다음 마지막 단계는 다른 UITableViewDelegate 메서드에 -tableView: heightForRowAtIndexPath:
있습니다. 이 메서드는 beginUpdates
테이블에서 업데이트가 필요하다고 판단한 각 인덱스 경로에 대해 한 번씩 트리거 한 후에 호출됩니다 . 여기에서 expandedIndexPath
현재 재평가중인 인덱스 경로와 비교합니다 .
두 인덱스 경로가 같으면 확장하려는 셀이고 그렇지 않으면 높이가 정상이어야합니다. 값 100과 44를 사용했지만 필요에 맞는 것을 사용할 수 있습니다.
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Compares the index path for the current cell to the index path stored in the expanded
// index path variable. If the two match, return a height of 100 points, otherwise return
// a height of 44 points.
if ([indexPath compare:self.expandedIndexPath] == NSOrderedSame) {
return 100.0; // Expanded height
}
return 44.0; // Normal height
}
이를 위해 오픈 소스 라이브러리를 만들었습니다. 코드와 voilà 에서 축소 및 확장 델리게이트를 구현하기 만하면됩니다 ! 모든 그림과 애니메이션을 수행 할 수도 있습니다. 이것을 확인 하십시오 .
나는 당신이 말하는 것과 정확히 일치하는 재사용 가능한 구성 요소를 만들었습니다. 사용하기가 매우 쉽고 데모 프로젝트가 있습니다.
GitHub의 GCRetractableSectionController .
[tableView beginUpdates]
및 을 사용하는 대신 메서드 내부에서 메서드를 [tableView endUpdates]
사용하고 있습니다.[tableView reloadRowsAtIndexPath:... withRowAnimation:...]
didSelectRowAtIndexPath
을 확장 할 때 표시해야하는 요소에 문제가 있었기 때문에 UITableViewCell
시작 및 종료 업데이트 메서드를 사용할 때 이것을 선호 합니다. 또 다른 점은 Top, Bottom, Left, Right ...와 같은 애니메이션 중에서 선택할 수 있다는 것입니다.
이것은 Mick의 대답이지만 Swift 4의 경우 (IndexPath는 nil이 Swift를 충돌시키기 때문에 빈 IndexPath와 함께 제공되는 NSIndexPath를 대체합니다. 또한를 사용하여 IndexPath의 두 인스턴스를 비교할 수 있습니다 ==
)
extendedIndexPath 속성을 선언합니다.
var expandedIndexPath = IndexPath()
선택적 viewDidLoad 부분.
expandedIndexPath = IndexPath(row: 1, section: 2)
그런 다음 didSelectRow 부분입니다.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.beginUpdates()
if indexPath == expandedIndexPath {
expandedIndexPath = IndexPath()
} else {
expandedIndexPath = indexPath
}
tableView.endUpdates()
}
그런 다음 heightForRow 부분.
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath == expandedIndexPath {
return 100
}
return 44
}
나는 Gcamp의 소스 코드를 사용하고 나만의 버전을 만들었습니다.
1) loadView 메서드에서 섹션의 확장 또는 비 확장 상태를 저장할 가변 배열을 초기화합니다. 확장 된 상태를 별도의 배열에 저장하는 것이 중요합니다. 이는 테이블보기가 스크롤되는 동안 파괴되지 않습니다 (예를 들어 headerView에 저장하면 다시 그려지고 확장 된 날씨를 잊어 버립니다). 제 경우에는 _sectionStatuses 배열입니다.
- (void)loadView
{
// At the beginning all sections are expanded
_sectionStates = [NSMutableArray arrayWithCapacity:self.tableView.numberOfSections];
for (int i = 0; i < self.tableView.numberOfSections; i++) {
_sectionStates[i] = [NSNumber numberWithBool:YES];
}
}
2) 확장 버튼이있는 섹션에 대한 사용자 지정 headerView를 만듭니다. 위임 패턴을 사용하여 headerView의 버튼에서 TableViewController로 작업을 위임합니다. Gcamp의 소스 코드에서 적절한 이미지를 찾을 수 있습니다.
3) 행을 제거하거나 추가하는 조치를 작성하십시오. 여기 _foldersArray는 모든 데이터를 포함하는 내 구조입니다. 내 섹션의 headerView-MCExpandableAccountHeaderView는 자신의 섹션 번호를 알고 있습니다. 각 섹션의 헤더보기를 만들 때 전송합니다. 어떤 섹션이 현재 확장 또는 확장되었는지 알아야하므로이 방법으로 전송하는 것이 중요합니다.
- (void)expandClicked:(MCAccountHeaderView *)sender
{
MCExpandableAccountHeaderView *expandableAccountHeaderView = (MCExpandableAccountHeaderView*)sender;
// Finding a section, where a button was tapped
NSInteger section = expandableAccountHeaderView.section;
// Number of rows, that must be in a section when it is expanded
NSUInteger contentCount = [_foldersArray[section - 1][@"folders"] count];
// Change a saved status of a section
BOOL expanded = [_sectionStates[section] boolValue];
expanded = ! expanded;
expandableAccountHeaderView.expanded = expanded;
_sectionStates[section] = [NSNumber numberWithBool:expanded];
// Animation in a table
[self.tableView beginUpdates];
NSMutableArray* modifiedIndexPaths = [[NSMutableArray alloc] init];
for (NSUInteger i = 0; i < contentCount; i++) {
NSIndexPath* indexPath = [NSIndexPath indexPathForRow:i inSection:section];
[modifiedIndexPaths addObject:indexPath];
}
if (expandableAccountHeaderView.expanded) [self.tableView insertRowsAtIndexPaths:modifiedIndexPaths withRowAnimation:UITableViewRowAnimationFade];
else [self.tableView deleteRowsAtIndexPaths:modifiedIndexPaths withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
// Scroll to the top of current expanded section
if (expandableAccountHeaderView.expanded) [self.tableView scrollToRowAtIndexPath:INDEX_PATH(0, section) atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
4) 확장 여부에 따라 섹션에서 올바른 수 또는 행을 반환하는 것도 중요합니다.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
BOOL expanded = [_sectionStates[section] boolValue];
return expanded ? [_foldersArray[section - 1][@"folders"] count] : 0;
}
나를 위해 다음을 사용하는 것이 좋습니다.
UITableViewDelegate에서
func tableView (_ tableView : UITableView, didSelectRowAt indexPath : IndexPath) {
print("Did select row: \(indexPath.row).") tableView.beginUpdates() tableView.endUpdates() }
선택 가능 / 확장 가능한 UITableViewCell
override func setSelected (_ selected : Bool, animated : Bool) {super.setSelected (selected, animated : animated)
configStyle(selected) }
중대한!
tableView.rowHeight
이다.automatic
와있는 UITableViewCell 자동 높이 계산을 가능하게하는 제약 조건이다, 즉 그것의 높이 제약 조건을 명확하게 사용되는 추가 위 / 아래 또는 높이 제한 또는 라벨 고유 콘텐츠 크기에 제약 같이 정의된다.
initialize iSelectedIndex = -1; and declare
UITableView *urTableView;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 10; //Section count
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 3; //row count
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
[cell.textLabel setText:[NSString stringWithFormat:@"sec:%d,row:%d",indexPath.section,indexPath.row]];
return cell;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section{
// adding a label with the tap gesture to the header in each section
headerLabel = [[UILabel alloc]init];
headerLabel.tag = section;
headerLabel.userInteractionEnabled = YES;
headerLabel.backgroundColor = [UIColor greenColor];
headerLabel.text = [NSString stringWithFormat:@"Header No.%d",section];
headerLabel.frame = CGRectMake(0, 0, tableView.tableHeaderView.frame.size.width, tableView.tableHeaderView.frame.size.height);
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(gestureTapped:)];
[headerLabel addGestureRecognizer:tapGesture];
return headerLabel;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
return 50.0; //adjust the height as you need
}
- (void)gestureTapped:(UITapGestureRecognizer *)sender{
UIView *theSuperview = self.view; // whatever view contains
CGPoint touchPointInSuperview = [sender locationInView:theSuperview];
UIView *touchedView = [theSuperview hitTest:touchPointInSuperview withEvent:nil];
if([touchedView isKindOfClass:[UILabel class]])
{
if (iSelectedIndex != touchedView.tag) { //if new header is selected , need to expand
iSelectedIndex = touchedView.tag;
}else{ // if the header is already expanded , need to collapse
iSelectedIndex = -1;
}
[urTableView beginUpdates];
[urTableView endUpdates];
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// Show or hide cell
float height = 0.0;
if (indexPath.section == iSelectedIndex) {
height = 44.0; // Show the cell - adjust the height as you need
}
return height;
}
0x7fffffff의 답변에 추가하려면 didSelectRowAtIndexPath 내의 if 문에 추가 조건이 필요하다는 것을 알았습니다 .
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView beginUpdates];
if (self.expandedIndexPath && [indexPath compare:self.expandedIndexPath] == NSOrderedSame) {
self.expandedIndexPath = nil;
} else {
self.expandedIndexPath = indexPath;
}
[tableView endUpdates];
}
버튼을 탭하여 셀을 확장하고 특정 레이블을 설정하는 방법에 대한 이 중간 기사 에 이어 다음 numbersOfLine
을 사용하여 애니메이션을 수행 할 수있었습니다.
tableView.beginUpdates()
tableView.performBatchUpdates({
cell.description.numberOfLines = !expanded ? 0 : 3
}, completion: nil)
tableView.endUpdates()
알림 performBatchUpdates
은 iOS 11⬆️에서만 사용할 수 있습니다.
참조 URL : https://stackoverflow.com/questions/4635338/uitableviewcell-expand-on-click
'programing' 카테고리의 다른 글
pip.req라는 모듈이 없습니다. (0) | 2021.01.16 |
---|---|
사용자가 모바일 Safari에서 탐색했는지 확인 (0) | 2021.01.16 |
셸에서 파일 크기 계산 (0) | 2021.01.16 |
리프트 웹 프레임 워크가 확장 가능한 이유는 무엇입니까? (0) | 2021.01.16 |
C #의 문자열에서 "\ r \ n"을 제거하려면 어떻게해야합니까? (0) | 2021.01.16 |