스 와이프하여 삭제 및 '추가'버튼 (iOS 7의 Mail 앱에서와 같이)
사용자가 테이블보기에서 셀을 스 와이프 할 때 "더보기"버튼을 만드는 방법 (예 : iOS 7의 메일 앱)
나는이 정보를 여기와 Cocoa Touch 포럼에서 찾고 있었지만 대답을 찾을 수없는 것 같고 나보다 똑똑한 사람이 나에게 해결책을 줄 수 있기를 바랍니다.
사용자가 테이블보기 셀을 스 와이프하여 둘 이상의 편집 버튼을 표시하고 싶습니다 (기본값은 삭제 버튼입니다). iOS 7 용 Mail 앱에서 스 와이프하여 삭제할 수 있지만 "MORE"버튼이 표시됩니다.
구현하는 방법
iOS 8 이이 API를 여는 것처럼 보입니다. 이러한 기능의 힌트는 베타 2에 있습니다.
무언가 효과를 얻으려면 UITableView의 대리자에 다음 두 가지 방법을 구현하여 원하는 효과를 얻으십시오 (예는 요지 참조).
- tableView:editActionsForRowAtIndexPath:
- tableView:commitEditingStyle:forRowAtIndexPath:
알려진 문제
설명서에 tableView : commitEditingStyle : forRowAtIndexPath는 다음과 같습니다.
"UITableViewRowAction을 사용하여 편집 조치를 호출하지 않습니다. 대신 조치 핸들러가 호출됩니다."
그러나 스 와이프가 없으면 스 와이프가 작동하지 않습니다. 메서드 스텁이 비어 있어도 지금은 여전히 필요합니다. 이것은 베타 2의 버그입니다.
출처
https://twitter.com/marksands/status/481642991745265664 https://gist.github.com/marksands/76558707f583dbb8f870
원래 답변 : https://stackoverflow.com/a/24540538/870028
최신 정보:
이 작업을 수행하는 샘플 코드 (Swift에서) : http://dropbox.com/s/0fvxosft2mq2v5m/DeleteRowExampleSwift.zip
샘플 코드에는 MasterViewController.swift에 따라하기 쉬운이 방법이 포함되어 있으며이 방법만으로도 OP 스크린 샷에 표시된 동작을 얻을 수 있습니다.
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]? {
var moreRowAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "More", handler:{action, indexpath in
println("MORE•ACTION");
});
moreRowAction.backgroundColor = UIColor(red: 0.298, green: 0.851, blue: 0.3922, alpha: 1.0);
var deleteRowAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Delete", handler:{action, indexpath in
println("DELETE•ACTION");
});
return [deleteRowAction, moreRowAction];
}
iOS 8 메일 앱과 같은 다양한 전환 및 확장 가능한 버튼을 지원하는 스 와이프 가능한 버튼을 구현하는 새로운 라이브러리를 만들었습니다.
https://github.com/MortimerGoro/MGSwipeTableCell
이 라이브러리는 UITableViewCell을 작성하고 iOS 5, iOS 6, iOS 7 및 iOS 8에서 테스트하는 다양한 방법과 호환됩니다.
다음은 몇 가지 전이 샘플입니다.
국경 전환 :
클립 전환
3D 전환 :
Johnny의 답변은 공감할 수있는 올바른 답변입니다. 나는 초보자 (그리고 Swift 구문을 배우기를 거부하는 우리들에게 더 명확하게하기 위해 objective-c에 아래에 이것을 추가하고 있습니다 :)
uitableviewdelegate를 선언하고 다음 메소드를 가지고 있는지 확인하십시오.
-(NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewRowAction *button = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"Button 1" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath)
{
NSLog(@"Action to perform with Button 1");
}];
button.backgroundColor = [UIColor greenColor]; //arbitrary color
UITableViewRowAction *button2 = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"Button 2" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath)
{
NSLog(@"Action to perform with Button2!");
}];
button2.backgroundColor = [UIColor blueColor]; //arbitrary color
return @[button, button2]; //array with all the buttons you want. 1,2,3, etc...
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
// you need to implement this method too or nothing will work:
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES; //tableview must be editable or nothing will work...
}
이것은 (사소하게도) 개인 API입니다.
다음 두 메소드는 개인용이며 UITableView의 대리자에게 전송됩니다.
-(NSString *)tableView:(UITableView *)tableView titleForSwipeAccessoryButtonForRowAtIndexPath:(NSIndexPath *)indexPath;
-(void)tableView:(UITableView *)tableView swipeAccessoryButtonPushedForRowAtIndexPath:(NSIndexPath *)indexPath;
그들은 꽤 자명하다.
Johnny의 답변을 개선하기 위해 이제 다음과 같이 공개 API를 사용하여 수행 할 수 있습니다.
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]? {
let moreRowAction = UITableViewRowAction(style: UITableViewRowActionStyle.default, title: "More", handler:{action, indexpath in
print("MORE•ACTION");
});
moreRowAction.backgroundColor = UIColor(red: 0.298, green: 0.851, blue: 0.3922, alpha: 1.0);
let deleteRowAction = UITableViewRowAction(style: UITableViewRowActionStyle.default, title: "Delete", handler:{action, indexpath in
print("DELETE•ACTION");
});
return [deleteRowAction, moreRowAction];
}
사과가 당신에게 필요한 것을 줄 때까지 기다릴 수 없기를 바랍니다. 그래서 여기 내 옵션이 있습니다.
사용자 정의 셀을 작성하십시오. 거기에 두 개의 uiviews가 있습니다
1. upper
2. lower
하단에서 필요한 버튼을 추가하십시오. 다른 IBAction과 마찬가지로 그 행동을 다루십시오. 애니메이션 시간, 스타일 등을 결정할 수 있습니다.
이제 상단보기에 uiswipegesture를 추가하고 살짝 밀기 제스처에서 하단보기를 표시하십시오. 내가 전에 까지이 작업을 수행했으며 가장 간단한 옵션입니다.
도움이 되길 바랍니다.
표준 SDK를 사용하면 불가능합니다. 그러나 Mail.app에는 동작을 모방하는 다양한 타사 솔루션이 있습니다. 그중 일부 (예 : MCSwipeTableViewCell , DAContextMenuTableViewController , RMSwipeTableViewCell )는 제스처 인식기를 사용하여 스 와이프를 감지하고 그 중 일부 (예 : SWTableViewCell )는 표준 UITableViewCellScrollView
(비공개 하위보기 UITableViewCell
) 아래에 두 번째 UISScrollView를 배치 하고 일부는 동작을 수정합니다 UITableViewCellScrollView
.
터치 핸들링이 가장 자연 스럽기 때문에 마지막 접근 방식이 가장 좋습니다. 특히 MSCMoreOptionTableViewCell 이 좋습니다. 선택은 특정 요구에 따라 달라질 수 있습니다 (왼쪽에서 오른쪽으로 팬이 필요한지 여부, iOS 6 호환성이 필요한지 여부 등). 또한 이러한 접근 방식의 대부분은 부담이 따른다는 점에 유의하십시오. Apple이 UITableViewCell
하위 뷰 계층 구조를 변경하면 향후 iOS 버전에서 쉽게 중단 될 수 있습니다 .
라이브러리를 사용하지 않고 Swift 3 버전 코드 :
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tableView.tableFooterView = UIView(frame: CGRect.zero) //Hiding blank cells.
tableView.separatorInset = UIEdgeInsets.zero
tableView.dataSource = self
tableView.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 4
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "tableCell", for: indexPath)
return cell
}
//Enable cell editing methods.
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
}
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let more = UITableViewRowAction(style: .normal, title: "More") { action, index in
//self.isEditing = false
print("more button tapped")
}
more.backgroundColor = UIColor.lightGray
let favorite = UITableViewRowAction(style: .normal, title: "Favorite") { action, index in
//self.isEditing = false
print("favorite button tapped")
}
favorite.backgroundColor = UIColor.orange
let share = UITableViewRowAction(style: .normal, title: "Share") { action, index in
//self.isEditing = false
print("share button tapped")
}
share.backgroundColor = UIColor.blue
return [share, favorite, more]
}
}
사용자가 셀을 스 와이프 할 때마다 호출되는 UITableViewCell
메소드 를 서브 클래스 및 서브 클래스 해야합니다 willTransitionToState:(UITableViewCellStateMask)state
. state
플래그는 삭제 버튼이 표시되어 있는지 알 수 있도록하고 더 많은 버튼이 숨기기 / 표시됩니다.
불행하게도이 방법은 삭제 버튼의 너비 나 애니메이션 시간을 제공하지 않습니다. 따라서 More 버튼의 프레임과 애니메이션 시간을 코드에 관찰하고 하드 코딩해야합니다 (개인적으로 Apple은 이에 대해 무언가를해야한다고 생각합니다).
신속한 프로그래밍
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == UITableViewCellEditingStyle.Delete {
deleteModelAt(indexPath.row)
self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
}
else if editingStyle == UITableViewCellEditingStyle.Insert {
println("insert editing action")
}
}
func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]? {
var archiveAction = UITableViewRowAction(style: .Default, title: "Archive",handler: { (action: UITableViewRowAction!, indexPath: NSIndexPath!) in
// maybe show an action sheet with more options
self.tableView.setEditing(false, animated: false)
}
)
archiveAction.backgroundColor = UIColor.lightGrayColor()
var deleteAction = UITableViewRowAction(style: .Normal, title: "Delete",
handler: { (action: UITableViewRowAction!, indexPath: NSIndexPath!) in
self.deleteModelAt(indexPath.row)
self.tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic);
}
);
deleteAction.backgroundColor = UIColor.redColor()
return [deleteAction, archiveAction]
}
func deleteModelAt(index: Int) {
//... delete logic for model
}
이것은 당신을 도울 수 있습니다.
-(NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewRowAction *button = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"Button 1" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath)
{
NSLog(@"Action to perform with Button 1");
}];
button.backgroundColor = [UIColor greenColor]; //arbitrary color
UITableViewRowAction *button2 = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDefault title:@"Button 2" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath)
{
NSLog(@"Action to perform with Button2!");
}];
button2.backgroundColor = [UIColor blueColor]; //arbitrary color
return @[button, button2]; //array with all the buttons you want. 1,2,3, etc...
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
// you need to implement this method too or nothing will work:
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES; //tableview must be editable or nothing will work...
}
내 앱에 동일한 기능을 추가하고 싶었고 수많은 튜토리얼 ( raywenderlich 가 최고의 DIY 솔루션 임)을 거친 후 Apple 자체 UITableViewRowAction
클래스 가 있음을 알았습니다 . 매우 편리합니다.
Tableview의 상용구 방법을 다음과 같이 변경해야합니다.
override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]? {
// 1
var shareAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Share" , handler: { (action:UITableViewRowAction!, indexPath:NSIndexPath!) -> Void in
// 2
let shareMenu = UIAlertController(title: nil, message: "Share using", preferredStyle: .ActionSheet)
let twitterAction = UIAlertAction(title: "Twitter", style: UIAlertActionStyle.Default, handler: nil)
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: nil)
shareMenu.addAction(twitterAction)
shareMenu.addAction(cancelAction)
self.presentViewController(shareMenu, animated: true, completion: nil)
})
// 3
var rateAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Rate" , handler: { (action:UITableViewRowAction!, indexPath:NSIndexPath!) -> Void in
// 4
let rateMenu = UIAlertController(title: nil, message: "Rate this App", preferredStyle: .ActionSheet)
let appRateAction = UIAlertAction(title: "Rate", style: UIAlertActionStyle.Default, handler: nil)
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: nil)
rateMenu.addAction(appRateAction)
rateMenu.addAction(cancelAction)
self.presentViewController(rateMenu, animated: true, completion: nil)
})
// 5
return [shareAction,rateAction]
}
이 사이트 에서 이에 대한 자세한 내용을 확인할 수 있습니다 . Apple의 자체 문서 는 배경색을 변경하는 데 실제로 유용합니다.
동작 버튼의 배경색입니다.
선언 OBJECTIVE-C @property (nonatomic, copy) UIColor * backgroundColor 토론이 속성을 사용하여 단추의 배경색을 지정하십시오. 이 속성의 값을 지정하지 않으면 UIKit은 스타일 속성의 값을 기반으로 기본 색상을 할당합니다.
iOS 8.0 이상에서 사용 가능합니다.
버튼의 글꼴을 변경하려면 조금 까다 롭습니다. SO에 대한 다른 게시물 을 보았습니다 . 코드와 링크를 제공하기 위해 여기에 사용 된 코드가 있습니다. 버튼의 모양을 변경해야합니다. tableviewcell에 대한 특정 참조를 작성해야합니다. 그렇지 않으면 앱 전체에서 버튼 모양을 변경해야합니다 (원하지 않았지만 모를 수도 있습니다 :))
목표 C :
+ (void)setupDeleteRowActionStyleForUserCell {
UIFont *font = [UIFont fontWithName:@"AvenirNext-Regular" size:19];
NSDictionary *attributes = @{NSFontAttributeName: font,
NSForegroundColorAttributeName: [UIColor whiteColor]};
NSAttributedString *attributedTitle = [[NSAttributedString alloc] initWithString: @"DELETE"
attributes: attributes];
/*
* We include UIView in the containment hierarchy because there is another button in UserCell that is a direct descendant of UserCell that we don't want this to affect.
*/
[[UIButton appearanceWhenContainedIn:[UIView class], [UserCell class], nil] setAttributedTitle: attributedTitle
forState: UIControlStateNormal];
}
빠른:
//create your attributes however you want to
let attributes = [NSFontAttributeName: UIFont.systemFontOfSize(UIFont.systemFontSize())] as Dictionary!
//Add more view controller types in the []
UIButton.appearanceWhenContainedInInstancesOfClasses([ViewController.self])
이것은 가장 쉽고 가장 유선 인 버전 IMHO입니다. 도움이 되길 바랍니다.
업데이트 : Swift 3.0 버전은 다음과 같습니다.
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
var shareAction:UITableViewRowAction = UITableViewRowAction(style: .default, title: "Share", handler: {(action, cellIndexpath) -> Void in
let shareMenu = UIAlertController(title: nil, message: "Share using", preferredStyle: .actionSheet)
let twitterAction = UIAlertAction(title: "Twitter", style: .default, handler: nil)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
shareMenu.addAction(twitterAction)
shareMenu.addAction(cancelAction)
self.present(shareMenu,animated: true, completion: nil)
})
var rateAction:UITableViewRowAction = UITableViewRowAction(style: .default, title: "Rate" , handler: {(action, cellIndexpath) -> Void in
// 4
let rateMenu = UIAlertController(title: nil, message: "Rate this App", preferredStyle: .actionSheet)
let appRateAction = UIAlertAction(title: "Rate", style: .default, handler: nil)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
rateMenu.addAction(appRateAction)
rateMenu.addAction(cancelAction)
self.present(rateMenu, animated: true, completion: nil)
})
// 5
return [shareAction,rateAction]
}
실제 스위프트 3 답변
이것은 필요한 유일한 기능입니다. 사용자 정의 조치에 CanEdit 또는 CommitEditingStyle 함수가 필요하지 않습니다.
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let action1 = UITableViewRowAction(style: .default, title: "Action1", handler: {
(action, indexPath) in
print("Action1")
})
action1.backgroundColor = UIColor.lightGray
let action2 = UITableViewRowAction(style: .default, title: "Action2", handler: {
(action, indexPath) in
print("Action2")
})
return [action1, action2]
}
iOS 11부터는에서 공개적으로 사용할 수 있습니다 UITableViewDelegate
. 샘플 코드는 다음과 같습니다.
- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath {
UIContextualAction *delete = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleDestructive
title:@"DELETE"
handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
NSLog(@"index path of delete: %@", indexPath);
completionHandler(YES);
}];
UIContextualAction *rename = [UIContextualAction contextualActionWithStyle:UIContextualActionStyleNormal
title:@"RENAME"
handler:^(UIContextualAction * _Nonnull action, __kindof UIView * _Nonnull sourceView, void (^ _Nonnull completionHandler)(BOOL)) {
NSLog(@"index path of rename: %@", indexPath);
completionHandler(YES);
}];
UISwipeActionsConfiguration *swipeActionConfig = [UISwipeActionsConfiguration configurationWithActions:@[rename, delete]];
swipeActionConfig.performsFirstActionWithFullSwipe = NO;
return swipeActionConfig;
}
또한 이용 가능한:
- (UISwipeActionsConfiguration *)tableView:(UITableView *)tableView leadingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath;
문서 : https://developer.apple.com/documentation/uikit/uitableviewdelegate/2902367-tableview?language=objc
스위프트 4 & iOS 11+
@available(iOS 11.0, *)
override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let delete = UIContextualAction(style: .destructive, title: "Delete") { _, _, handler in
handler(true)
// handle deletion here
}
let more = UIContextualAction(style: .normal, title: "More") { _, _, handler in
handler(true)
// handle more here
}
return UISwipeActionsConfiguration(actions: [delete, more])
}
나는 여러 개의 데이터를 보여주기 위해 tableViewCell 을 사용 했다. 셀에서 오른쪽에서 왼쪽으로 스 와이프 한 후에는 두 개의 버튼이 표시된다 승인 및 거부, 두 가지 방법이 있는데, 첫 번째 방법은 하나의 인수를 취하는 ApproveFunc이고 다른 하나는 RejectFunc입니다. 하나의 주장을 취합니다.
func tableView(_ tableView: UITableView, editActionsForRowAt indexPath: IndexPath) -> [UITableViewRowAction]? {
let Approve = UITableViewRowAction(style: .normal, title: "Approve") { action, index in
self.ApproveFunc(indexPath: indexPath)
}
Approve.backgroundColor = .green
let Reject = UITableViewRowAction(style: .normal, title: "Reject") { action, index in
self.rejectFunc(indexPath: indexPath)
}
Reject.backgroundColor = .red
return [Reject, Approve]
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func ApproveFunc(indexPath: IndexPath) {
print(indexPath.row)
}
func rejectFunc(indexPath: IndexPath) {
print(indexPath.row)
}
개인 API를 포함하지 않거나 자체 시스템을 구성하지 않는 다소 취약한 방법이 있습니다. 당신은 애플이 이것을 깨뜨리지 않을 것이라는 내기를 헤징하고 있으며 희망적으로 그들은 몇 줄의 코드로 대체 할 수있는 API를 발표 할 것입니다.
- KVO self.contentView.superview.layer.sublayer. init에서 이것을하십시오. 이것이 UIScrollView의 레이어입니다. KVO 'subviews'는 할 수 없습니다.
- 하위보기가 변경되면 scrollview.subviews에서 삭제 확인보기를 찾으십시오. 이것은 관찰 콜백에서 수행됩니다.
- 해당 뷰의 크기를 두 배로 늘리고 하위 뷰의 왼쪽에 UIButton을 추가하십시오. 이것은 관찰 콜백에서도 수행됩니다. 삭제 확인보기의 유일한 하위보기는 삭제 단추입니다.
- (선택 사항) UIButton 이벤트는 UITableView를 찾을 때까지 self.superview를 찾은 다음 tableView : commitCustomEditingStyle : forRowAtIndexPath :와 같이 생성 한 데이터 소스 또는 위임 메소드를 호출해야합니다. [tableView indexPathForCell : self]를 사용하여 셀의 indexPath를 찾을 수 있습니다.
또한 표준 테이블 뷰 편집 대리자 콜백을 구현해야합니다.
static char kObserveContext = 0;
@implementation KZTableViewCell {
UIScrollView *_contentScrollView;
UIView *_confirmationView;
UIButton *_editButton;
UIButton *_deleteButton;
}
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
_contentScrollView = (id)self.contentView.superview;
[_contentScrollView.layer addObserver:self
forKeyPath:@"sublayers"
options:0
context:&kObserveContext];
_editButton = [UIButton new];
_editButton.backgroundColor = [UIColor lightGrayColor];
[_editButton setTitle:@"Edit" forState:UIControlStateNormal];
[_editButton addTarget:self
action:@selector(_editTap)
forControlEvents:UIControlEventTouchUpInside];
}
return self;
}
-(void)dealloc {
[_contentScrollView.layer removeObserver:self forKeyPath:@"sublayers" context:&kObserveContext];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if(context != &kObserveContext) {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
return;
}
if(object == _contentScrollView.layer) {
for(UIView * view in _contentScrollView.subviews) {
if([NSStringFromClass(view.class) hasSuffix:@"ConfirmationView"]) {
_confirmationView = view;
_deleteButton = [view.subviews objectAtIndex:0];
CGRect frame = _confirmationView.frame;
CGRect frame2 = frame;
frame.origin.x -= frame.size.width;
frame.size.width *= 2;
_confirmationView.frame = frame;
frame2.origin = CGPointZero;
_editButton.frame = frame2;
frame2.origin.x += frame2.size.width;
_deleteButton.frame = frame2;
[_confirmationView addSubview:_editButton];
break;
}
}
return;
}
}
-(void)_editTap {
UITableView *tv = (id)self.superview;
while(tv && ![tv isKindOfClass:[UITableView class]]) {
tv = (id)tv.superview;
}
id<UITableViewDelegate> delegate = tv.delegate;
if([delegate respondsToSelector:@selector(tableView:editTappedForRowWithIndexPath:)]) {
NSIndexPath *ip = [tv indexPathForCell:self];
// define this in your own protocol
[delegate tableView:tv editTappedForRowWithIndexPath:ip];
}
}
@end
이라는 놀라운 라이브러리가 있으며 SwipeCellKit
더 많은 인정을 받아야합니다. 내 생각에 그것은보다 시원하다 MGSwipeTableCell
. 후자는 Mail 앱의 셀 동작을 완전히 복제하지는 않지만 그렇지 SwipeCellKit
않습니다. 보세요
스위프트 4
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let delete = UIContextualAction(style: .destructive, title: "Delete") { (action, sourceView, completionHandler) in
print("index path of delete: \(indexPath)")
completionHandler(true)
}
let rename = UIContextualAction(style: .normal, title: "Edit") { (action, sourceView, completionHandler) in
print("index path of edit: \(indexPath)")
completionHandler(true)
}
let swipeActionConfig = UISwipeActionsConfiguration(actions: [rename, delete])
swipeActionConfig.performsFirstActionWithFullSwipe = false
return swipeActionConfig
}
간단한 해결책이 하나 있습니다. UITableViewCell 내에서 사용자 정의 UIView를 표시하고 숨길 수 있습니다. 표시 로직은 UITableViewCell, BaseTableViewCell에서 확장 된 클래스 내에 포함됩니다.
BaseTableViewCell.h
#import <UIKit/UIKit.h>
@interface BaseTableViewCell : UITableViewCell
@property(nonatomic,strong)UIView* customView;
-(void)showCustomView;
-(void)hideCustomView;
@end
BaseTableViewCell.M
#import "BaseTableViewCell.h"
@interface BaseTableViewCell()
{
BOOL _isCustomViewVisible;
}
@end
@implementation BaseTableViewCell
- (void)awakeFromNib {
// Initialization code
}
-(void)prepareForReuse
{
self.customView = nil;
_isCustomViewVisible = NO;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
-(void)showCustomView
{
if(nil != self.customView)
{
if(!_isCustomViewVisible)
{
_isCustomViewVisible = YES;
if(!self.customView.superview)
{
CGRect frame = self.customView.frame;
frame.origin.x = self.contentView.frame.size.width;
self.customView.frame = frame;
[self.customView willMoveToSuperview:self.contentView];
[self.contentView addSubview:self.customView];
[self.customView didMoveToSuperview];
}
__weak BaseTableViewCell* blockSelf = self;
[UIView animateWithDuration:.5 animations:^(){
for(UIView* view in blockSelf.contentView.subviews)
{
CGRect frame = view.frame;
frame.origin.x = frame.origin.x - blockSelf.customView.frame.size.width;
view.frame = frame;
}
}];
}
}
}
-(void)hideCustomView
{
if(nil != self.customView)
{
if(_isCustomViewVisible)
{
__weak BaseTableViewCell* blockSelf = self;
_isCustomViewVisible = NO;
[UIView animateWithDuration:.5 animations:^(){
for(UIView* view in blockSelf.contentView.subviews)
{
CGRect frame = view.frame;
frame.origin.x = frame.origin.x + blockSelf.customView.frame.size.width;
view.frame = frame;
}
}];
}
}
}
@end
이 기능을 사용하려면 BaseTableViewCell에서 테이블 뷰 셀을 간단히 확장하십시오.
다음으로 UITableViewDelegate를 구현하는 내부 UIViewController는 왼쪽 및 오른쪽 스 와이프를 처리하는 두 개의 제스처 인식기를 만듭니다.
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self.tableView registerNib:[UINib nibWithNibName:CUSTOM_CELL_NIB_NAME bundle:nil] forCellReuseIdentifier:CUSTOM_CELL_ID];
UISwipeGestureRecognizer* leftSwipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleLeftSwipe:)];
leftSwipeRecognizer.direction = UISwipeGestureRecognizerDirectionLeft;
[self.tableView addGestureRecognizer:leftSwipeRecognizer];
UISwipeGestureRecognizer* rightSwipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleRightSwipe:)];
rightSwipeRecognizer.direction = UISwipeGestureRecognizerDirectionRight;
[self.tableView addGestureRecognizer:rightSwipeRecognizer];
}
두 개의 스 와이프 핸들러를 추가하는 것보다
- (void)handleLeftSwipe:(UISwipeGestureRecognizer*)recognizer
{
CGPoint point = [recognizer locationInView:self.tableView];
NSIndexPath* index = [self.tableView indexPathForRowAtPoint:point];
UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:index];
if([cell respondsToSelector:@selector(showCustomView)])
{
[cell performSelector:@selector(showCustomView)];
}
}
- (void)handleRightSwipe:(UISwipeGestureRecognizer*)recognizer
{
CGPoint point = [recognizer locationInView:self.tableView];
NSIndexPath* index = [self.tableView indexPathForRowAtPoint:point];
UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:index];
if([cell respondsToSelector:@selector(hideCustomView)])
{
[cell performSelector:@selector(hideCustomView)];
}
}
이제 UITableViewDelegate의 cellForRowAtIndexPath 내부에서 사용자 정의 UIView를 작성하여 큐에 넣을 수 있습니다.
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCellTableViewCell* cell = (CustomCellTableViewCell*)[tableView dequeueReusableCellWithIdentifier:@"CustomCellTableViewCell" forIndexPath:indexPath];
NSArray* nibViews = [[NSBundle mainBundle] loadNibNamed:@"CellCustomView"
owner:nil
options:nil];
CellCustomView* customView = (CellCustomView*)[ nibViews objectAtIndex: 0];
cell.customView = customView;
return cell;
}
물론, 사용자 정의 UIView를로드하는이 방법은이 예제를위한 것입니다. 원하는대로 관리하십시오.
'IT story' 카테고리의 다른 글
CUDA 런타임 API를 사용하여 오류를 확인하는 정식 방법은 무엇입니까? (0) | 2020.04.07 |
---|---|
TypeError를 수정하는 방법 : 해시하기 전에 유니 코드 개체를 인코딩해야합니까? (0) | 2020.04.07 |
C ++ 11의 람다가 기본적으로 값별 캡처를 위해 "mutable"키워드를 요구하는 이유는 무엇입니까? (0) | 2020.04.07 |
PHP는 백그라운드 프로세스를 실행 (0) | 2020.04.07 |
Erlang은 어디에 사용되며 왜 그런가요? (0) | 2020.04.07 |