使用DatePicker展开和折叠UITableViewCells
我正在构build一个让用户从UITableView中selectdate的应用程序。 tableView是静态的和分组的。 我已经浏览了许多问题,包括这个问题,试图找出如何实现这一点 – 但似乎没有任何工作最佳。 苹果的日历应用程序function非常stream畅,漂亮的animation,没有任何我经历过的例子已经设法重新创build。
这是我想要的结果:
有人能指点我一个教程,或者解释我如何用最简洁直接的方式来完成这样一个stream畅的animation,就像我们在日历应用程序中看到的那样?
非常感谢!
埃里克
我假设你正在使用故事板,这个例子是与UIPickerView
:在包含你想要填充的文本单元的单元格下创build一个tableviewcell,并在检查器中设置单元格行高度为216.0,并添加一个UIPickerView到该单元格。
接下来通过Outlet将UIPickerView连接到您的viewcontroller,并将以下属性添加到您的ViewController.h:
@property (weak, nonatomic) IBOutlet UIPickerView *statusPicker; @property BOOL statusPickerVisible;
在你的ViewController.m中做viewWillAppear
self.statusPickerVisible = NO; self.statusPicker.hidden = YES; self.statusPicker.translatesAutoresizingMaskIntoConstraints = NO;
添加两个方法:
- (void)showStatusPickerCell { self.statusPickerVisible = YES; [self.tableView beginUpdates]; [self.tableView endUpdates]; self.statusPicker.alpha = 0.0f; [UIView animateWithDuration:0.25 animations:^{ self.statusPicker.alpha = 1.0f; } completion:^(BOOL finished){ self.statusPicker.hidden = NO; }];]; } - (void)hideStatusPickerCell { self.statusPickerVisible = NO; [self.tableView beginUpdates]; [self.tableView endUpdates]; [UIView animateWithDuration:0.25 animations:^{ self.statusPicker.alpha = 0.0f; } completion:^(BOOL finished){ self.statusPicker.hidden = YES; }]; }
在heightForRowAtIndexPath
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { CGFloat height = self.tableView.rowHeight; if (indexPath.row == 1){ height = self.statusPickerVisible ? 216.0f : 0.0f; } return height; }
在didSelectRowAtIndexPath
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { if (indexPath.row == 0) { if (self.statusPickerVisible){ [self hideStatusPickerCell]; } else { [self showStatusPickerCell]; } } [self.tableView deselectRowAtIndexPath:indexPath animated:YES]; }
上面的2个答案使我能够解决这个问题。 他们应该得到这个荣誉,我为自己提供了一个提醒 – 总结格式。
这是我的上述答案的版本。
1.如上所述 – 将拾取器添加到要显示/隐藏的单元格中。
2.在界面构build器中为选取器添加约束 – 将中心X / center Y /等于height / equal width添加到单元格的内容视图
3.将选取器连接到VC
@IBOutlet weak var dobDatePicker: UIDatePicker!
你也可以控制拖动并添加一个方法来注册date的变化
@IBAction func dateChanged(sender: UIDatePicker) { // updates ur label in the cell above dobLabel.text = "\(dobDatePicker.date)" }
4.在viewDidLoad中
dobDatePicker.date = NSDate() dobLabel.text = "\(dobDatePicker.date)" // my label in cell above dobDatePicker.hidden = true
5.设置单元格高度,在我的例子中,我要展开的单元格是第0行,第3行…将其设置为您想要展开/隐藏的单元格。 如果你有许多不同高度的细胞,就可以做到这一点。
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { if indexPath.section == 0 && indexPath.row == 3 { let height:CGFloat = dobDatePicker.hidden ? 0.0 : 216.0 return height } return super.tableView(tableView, heightForRowAtIndexPath: indexPath) }
6.select上面的单元格展开下面的单元格,再次将其设置到单元格,您将点击以显示下面的单元格。
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { let dobIndexPath = NSIndexPath(forRow: 2, inSection: 0) if dobIndexPath == indexPath { dobDatePicker.hidden = !dobDatePicker.hidden UIView.animateWithDuration(0.3, animations: { () -> Void in self.tableView.beginUpdates() // apple bug fix - some TV lines hide after animation self.tableView.deselectRowAtIndexPath(indexPath, animated: true) self.tableView.endUpdates() }) } }
我在Swift中实现了@ thorb65的答案,它的function就像一个魅力。 即使我设置了两个dateselect器(例如日历中的“开始”和“结束”),并设置它们使得打开的一个在展开另一个时自动折叠(即“一次最多打开一个”政策,就像日历),(并发)animation仍然平稳。
但是,我努力的一件事就是find正确的自动布局限制。 以下给了我与Calendar.app相同的行为:
来自UIDatePicker的约束:
- 高度
从UIDatePicker对UITableViewCell的内容视图的约束:
- 领先的空间到集装箱保证金
- 尾随空间到集装箱保证金
- 顶部空间到集装箱保证金
“底部空间到容器边距”被明确地排除在外,在animation中一直执行固定的高度(这重新创build了Calendar.app的行为,表格单元格“滑动打开”以显示下面不变的固定高度dateselect器)。
编辑:这是swift代码
属性:
// "Start Date" (first date picker) @IBOutlet weak var startDateLabel: UILabel! @IBOutlet weak var startDatePicker: UIDatePicker! var startDatePickerVisible:Bool? // "End Date" (second date picker) @IBOutlet weak var endDateLabel: UILabel! @IBOutlet weak var endDatePicker: UIDatePicker! var endDatePickerVisible:Bool? private var startDate:NSDate private var endDate:NSDate // Backup date labels' initial text color, to restore on collapse // (we change it to control tint while expanded, like calendar.app) private var dateLabelInitialTextColor:UIColor!
UIViewController方法:
override func viewDidLoad() { super.viewDidLoad() // Set pickers to their initial values (eg, "now" and "now + 1hr" ) startDatePicker.date = startDate startDateLabel.text = formatDate(startDate) endDatePicker.date = endDate endDateLabel.text = formatDate(endDate) // Backup (unselected) date label color dateLabelInitialTextColor = startDateLabel.textColor } override func viewWillAppear(animated: Bool) { super.viewWillAppear(animated) startDatePickerVisible = false startDatePicker.hidden = true endDatePickerVisible = false endDatePicker.hidden = true }
UITableViewDelegate方法:
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { var height:CGFloat = 44 // Default if indexPath.row == 3 { // START DATE PICKER ROW if let startDatePickerVisible = startDatePickerVisible { height = startDatePickerVisible ? 216 : 0 } } else if indexPath.row == 5 { // END DATE PICKER ROW if let endDatePickerVisible = endDatePickerVisible { height = endDatePickerVisible ? 216 : 0 } } return height } override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { switch indexPath.row { case 2: // [ A ] START DATE // Collapse the other date picker (if expanded): if endDatePickerVisible! { hideDatePickerCell(containingDatePicker: endDatePicker) } // Expand: if startDatePickerVisible! { hideDatePickerCell(containingDatePicker: startDatePicker) } else{ showDatePickerCell(containingDatePicker: startDatePicker) } case 4: // [ B ] END DATE // Collapse the other date picker (if expanded): if startDatePickerVisible!{ hideDatePickerCell(containingDatePicker: startDatePicker) } // Expand: if endDatePickerVisible! { hideDatePickerCell(containingDatePicker: endDatePicker) } else{ showDatePickerCell(containingDatePicker: endDatePicker) } default: break } tableView.deselectRowAtIndexPath(indexPath, animated: true) }
date选取器控制操作:
@IBAction func dateChanged(sender: AnyObject) { guard let picker = sender as? UIDatePicker else { return } let dateString = formatDate(picker.date) if picker == startDatePicker { startDateLabel.text = dateString } else if picker == endDatePicker { endDateLabel.text = dateString } }
辅助方法:(animation,date格式)
@IBAction func dateChanged(sender: AnyObject) { guard let picker = sender as? UIDatePicker else { return } let dateString = formatDate(picker.date) if picker == startDatePicker { startDateLabel.text = dateString } else if picker == endDatePicker { endDateLabel.text = dateString } } func showDatePickerCell(containingDatePicker picker:UIDatePicker) { if picker == startDatePicker { startDatePickerVisible = true startDateLabel.textColor = myAppControlTintColor } else if picker == endDatePicker { endDatePickerVisible = true endDateLabel.textColor = myAppControlTintColor } tableView.beginUpdates() tableView.endUpdates() picker.hidden = false picker.alpha = 0.0 UIView.animateWithDuration(0.25) { () -> Void in picker.alpha = 1.0 } } func hideDatePickerCell(containingDatePicker picker:UIDatePicker) { if picker == startDatePicker { startDatePickerVisible = false startDateLabel.textColor = dateLabelInitialTextColor } else if picker == endDatePicker { endDatePickerVisible = false endDateLabel.textColor = dateLabelInitialTextColor } tableView.beginUpdates() tableView.endUpdates() UIView.animateWithDuration(0.25, animations: { () -> Void in picker.alpha = 0.0 }, completion:{ (finished) -> Void in picker.hidden = true } ) }
只是想我还会加上我的两分钱。 我实际上是在Xamarin编程,必须做一些小的调整才能在Xamarin的框架下工作。
所有的原则都是一样的,但是Xamarin为TableViewSource使用了一个单独的类,因此委托的pipe理是不同的。 当然,如果你想在UIViewController中也可以分配UITableViewDelegates,但是我很好奇它是否能够以这种方式工作:
开始我分类date选取器单元格(datePickerCell)和select器单元格(selectorCell)。 我注意到,我没有一个StoryBoard以编程的方式完成这个任务
datePickerCell:
using System; using UIKit; namespace DatePickerInTableViewCell { public class CustomDatePickerCell : UITableViewCell { //======================================================================================================================================== // PRIVATE CLASS PROPERTIES //======================================================================================================================================== private UIDatePicker datePicker; private bool datePickerVisible; private Boolean didUpdateConstraints; //======================================================================================================================================== // PUBLIC CLASS PROPERTIES //======================================================================================================================================== public event EventHandler dateChanged; //======================================================================================================================================== // Constructor //======================================================================================================================================== /// <summary> /// Initializes a new instance of the <see cref="DatePickerInTableViewCell.CustomDatePickerCell"/> class. /// </summary> public CustomDatePickerCell (string rid) : base(UITableViewCellStyle.Default, rid) { Initialize (); } //======================================================================================================================================== // PUBLIC OVERRIDES //======================================================================================================================================== /// <summary> /// Layout the subviews. /// </summary> public override void LayoutSubviews () { base.LayoutSubviews (); ContentView.AddSubview (datePicker); datePicker.Hidden = true; AutoresizingMask = UIViewAutoresizing.FlexibleHeight | UIViewAutoresizing.FlexibleWidth; foreach (UIView view in ContentView.Subviews) { view.TranslatesAutoresizingMaskIntoConstraints = false; } ContentView.SetNeedsUpdateConstraints (); } /// <summary> /// We override the UpdateConstraints to allow us to only set up our constraint rules one time. Since /// we need to use this method to properly call our constraint rules at the right time we use a boolean /// as a flag so that we only fix our auto layout once. Afterwards UpdateConstraints runs as normal. /// </summary> public override void UpdateConstraints () { if (NeedsUpdateConstraints () && !didUpdateConstraints) { setConstraints (); didUpdateConstraints = true; } base.UpdateConstraints (); } //======================================================================================================================================== // PUBLIC METHODS //======================================================================================================================================== /// <summary> /// Allows us to determine the visibility state of the cell from the tableViewSource. /// </summary> /// <returns><c>true</c> if this instance is visible; otherwise, <c>false</c>.</returns> public bool IsVisible() { return datePickerVisible; } /// <summary> /// Allows us to show the datePickerCell from the tableViewSource. /// </summary> /// <param name="tableView">Table view.</param> public void showDatePicker(ref UITableView tableView) { datePickerVisible = true; tableView.BeginUpdates (); tableView.EndUpdates (); datePicker.Hidden = false; datePicker.Alpha = 0f; UIView.Animate( 0.25, ()=> { datePicker.Alpha = 1f;} ); } public void hideDatePicker(ref UITableView tableView) { datePickerVisible = false; tableView.BeginUpdates (); tableView.EndUpdates (); UIView.Animate( 0.25, ()=> { datePicker.Alpha = 0f;}, ()=> {datePicker.Hidden = true;} ); } //======================================================================================================================================== // PRIVATE METHODS //======================================================================================================================================== /// <summary> /// We make sure the UIDatePicker is center in the cell. /// </summary> private void setConstraints() { datePicker.CenterXAnchor.ConstraintEqualTo(ContentView.CenterXAnchor).Active = true; } /// <summary> /// Init class properties. /// </summary> private void Initialize() { datePicker = new UIDatePicker (); datePickerVisible = false; datePicker.TimeZone = Foundation.NSTimeZone.LocalTimeZone; datePicker.Calendar = Foundation.NSCalendar.CurrentCalendar; datePicker.ValueChanged += (object sender, EventArgs e) => { if(dateChanged != null) { dateChanged (datePicker, EventArgs.Empty); } }; } } }
select器单元
using System; using UIKit; namespace DatePickerInTableViewCell { ///<summary> /// ///</summary> public class CustomDatePickerSelectionCell : UITableViewCell { //======================================================================================================================================== // PRIVATE CLASS PROPERTIES //======================================================================================================================================== private UILabel prefixLabel; private UILabel dateLabel; private UILabel timeLabel; private Boolean didUpdateConstraints; private UIColor originalLableColor; private UIColor editModeLabelColor; //======================================================================================================================================== // PUBLIC CLASS PROPERTIES //======================================================================================================================================== //======================================================================================================================================== // Constructor //======================================================================================================================================== /// <summary> /// Initializes a new instance of the <see cref="DatePickerInTableViewCell.CustomDatePickerSelectionCell"/> class. /// </summary> public CustomDatePickerSelectionCell (string rid) : base(UITableViewCellStyle.Default, rid) { Initialize (); } //======================================================================================================================================== // PUBLIC OVERRIDES //======================================================================================================================================== /// <summary> /// We override the UpdateConstraints to allow us to only set up our constraint rules one time. Since /// we need to use this method to properly call our constraint rules at the right time we use a boolean /// as a flag so that we only fix our auto layout once. Afterwards UpdateConstraints runs as normal. /// </summary> public override void UpdateConstraints () { if (NeedsUpdateConstraints () && !didUpdateConstraints) { setConstraints (); didUpdateConstraints = true; } base.UpdateConstraints (); } public override void LayoutSubviews () { base.LayoutSubviews (); AutoresizingMask = UIViewAutoresizing.FlexibleHeight | UIViewAutoresizing.FlexibleWidth; timeLabel.TextAlignment = UITextAlignment.Right; prefixLabel.Text = "On: "; dateLabel.Text = DateTime.Now.ToString ("MMM d, yyyy"); timeLabel.Text = DateTime.Now.ToShortTimeString (); ContentView.AddSubviews (new UIView[]{ prefixLabel, dateLabel, timeLabel }); foreach (UIView view in ContentView.Subviews) { view.TranslatesAutoresizingMaskIntoConstraints = false; } ContentView.SetNeedsUpdateConstraints (); } //======================================================================================================================================== // PUBLIC METHODS //======================================================================================================================================== public void willUpdateDateTimeLables(string date, string time) { dateLabel.Text = date; timeLabel.Text = time; } public void willEditDateTime() { dateLabel.TextColor = editModeLabelColor; timeLabel.TextColor = editModeLabelColor; } public void didEditDateTime() { dateLabel.TextColor = originalLableColor; timeLabel.TextColor = originalLableColor; } //======================================================================================================================================== // PRIVATE METHODS //======================================================================================================================================== private void Initialize() { prefixLabel = new UILabel (); dateLabel = new UILabel (); timeLabel = new UILabel (); originalLableColor = dateLabel.TextColor; editModeLabelColor = UIColor.Red; } private void setConstraints() { var cellMargins = ContentView.LayoutMarginsGuide; prefixLabel.LeadingAnchor.ConstraintEqualTo (cellMargins.LeadingAnchor).Active = true; dateLabel.LeadingAnchor.ConstraintEqualTo (prefixLabel.TrailingAnchor).Active = true; timeLabel.LeadingAnchor.ConstraintEqualTo (dateLabel.TrailingAnchor).Active = true; timeLabel.TrailingAnchor.ConstraintEqualTo (cellMargins.TrailingAnchor).Active = true; dateLabel.WidthAnchor.ConstraintEqualTo (ContentView.WidthAnchor, 2f / 7f).Active = true; prefixLabel.HeightAnchor.ConstraintEqualTo (ContentView.HeightAnchor, 1).Active = true; timeLabel.HeightAnchor.ConstraintEqualTo (ContentView.HeightAnchor, 1).Active = true; dateLabel.HeightAnchor.ConstraintEqualTo (ContentView.HeightAnchor, 1).Active = true; } } }
所以你可以看到我有一些方法暴露每个细胞,以方便所需的沟通。 然后我需要在我的tableViewSource中创build这些单元格的一个实例。 也许这样做的耦合方式较less,但我不能轻易弄清楚。 我相信我在iOS编程方面的经验比以前的我的前辈less了:)。 也就是说,使用类范围内的单元格可以很容易地调用和访问RowSelected和GetHeightForRow方法中的单元格。
TableViewSource
using System; using UIKit; using System.Collections.Generic; namespace DatePickerInTableViewCell { public class TableViewSource : UITableViewSource { //======================================================================================================================================== // PRIVATE CLASS PROPERTIES //======================================================================================================================================== private const string datePickerIdentifier = "datePickerCell"; private const string datePickerActivateIdentifier = "datePickerSelectorCell"; private const int datePickerRow = 1; private const int datePickerSelectorRow = 0; private List<UITableViewCell> datePickerCells; private CustomDatePickerCell datePickerCell; private CustomDatePickerSelectionCell datePickerSelectorCell; //======================================================================================================================================== // PUBLIC CLASS PROPERTIES //======================================================================================================================================== //======================================================================================================================================== // Constructor //======================================================================================================================================== /// <summary> /// Initializes a new instance of the <see cref="DatePickerInTableViewCell.TableViewSource"/> class. /// </summary> public TableViewSource () { initDemoDatePickerCells (); } //======================================================================================================================================== // PUBLIC OVERRIDES //======================================================================================================================================== public override UITableViewCell GetCell (UITableView tableView, Foundation.NSIndexPath indexPath) { UITableViewCell cell = null; if (indexPath.Row == datePickerSelectorRow) { cell = tableView.DequeueReusableCell (datePickerActivateIdentifier); cell = cell ?? datePickerCells[indexPath.Row]; return cell; } if (indexPath.Row == datePickerRow) { cell = tableView.DequeueReusableCell (datePickerIdentifier) as CustomDatePickerCell; cell = cell ?? datePickerCells[indexPath.Row]; return cell; } return cell; } public override nint RowsInSection (UITableView tableview, nint section) { return datePickerCells.Count; } public override nfloat GetHeightForRow (UITableView tableView, Foundation.NSIndexPath indexPath) { float height = (float) tableView.RowHeight; if (indexPath.Row == datePickerRow) { height = datePickerCell.IsVisible () ? DefaultiOSDimensions.heightForDatePicker : 0f; } return height; } public override void RowSelected (UITableView tableView, Foundation.NSIndexPath indexPath) { if (indexPath.Row == datePickerSelectorRow) { if (datePickerCell != null) { if (datePickerCell.IsVisible ()) { datePickerCell.hideDatePicker (ref tableView); datePickerSelectorCell.didEditDateTime (); } else { datePickerCell.showDatePicker (ref tableView); datePickerSelectorCell.willEditDateTime (); } } } tableView.DeselectRow (indexPath, true); } //======================================================================================================================================== // PUBLIC METHODS //======================================================================================================================================== //======================================================================================================================================== // PRIVATE METHODS //======================================================================================================================================== private void willUpdateDateChanged(Object sender, EventArgs args) { var picker = sender as UIDatePicker; var dateTime = picker.Date.ToDateTime (); if (picker != null && dateTime != null) { var date = dateTime.ToString ("MMM d, yyyy"); var time = dateTime.ToShortTimeString (); datePickerSelectorCell.willUpdateDateTimeLables (date, time); } } private void initDemoDatePickerCells() { datePickerCell = new CustomDatePickerCell (datePickerIdentifier); datePickerSelectorCell = new CustomDatePickerSelectionCell (datePickerActivateIdentifier); datePickerCell.dateChanged += willUpdateDateChanged; datePickerCells = new List<UITableViewCell> () { datePickerSelectorCell, datePickerCell }; } } }
希望代码是相当自我解释。 toDateTime btw方法只是将NSDateTime转换为.net DateTime对象的扩展方法。 该参考可以在这里find: https ://forums.xamarin.com/discussion/27184/convert-nsdate-to-datetime和DefaultiOSDimensions只是一个小的静态类,我用来跟踪典型的尺寸,如cellHeight(44pts )或在heightForDatePicker
的情况下; 在我的模拟器上,它似乎对我很好。 我还没有testing它的实际设备。 希望它可以帮助别人!
我也一直在努力,我想我可能会分享我的解决scheme,这是从这里已经提供的解决scheme。
我注意到在其他例子中有很多特定于个别元素的代码,所以我做的是创build一个“经理”类来处理任何项目。
这是我做的:
CellShowHideDetail
存储您想要显示或隐藏的项目的详细信息。 这些细节包括它所在的单元格,以及将被点击来切换显示和隐藏的单元格:
public class CellShowHideDetail { var item: UIView var indexPath_ToggleCell: IndexPath var indexPath_ItemCell: IndexPath var desiredHeight: CGFloat init(item: UIView, indexPath_ToggleCell: IndexPath, indexPath_ItemCell: IndexPath, desiredHeight: CGFloat) { self.item = item self.indexPath_ToggleCell = indexPath_ToggleCell self.indexPath_ItemCell = indexPath_ItemCell self.desiredHeight = desiredHeight //By default cells are not expanded: self.item.isHidden = true } }
请注意, UIView
是大多数(所有?)UI元素的父类。
接下来,我们有经理,这将处理尽可能多的这些项目,只要你喜欢:
import Foundation import UIKit public class CellShowHideManager { var cellItems: [CellShowHideDetail] init() { cellItems = [] } func addItem(item: CellShowHideDetail) { cellItems.append(item) } func getRowHeight(indexPath: IndexPath) -> (match: Bool, height: CGFloat) { for item in cellItems { if indexPath.section == item.indexPath_ItemCell.section && indexPath.row == item.indexPath_ItemCell.row { return (match: true, height: item.item.isHidden ? 0.0 : item.desiredHeight) } } return (match: false, height: 0) } func rowSelected(indexPath: IndexPath) -> Bool { var changesMade = false for item in cellItems { if item.indexPath_ToggleCell == indexPath { item.item.isHidden = !item.item.isHidden changesMade = true } else { if item.item.isHidden == false { changesMade = true } item.item.isHidden = true } } return changesMade } }
然后,您可以在任何UITableViewController
类上轻松创buildCellShowHideManager
,添加您想要切换的项目:
var showHideManager = CellShowHideManager() override func viewDidLoad() { super.viewDidLoad() let item1ToShowHide = CellShowHideDetail(item: datePicker, indexPath_ToggleCell: IndexPath(row: 0, section: 0), indexPath_ItemCell: IndexPath(row: 1, section: 0), desiredHeight: 232.0) let item2ToShowHide = CellShowHideDetail(item: selection_Picker, indexPath_ToggleCell: IndexPath(row: 0, section: 1), indexPath_ItemCell: IndexPath(row: 1, section: 1), desiredHeight: 90.0) //Add items for the expanding cells: showHideManager.addItem(item: item1ToShowHide) showHideManager.addItem(item: item2ToShowHide) }
最后只需重写这两个TableView
方法,如下所示:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { let showHideResult = showHideManager.getRowHeight(indexPath: indexPath) if showHideResult.match { return showHideResult.height } else { return super.tableView(tableView, heightForRowAt: indexPath) } } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { if showHideManager.rowSelected(indexPath: indexPath) { UIView.animate(withDuration: 0.3, animations: { () -> Void in self.tableView.beginUpdates() // apple bug fix - some TV lines hide after animation //self.tableView.deselectRowAt(indexPath, animated: true) self.tableView.endUpdates() }) } }
它应该很好地工作!
我分享我的答案:
我做的一切都没有故事板
Swift 3
1.1添加datePicker
var travelDatePicker: UIDatePicker = { let datePicker = UIDatePicker() datePicker.timeZone = NSTimeZone.local datePicker.backgroundColor = UIColor.white datePicker.layer.cornerRadius = 5.0 datePicker.datePickerMode = .date datePicker.addTarget(self, action: #selector(TableViewController.datePickerValueChanged(_:)), for: .valueChanged) return datePicker }()
1.2及其方法
func datePickerValueChanged(_ sender: UIDatePicker){ let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd" let dateString = dateFormatter.string(from: travelDatePicker.date) self.shareCell.textLabel?.text = "\(dateString)" print("changed") print("Selected value \(dateString)") }
2.然后在loadView中用格式在上面的单元格中显示date
let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd" let dateString = dateFormatter.string(from: travelDatePicker.date) self.shareCell.textLabel?.text = "\(dateString)" travelDatePicker.isHidden = true
3.将datePicker添加到单元格
self.datePickerCell.backgroundColor = UIColor.red self.datePickerCell.addSubview(self.travelDatePicker) self.travelDatePicker.frame = CGRect(x: 0, y: 0, width: 500, height: 216) self.datePickerCell.accessoryType = UITableViewCellAccessoryType.none
4.设置单元格的高度
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { if indexPath.section == 1 && indexPath.row == 1{ let height: CGFloat = travelDatePicker.isHidden ? 0.0 : 216.0 return height } return 44.0 }
- 最后在didSelectAt中设置if语句
if(indexPath.section == 1 && indexPath.row == 0){
travelDatePicker.isHidden = !travelDatePicker.isHidden UIView.animate(withDuration: 0.3, animations: { () -> Void in self.tableView.beginUpdates() // apple bug fix - some TV lines hide after animation self.tableView.deselectRow(at: indexPath, animated: true) self.tableView.endUpdates() }) }
完整的代码在这里与其他元素只是得到一个工作的应用程序的感觉
import Foundation import UIKit class TableViewController: UITableViewController { var firstNameCell: UITableViewCell = UITableViewCell() var lastNameCell: UITableViewCell = UITableViewCell() var shareCell: UITableViewCell = UITableViewCell() var datePickerCell: UITableViewCell = UITableViewCell() var cityToCell: UITableViewCell = UITableViewCell() var cityFromCell: UITableViewCell = UITableViewCell() var firstNameText: UITextField = UITextField() var lastNameText: UITextField = UITextField() var travelDatePicker: UIDatePicker = { let datePicker = UIDatePicker() datePicker.timeZone = NSTimeZone.local datePicker.backgroundColor = UIColor.white datePicker.layer.cornerRadius = 5.0 datePicker.datePickerMode = .date datePicker.addTarget(self, action: #selector(TableViewController.datePickerValueChanged(_:)), for: .valueChanged) return datePicker }() override func loadView() { super.loadView() let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd" let dateString = dateFormatter.string(from: travelDatePicker.date) self.shareCell.textLabel?.text = "\(dateString)" travelDatePicker.isHidden = true // set the title self.title = "User Options" // construct first name cell, section 0, row 0 self.firstNameCell.backgroundColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 0.5) self.firstNameText = UITextField(frame: self.firstNameCell.contentView.bounds.insetBy(dx: 15, dy: 0)) self.firstNameText.placeholder = "First Name" self.firstNameCell.addSubview(self.firstNameText) // construct last name cell, section 0, row 1 self.lastNameCell.backgroundColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 0.5) self.lastNameText = UITextField(frame: self.lastNameCell.contentView.bounds.insetBy(dx: 15, dy: 0)) self.lastNameText.placeholder = "Last Name" self.lastNameCell.addSubview(self.lastNameText) // construct share cell, section 1, row 0 self.shareCell.backgroundColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 0.5) self.shareCell.accessoryType = UITableViewCellAccessoryType.checkmark self.datePickerCell.backgroundColor = UIColor.red self.datePickerCell.addSubview(self.travelDatePicker) self.travelDatePicker.frame = CGRect(x: 0, y: 0, width: 500, height: 216) self.datePickerCell.accessoryType = UITableViewCellAccessoryType.none self.cityToCell.textLabel?.text = "Kiev" self.cityToCell.backgroundColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 0.5) self.cityToCell.accessoryType = UITableViewCellAccessoryType.none self.cityFromCell.textLabel?.text = "San Francisco" self.cityFromCell.backgroundColor = UIColor(red: 1.0, green: 1.0, blue: 1.0, alpha: 0.5) self.cityFromCell.accessoryType = UITableViewCellAccessoryType.none } func datePickerValueChanged(_ sender: UIDatePicker){ let dateFormatter = DateFormatter() dateFormatter.dateFormat = "yyyy-MM-dd" let dateString = dateFormatter.string(from: travelDatePicker.date) self.shareCell.textLabel?.text = "\(dateString)" print("changed") print("Selected value \(dateString)") } // Return the number of sections override func numberOfSections(in tableView: UITableView) -> Int { return 2 } // Return the number of rows for each section in your static table override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { switch(section) { case 0: return 2 // section 0 has 2 rows case 1: return 4 // section 1 has 1 row default: fatalError("Unknown number of sections") } } override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { if indexPath.section == 1 && indexPath.row == 1{ let height: CGFloat = travelDatePicker.isHidden ? 0.0 : 216.0 return height } return 44.0 } // Return the row for the corresponding section and row override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { switch(indexPath.section) { case 0: switch(indexPath.row) { case 0: return self.firstNameCell // section 0, row 0 is the first name case 1: return self.lastNameCell // section 0, row 1 is the last name default: fatalError("Unknown row in section 0") } case 1: switch(indexPath.row) { case 0: return self.shareCell // section 1, row 0 is the share option case 1: return self.datePickerCell case 2: return self.cityToCell case 3: return self.cityFromCell default: fatalError("Unknown row in section 1") } default: fatalError("Unknown section") } } // Customize the section headings for each section override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { switch(section) { case 0: return "Profile" case 1: return "Social" default: fatalError("Unknown section") } } // Configure the row selection code for any cells that you want to customize the row selection override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { // Handle social cell selection to toggle checkmark if(indexPath.section == 1 && indexPath.row == 0) { // deselect row tableView.deselectRow(at: indexPath as IndexPath, animated: false) // toggle check mark if(self.shareCell.accessoryType == UITableViewCellAccessoryType.none) { self.shareCell.accessoryType = UITableViewCellAccessoryType.checkmark; } else { self.shareCell.accessoryType = UITableViewCellAccessoryType.none; } } if(indexPath.section == 1 && indexPath.row == 0) { travelDatePicker.isHidden = !travelDatePicker.isHidden UIView.animate(withDuration: 0.3, animations: { () -> Void in self.tableView.beginUpdates() // apple bug fix - some TV lines hide after animation self.tableView.deselectRow(at: indexPath, animated: true) self.tableView.endUpdates() }) } } }