Managing Selections
管理选择
When users tap a row of a table view, usually something happens as a result. Another table view could slide into place, the row could display a checkmark, or some other action could be performed. The following sections describe how to respond to selections and how to make selections programmatically.
当用户点击表格视图的一行时,通常会发生一些事情。 另一个表格视图可以滑入到位,行可以显示一个勾选标记,或者其它一些操作可能执行。 以下章节描述了如何响应选择以及如何通过程序做选择。
Selections in Table Views
一、在表格视图中选择
There are a few human-interface guidelines to keep in mind when dealing with cell selection in table views:
当你在表格视图里处理单元格选择时一些人机界面(human-interface)指南需要牢记:
-
You should never use selection to indicate state. Instead, use check marks and accessory views for showing state.
你绝不应该使用选择来表示状态。作为替代,你可以使用复选标记和辅助视图来显示状态。
-
When the user selects a cell, you should respond by deselecting the previously selected cell (by calling the
deselectRowAtIndexPath:animated:
method) as well as by performing any appropriate action, such as displaying a detail view.当用户选择一个单元格,你应该通过取消选择前一个被选择的单元格来响应(通过调用deselectRowAtIndexPath:animated:方法),以及通过执行任何正确的操作,比如显示一个详细视图等。
-
If you respond to the the selection of a cell by pushing a new view controller onto the navigation controller’s stack, you should deselect the cell (with animation) when the view controller is popped off the stack.
如果你通过把一个新的视图控制器压入导航控制器栈来响应一个单元格的选择, 那么当视图控制器从栈中弹出时,你应该取消选择单元格(用动画)。
You can control whether rows are selectable when the table view is in editing mode by setting the allowsSelectionDuringEditing
property of UITableView
. In addition, beginning with iOS 3.0, you can control whether cells are selectable when editing mode is not in effect by setting the allowsSelection
property.
当表格视图处于编辑模式时,你可以通过设置UITableView的allowsSelectionDuringEditing 特性来控制行是否可选择。 此外,从iOS3.0开始,当编辑模式不受allowsSelection特性的设置影响时,你可以控制单元格是否可选。
Responding to Selections
二、响应选择
Users tap a row in a table view either to signal to the application that they want to know more about what that row signifies or to select what the row represents. In response to the user tapping a row, an application could do any of the following:
用户在表格视图里点击一行来提示应用程序他们想要了解该行的更多信息或者来选择该行所代表的内容。 应用程序可以实现以下任何操作来响应用户点击一行:
-
Show the next level in a data-model hierarchy.
显示数据模型层次中的下一层。
-
Show a detail view of an item (that is, a leaf node of the data-model hierarchy).
显示一个数据项的详细视图(就是数据模型层次的一个叶节点)。
-
Show a checkmark in the row to indicate that the represented item is selected.
在行中显示一个复选标记来表明代表数据项被选中。
-
If the touch occurred in a control embedded in the row, it could respond to the action message sent by the control.
如果点击发生在一行中内嵌的控件中,它可以响应该控件发送的操作消息。
To handle most selections of rows, the table view’s delegate must implement the tableView:didSelectRowAtIndexPath:
method. In sample method implementation shown in Listing 6-1, the delegate first deselects the selected row. Then it allocates and initializes an instance of the next table-view controller in the sequence. It sets the data this view controller needs to populate its table view and then pushes this object onto the stack maintained by the application’sUINavigationController
object.
要想处理大多数行的选择,表格视图的委托必须实现tableView:didSelectRowAtIndexPath: 方法。 在列表6-1中显示了一个示例方法实现,委托首先取消选择被选择的行。 然后它在队列中分配和初始化下一个表格视图控制器的实例。 它设置该视图控制器用来填充(populate)其表格视图的数据,然后通过应用程序的UINavigationController对象把该对象压入栈。
Responding to a row selection
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath |
{ |
[tableView deselectRowAtIndexPath:indexPath animated:NO]; |
BATTrailsViewController *trailsController = [[BATTrailsViewController alloc] initWithStyle:UITableViewStylePlain]; |
trailsController.selectedRegion = [regions objectAtIndex:indexPath.row]; |
[[self navigationController] pushViewController:trailsController animated:YES]; |
} |
If a row has a disclosure control—the white chevron over a blue circle—for an accessory view, clicking the control results in the delegate receiving atableView:accessoryButtonTappedForRowWithIndexPath:
message (instead of tableView:didSelectRowAtIndexPath:
). The delegate responds to this message in the same general way as it does for other kinds of selections.
如果行中有一个下拉控件(disclosure control)---蓝色圈圈里有一个白色v型标记---表示一个附属视图,在tableView:accessoryButtonTappedForRowWithIndexPath: 消息(而不是在tableView:didSelectRowAtIndexPath:)中接收到的委托中点击控件结果。委托以跟别的类型的选择一样的通用方式响应该消息。
A row can also have a control object as its accessory view, such as a switch or a slider. This control object functions as it would in any other context: Manipulating the object in the proper way results in an action message being sent to a target object. Listing 6-2 illustrates a data source object that adds a UISwitch
object as a cell’s accessory view and then responds to the action messages sent when the switch is “flipped.”
行还可以有一个控件对象作为它的辅助视图,比如一个开关或一个滑动条。 该控件对象跟它在其它上下文(context)中有一样的功能:以正确的方式操作对象让某个动作消息被发送到某个目标对象。 列表6-2 演示了一个数据源对象,它添加一个UISwitch 对象作为一个单元格的辅助视图,然后当开关被按下时响应操作消息。
Setting a switch object as an accessory view and responding to its action message
列表6-2 把一个开关对象设置为一个辅助视图并响应它的操作消息。
- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath { |
UITableViewCell *cell = [tv dequeueReusableCellWithIdentifier:@"CellWithSwitch"]; |
if (cell == nil) { |
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"CellWithSwitch"]; |
cell.selectionStyle = UITableViewCellSelectionStyleNone; |
cell.textLabel.font = [UIFont systemFontOfSize:14]; |
} |
UISwitch *switchObj = [[UISwitch alloc] initWithFrame:CGRectMake(1.0, 1.0, 20.0, 20.0)]; |
switchObj.on = YES; |
[switchObj addTarget:self action:@selector(toggleSoundEffects:) forControlEvents:(UIControlEventValueChanged | UIControlEventTouchDragInside)]; |
cell.accessoryView = switchObj; |
cell.textLabel.text = @"Sound Effects"; |
return cell; |
} |
- (void)toggleSoundEffects:(id)sender { |
[self.soundEffectsOn = [(UISwitch *)sender isOn]; |
[self reset]; |
} |
You may also define controls as accessory views of table-view cells created in Interface Builder. Drag a control object (switch, slider, and so on) into anib document window containing a table-view cell. Then, using the connection window, make the control the accessory view of the cell. “Loading Table View Cells from a Storyboard” describes the procedure for creating and configuring table-view cell objects in nib files.
你还可以在界面生成器里定义各种控件成为表格视图单元格的辅助视图。 把一个控件对象(开关,滑动条等等)拖到包含一个表格视图单元格的nib文件窗口中。 然后使用连接窗口(connection window)设置单元格的辅助视图控件。 “Loading Table View Cells from a Storyboard” 描述了如何在nib文件中创建和配置表格视图单元格对象。
Selection management is also important with selection lists. There are two kinds of selection lists:
选择管理对于选择列表同样重要。 以下是两种选择列表:
-
Exclusive lists where only one row is permitted the checkmark
单元列表只允许选中一行。
-
Inclusive lists where more than one row can have a checkmark
多选列表允许选中多行。
Listing 6-3 illustrates one approach to managing an exclusive selection list. It first deselects the currently selected row and returns if the same row is selected; otherwise it sets the checkmark accessory type on the newly selected row and removes the checkmark on the previously selected row
列表6-3 显示了管理一个单选列表的方法。 如果选中了同一行,它首先取消选择单前被选择的行,然后返回;否则它给新选择的行打上勾,并取消之前被选择行中的勾。
Managing a selection list—exclusive list
列表 6-3 管理一个选择列表---单选列表
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { |
[tableView deselectRowAtIndexPath:indexPath animated:NO]; |
NSInteger catIndex = [taskCategories indexOfObject:self.currentCategory]; |
if (catIndex == indexPath.row) { |
return; |
} |
NSIndexPath *oldIndexPath = [NSIndexPath indexPathForRow:catIndex inSection:0]; |
UITableViewCell *newCell = [tableView cellForRowAtIndexPath:indexPath]; |
if (newCell.accessoryType == UITableViewCellAccessoryNone) { |
newCell.accessoryType = UITableViewCellAccessoryCheckmark; |
self.currentCategory = [taskCategories objectAtIndex:indexPath.row]; |
} |
UITableViewCell *oldCell = [tableView cellForRowAtIndexPath:oldIndexPath]; |
if (oldCell.accessoryType == UITableViewCellAccessoryCheckmark) { |
oldCell.accessoryType = UITableViewCellAccessoryNone; |
} |
} |
Listing 6-4 illustrates how to manage a inclusive selection list. As the comments in this example indicate, when the delegate adds a checkmark to a row or removes one, it typically also sets or unsets any associated model-object attribute.
列表 6-4 演示了如何管理一个多选列表。 正如在该例子中的注释所示,当委托给一行添加勾选标记或删除一个勾选标记时,通常还会设置或取消设置任何相关的模型对象属性。
Managing a selection list—inclusive list
列表 6-4 管理一个选择列表--多选列表
- (void)tableView:(UITableView *)theTableView |
didSelectRowAtIndexPath:(NSIndexPath *)newIndexPath { |
[theTableView deselectRowAtIndexPath:[theTableView indexPathForSelectedRow] animated:NO]; |
UITableViewCell *cell = [theTableView cellForRowAtIndexPath:newIndexPath]; |
if (cell.accessoryType == UITableViewCellAccessoryNone) { |
cell.accessoryType = UITableViewCellAccessoryCheckmark; |
// Reflect selection in data model |
} else if (cell.accessoryType == UITableViewCellAccessoryCheckmark) { |
cell.accessoryType = UITableViewCellAccessoryNone; |
// Reflect deselection in data model |
} |
} |
In tableView:didSelectRowAtIndexPath:
you should always deselect the currently selected row.
在tableView:didSelectRowAtIndexPath: 中,你应该总是取消选择当前已被选择的行。
Programmatically Selecting and Scrolling
三、通过程序实现选择和滚动
Occasionally the selection of a row originates within the application itself rather than from a tap in a table view. There could be an externally induced change in the data model. For example, the user adds a new person to an address book and then returns to the list of contacts; the application wants to scroll this list to the recently added person. For situations like these, you can use the UITableView
methods selectRowAtIndexPath:animated:scrollPosition:
and (if the row is already selected) scrollToNearestSelectedRowAtScrollPosition:animated:
. You may also call scrollToRowAtIndexPath:atScrollPosition:animated:
if you want to scroll to a specific row without selecting it.
行的选择偶尔会在应用程序由自身激活而不是在一个表格视图的一个点击。 它有可能是在数据模型中由外部引发的变化。 比如,用户给联络簿里添加了一个新人,然后返回到联系人列表;应用程序想要把列表滚动到最近添加的联系人那。 对已类似这样的情况,你可以使用UITableView方法selectRowAtIndexPath:animated:scrollPosition: 以及(如果行已被选择)scrollToNearestSelectedRowAtScrollPosition:animated:
. 方法。 如果你想要把列表滚动到某行但不选择它,你还可以调用scrollToRowAtIndexPath:atScrollPosition:animated: 方法。
The code in Listing 6-5 (somewhat whimsically) programmatically selects and scrolls to a row 20 rows away from the just-selected row using theselectRowAtIndexPath:animated:scrollPosition:
method.
列表6-5中的代码通过selectRowAtIndexPath:animated:scrollPosition: 方法 实现列表从刚选择的行
滚动到第20行并选择该行。
Programmatically selecting a row
列表6-5 通过程序选择某行
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)newIndexPath { |
NSIndexPath *scrollIndexPath; |
if (newIndexPath.row + 20 < [timeZoneNames count]) { |
scrollIndexPath = [NSIndexPath indexPathForRow:newIndexPath.row+20 inSection:newIndexPath.section]; |
} else { |
scrollIndexPath = [NSIndexPath indexPathForRow:newIndexPath.row-20 inSection:newIndexPath.section]; |
} |
[theTableView selectRowAtIndexPath:scrollIndexPath animated:YES |
scrollPosition:UITableViewScrollPositionMiddle]; |
} |