Я новичок в разработке iOS. Я хочу добавить галочку к себе, UITableViewCell
когда она выбрана. Галочку следует снимать при выборе другой строки. Как бы я это сделал?
Ответы:
Не используйте [tableview reloadData];
// это молоток.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
}
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
}
В вашем методе UITableViewDatasource:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil )
{
cell =[[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
}
if ([indexPath compare:self.lastIndexPath] == NSOrderedSame)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
// UITableView Delegate Method
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.lastIndexPath = indexPath;
[tableView reloadData];
}
И lastIndexPath - это property(strong) NSIndexPath* lastIndexPath;
Я обнаружил, что перезагрузка данных некрасиво прерывает анимацию отмены выбора.
Эта реализация Swift аккуратно добавляет / удаляет галочки и отменяет выбор строки:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if self.lastSelection != nil {
self.myTableView.cellForRowAtIndexPath(self.lastSelection)?.accessoryType = .None
}
self.myTableView.cellForRowAtIndexPath(indexPath)?.accessoryType = .Checkmark
self.lastSelection = indexPath
self.myTableView.deselectRowAtIndexPath(indexPath, animated: true)
}
где lastSelection
объявлено какvar lastSelection: NSIndexPath!
Никаких дополнительных действий не cellForRowAtIndexPath
требуется. Нетрудно воспроизвести в Obj-C.
Чтобы установить галочку:
UITableViewCell *cell = ...;
cell.accessoryType = UITableViewCellAccessoryCheckmark;
Чтобы выбрать / отменить выбор ячейки:
[cell setSelected:TRUE animated:TRUE]; // select
[cell setSelected:FALSE animated:TRUE]; // deselect
Чтобы отменить выбор предыдущей ячейки, используйте NSIndexPath * lastSelected ivar для отслеживания последней выбранной ячейки:
- (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
if (self.lastSelected==indexPath) return; // nothing to do
// deselect old
UITableViewCell *old = [self.tableView cellForRowAtIndexPath:self.lastSelected];
old.accessoryType = UITableViewCellAccessoryNone;
[old setSelected:FALSE animated:TRUE];
// select new
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[cell setSelected:TRUE animated:TRUE];
// keep track of the last selected cell
self.lastSelected = indexPath;
}
Обновить Swift 4
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath)?.accessoryType = .none
}
extension ViewController : UITableViewDelegate,UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.dataArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = dataArray[indexPath.row]
if selectedData.contains(dataArray[indexPath.row]) {
cell.accessoryType = .checkmark
}else{
cell.accessoryType = .none
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if selectedData.contains(dataArray[indexPath.row]) {
selectedData.removeLast()
tableView.cellForRow(at: indexPath)?.accessoryType = .none
}else {
selectedData.removeAll()
selectedData.append(dataArray[indexPath.row])
tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
print(selectedData)
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath)?.accessoryType = .none
}
}
на основе представления таблицы dataArray, сформированной ... аналогично, я взял пустой массив, и всякий раз, когда пользователь нажимает на ячейку, на основе indexValue из dataArray я сохранял этот объект в selectedDataArray
Что касается вопроса, это похоже на ... У вопроса есть несколько вариантов (ответов), но, в конце концов, будет только один или ни один ответ.
Точно так же только одна ячейка должна показывать галочку, а остальные ячейки должны быть невыделенными ... в некоторых случаях вы можете отменить выбор своего ответа ... Я надеюсь, что это лучший ответ на этот вопрос
Я думаю, что будет проще установить аксессуар в вашей пользовательской реализации UITableViewCell. В быстром темпе я использовал:
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
accessoryType = selected ? .checkmark : .none
}
Использование Swift 4.2 и Swift 5 Рабочий код галочки только для выбранной строки в TableView
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
self.tableView.cellForRow(at: indexPath)?.accessoryType = .none
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//print(self.coloursArray[indexPath.row])
self.tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
Предполагая, что вы принадлежите к классу, наследующему от UITableViewController
, в Swift 3 есть трюк:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Add a visual cue to indicate that the cell was selected.
self.tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
}
override func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
// Invoked so we can prepare for a change in selection.
// Remove previous selection, if any.
if let selectedIndex = self.tableView.indexPathForSelectedRow {
// Note: Programmatically deslecting does NOT invoke tableView(:didSelectRowAt:), so no risk of infinite loop.
self.tableView.deselectRow(at: selectedIndex, animated: false)
// Remove the visual selection indication.
self.tableView.cellForRow(at: selectedIndex)?.accessoryType = .none
}
return indexPath
}
небольшая опечатка
// deselect old
UITableViewCell *old = [self.tableView cellForRowAtIndexPath:self.lastSelected];
cell.accessoryType = UITableViewCellAccessoryNone;
[cell setSelected:FALSE animated:TRUE];
должен прочесть
// deselect old
UITableViewCell *old = [self.tableView cellForRowAtIndexPath:self.lastSelected];
old.accessoryType = UITableViewCellAccessoryNone;
[old setSelected:FALSE animated:TRUE];
а также в
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == [previouslySelected intValue])
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
selectedIndex = indexPath;
[cell setSelected:YES animated:YES];
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
[cell setSelected:NO animated:YES];
}
}
где previouslySelected ваш местный Ивара и т.д. Таким образом , если вы загрузите с выбранным индексом также получает выключенный когда вы пролистать возможные выборы.
Приведенные выше ответы не работают, если вы повторно использовали ячейку для большого количества данных. При прокрутке вы можете увидеть повторяющуюся галочку. Чтобы избежать использования следующих шагов:
объявить в переменной: var indexNumber: NSInteger = -1
Добавьте ниже код в cellforRowAtIndexPath:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
if indexNumber == indexPath.row{
cell.accessoryType = .checkmark
}else{
cell.accessoryType = .none
}
}
И в didselectAtIndexpath добавьте ниже код:
переопределить func tableView (_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath as IndexPath)?.accessoryType = .checkmark
indexNumber = indexPath.row
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath as IndexPath)?.accessoryType = .none
}
Лучше взглянуть на эту проблему с другой стороны. Положите всю работу на внутренние механизмы UIKit и перенесите реализацию в UITableViewCell:
@implementation MYTableViewCell
- (void)setSelected:(BOOL)selected animated:(BOOL)animated {
[super setSelected:selected animated:animated];
self.accessoryType = selected ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone;
}
- (void)prepareForReuse {
[super prepareForReuse];
self.accessoryType = UITableViewCellAccessoryNone;
}
@end
Просто вызовите didSelectRowAtIndexPath
метод, когда выберите любую строку, чтобы отобразить CheckMark, и выберите строку с галочкой, чтобы скрыть CheckMark.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath: (NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:true];
NSLog(@"touch");
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryNone)
{
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}
else
{
cell.accessoryType = UITableViewCellAccessoryNone;
}
}
swift 4 в случае необходимости.
var lastSelection: NSIndexPath!
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//CHECK MARK THE CELL
if self.lastSelection != nil {
self.tableView.cellForRow(at: self.lastSelection as IndexPath)?.accessoryType = .none
}
self.tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark
self.lastSelection = indexPath as NSIndexPath
self.tableView.deselectRow(at: indexPath, animated: true)
}
Есть два способа сделать это. один без множественного выбора, а другой с множественным выбором.
// Table View Controller -- without Multiple Selection
// Step 1
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if(tableView.cellForRow(at: indexPath)?.imageView?.image == UIImage(systemName:"checkmark.circle")) {
tableView.cellForRow(at: indexPath)?.imageView?.image = UIImage(systemName:"circle")
} else {
tableView.cellForRow(at: indexPath)?.imageView?.image = UIImage(systemName:"checkmark.circle")
}
}
//Step 2
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = employeeValues[indexPath.row]
cell.imageView?.image = UIImage(systemName:"circle")
return cell
}
// Table View Controller -- with Multiple Selection
@IBOutlet var myTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
self.myTableView.allowsMultipleSelection = true
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = employeeValues[indexPath.row]
cell.imageView?.image = UIImage(systemName:"circle")
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// let cell = tableView.cellForRow(at: indexPath)?.accessoryType = UITableViewCell.AccessoryType.checkmark
tableView.cellForRow(at: indexPath)?.imageView?.image = UIImage(systemName:"checkmark.circle")
}
override func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
tableView.cellForRow(at: indexPath)?.imageView?.image = UIImage(systemName:"circle")
}
Вышеупомянутый код работает только с одиночным выбором. Следующий код, несомненно, будет работать для множественного выбора .
- (void)viewDidLoad {
arrSelectionStatus =[NSMutableArray array]; //arrSelectionStatus holds the cell selection status
for (int i=0; i<arrElements.count; i++) { //arrElements holds those elements which will be populated in tableview
[arrSelectionStatus addObject:[NSNumber numberWithBool:NO]];
}
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
if (cell==nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
}
cell.textLabel.text=[arrElements objectAtIndex:indexPath.row];
if ([[arrSelectionStatus objectAtIndex:indexPath.row] boolValue] == YES)
cell.accessoryType = UITableViewCellAccessoryCheckmark;
else
cell.accessoryType = UITableViewCellAccessoryNone;
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
[arrSelectionStatus replaceObjectAtIndex:indexPath.row withObject:[NSNumber numberWithBool:YES]];
}
-(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryNone;
[arrSelectionStatus replaceObjectAtIndex:indexPath.row withObject:[NSNumber numberWithBool:NO]];
}
Когда выделенная ячейка (с галочкой снова выбрана), просто снимите выделение.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
BOOL isSelected = ([tableView cellForRowAtIndexPath:indexPath].accessoryType == UITableViewCellAccessoryCheckmark);
if(isSelected){
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
[tableView deselectRowAtIndexPath:indexPath animated:YES]; //this won't trigger the didDeselectRowAtIndexPath, but it's always a good idea to remove the selection
}else{
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryCheckmark;
}
}
- (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath*)indexPath
{
[tableView cellForRowAtIndexPath:indexPath].accessoryType = UITableViewCellAccessoryNone;
}
Бонус:
Использовать self.tableView.indexPathForSelectedRow
для определения indexPath для выбранной ячейки
// Check or Uncheck a cell
if let cell = tableView.cellForRow(at: indexPath) {
if cell.accessoryType == .checkmark {
cell.accessoryType = .none
} else {
cell.accessoryType = .checkmark
}
}