向左或向右滑动以加载带有集合视图单元高亮的视图控制器
Swipe left or right to load the view controller with the collection view cell highlight
我有 3 个名为 firstvc, secondvc, thirdvc
的视图控制器。我有一个水平滚动的集合视图。如果我 select 我的 first cell
我的 firstvc
将显示在我的 mainviewcontroller
的子视图中。 2, 3rd cell
也一样。很好.
现在我需要一个功能,例如,如果我滑动我的 subview
,当我 select 访问任何单元格时,它将拥有我所有的视图控制器。我需要添加向左或向右滑动。
例如:
如果我在 firstvc
,那么我的 first cell
将是 selected。现在,如果我将我的 subview
向右滑动,我的 secondvc
必须是平均的,而我的第二个集合视图单元格也必须是 highlight
不知道怎么玩
我的代码:
@IBOutlet weak var collectionview: UICollectionView!
@IBOutlet weak var contentSubView: UIView!
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.items.count
}
// make a cell for each cell index path
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// get a reference to our storyboard cell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath as IndexPath) as! MyCollectionViewCell
// Use the outlet in our custom class to get a reference to the UILabel in the cell
cell.myLabel.text = self.items[indexPath.item]
// cell.backgroundColor = UIColor.cyan // make cell more visible in our example project
var borderColor: UIColor! = UIColor.clear
//var borderWidth: CGFloat = 0
if indexPath == selectedIndexPath{
borderColor = UIColor.red
//borderWidth = 1 //or whatever you please
}else{
borderColor = UIColor.white
// borderWidth = 0
}
cell.myview.backgroundColor = borderColor
// cell.myview.layer.borderWidth = borderColor
return cell
}
// MARK: - UICollectionViewDelegate protocol
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("You selected cell #\(indexPath.item)!")
//based on your comment remove the subviews before add on your myview
//let cell = collectionView.cellForItemAtIndexPath(indexPath) as! MyCollectionViewCell
selectedIndexPath = indexPath
for subview in contentSubView.subviews {
subview.removeFromSuperview()
}
let alertStoryBoard = UIStoryboard(name: "Main", bundle: nil)
var controller: UIViewController!
if indexPath.item == 0 {
if let allCollectionViewController = alertStoryBoard.instantiateViewController(withIdentifier:"firstvc") as? firstvc {
controller = allCollectionViewController
}
} else if indexPath.item == 1 {
if let allCollec = alertStoryBoard.instantiateViewController(withIdentifier:"secondvc") as? secondvc {
controller = allCollec
}
}else if indexPath.item == 2 {
if let wController = alertStoryBoard.instantiateViewController(withIdentifier:"Thirdvc") as? Thirdvc {
controller = wController
}
}
addChildViewController(controller)
// Add the child's View as a subview
contentSubView.addSubview(controller.view)
controller.view.frame = contentSubView.bounds
controller.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// tell the childviewcontroller it's contained in it's parent
controller.didMove(toParentViewController: self)
}
我的完整项目 zip:https://www.dropbox.com/s/fwj745kdgqvgjxa/Collection%20view%20example.zip?dl=0
您应该只将 UISwipeGestureRecognizer
添加到主视图控制器的视图中。
主视图控制器将负责管理手势的调用
基本上在代码中:
在viewDidLoad
中:
let swipeToLeft = UISwipeGestureRecognizer(target: self, action: #selector(changePageOnSwipe(_:)))
let swipeToRight = UISwipeGestureRecognizer(target: self, action: #selector(changePageOnSwipe(_:)))
swipeToLeft.direction = .right
swipeToRight.direction = .left
self.contentSubView.addGestureRecognizer(swipeToLeft) // Gesture are added to the top view that should handle them
self.contentSubView.addGestureRecognizer(swipeToRight)
由于您必须从一个索引处的 VC 移动到另一个索引,您可能需要一个 属性 来跟踪当前选定的视图控制器:
var currentIndexPath: IndexPath?
您可以在每次选择新的 VC 时更改它的值。所以:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("You selected cell #\(indexPath.item)!")
self.currentIndexPath = indexPath
// ... Other settings
}
在您的主 ViewController 中添加 changePageOnSwipe(_ gesture: UISwipeGestureRecognizer)
方法。由于 "chief" 视图控制器拥有 collectionView
,它将处理滑动并告诉其子项出现:
func changePageOnSwipe(_ gesture: UISwipeGestureRecognizer) {
guard let indexPath = self.currentIndexPath else {
// When the page loads and there is no current selected VC, the swipe will not work
// unless you set an initial value for self.currentIndexPath
return
}
var newIndex = indexPath // if self.collectionview.indexPathsForSelectedItems is not empty, you can also use it instead of having a self.currentIndexPath property
// move in the opposite direction for the movement to be intuitive
// So swiping " <-- " should show index on the right (row + 1)
if gesture.direction == .left {
newIndex = IndexPath(row: newIndex.row+1, section: newIndex.section)
} else {
newIndex = IndexPath(row: newIndex.row-1, section: self.currentIndexPath!.section)
}
if canPresentPageAt(indexPath: newIndex) {
// Programmatically select the item and make the collectionView scroll to the correct number
self.collectionview.selectItem(at: newIndex, animated: true, scrollPosition: UICollectionViewScrollPosition.centeredHorizontally)
// The delegate method is not automatically called when you select programmatically
self.collectionView(self.collectionview, didSelectItemAt: newIndex!)
} else {
// Do something when the landing page is invalid (like if the swipe would got to page at index -1 ...)
// You could choose to direct the user to the opposite side of the collection view (like the VC at index self.items.count-1
print("You are tying to navigate to an invalid page")
}
}
并且由于您是以编程方式进行滑动,因此在尝试实际移动之前,您必须确保滑动有效。您必须添加安全检查:
/** You can use an helper method for those checks
*/
func canPresentPageAt(indexPath: IndexPath) -> Bool {
// Do necessary checks to ensure that the user can indeed go to the desired page
// Like: check if you have a non-nil ViewController at the given index. (If you haven't implemented index 3,4,5,... it should return false)
//
// This method can be called either from a swipe
// or another way when you need it
if indexPath.row < 0 || indexPath.row >= self.items.count {
print("You are trying to go to a non existing page")
return false
} else {
print("If you haven't implemented a VC for page 4 it will crash here")
return true;
}
}
最后,您可以在 viewDidLoad
中为 self.currentIndexPath
设置一个默认的 indexPath,这样用户在到达您的主 VC 时就可以滑动,而无需选择另一个 VC 在 collectionView 中。
注意:如果你碰巧在子ViewController中有手势识别器,一些手势可能会发生冲突,你将不得不学习如何使用委托方法解决此类冲突,例如gestureRecognizer(_:shouldRequireFailureOf:)
.
我有 3 个名为 firstvc, secondvc, thirdvc
的视图控制器。我有一个水平滚动的集合视图。如果我 select 我的 first cell
我的 firstvc
将显示在我的 mainviewcontroller
的子视图中。 2, 3rd cell
也一样。很好.
现在我需要一个功能,例如,如果我滑动我的 subview
,当我 select 访问任何单元格时,它将拥有我所有的视图控制器。我需要添加向左或向右滑动。
例如:
如果我在 firstvc
,那么我的 first cell
将是 selected。现在,如果我将我的 subview
向右滑动,我的 secondvc
必须是平均的,而我的第二个集合视图单元格也必须是 highlight
不知道怎么玩
我的代码:
@IBOutlet weak var collectionview: UICollectionView!
@IBOutlet weak var contentSubView: UIView!
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return self.items.count
}
// make a cell for each cell index path
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// get a reference to our storyboard cell
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath as IndexPath) as! MyCollectionViewCell
// Use the outlet in our custom class to get a reference to the UILabel in the cell
cell.myLabel.text = self.items[indexPath.item]
// cell.backgroundColor = UIColor.cyan // make cell more visible in our example project
var borderColor: UIColor! = UIColor.clear
//var borderWidth: CGFloat = 0
if indexPath == selectedIndexPath{
borderColor = UIColor.red
//borderWidth = 1 //or whatever you please
}else{
borderColor = UIColor.white
// borderWidth = 0
}
cell.myview.backgroundColor = borderColor
// cell.myview.layer.borderWidth = borderColor
return cell
}
// MARK: - UICollectionViewDelegate protocol
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("You selected cell #\(indexPath.item)!")
//based on your comment remove the subviews before add on your myview
//let cell = collectionView.cellForItemAtIndexPath(indexPath) as! MyCollectionViewCell
selectedIndexPath = indexPath
for subview in contentSubView.subviews {
subview.removeFromSuperview()
}
let alertStoryBoard = UIStoryboard(name: "Main", bundle: nil)
var controller: UIViewController!
if indexPath.item == 0 {
if let allCollectionViewController = alertStoryBoard.instantiateViewController(withIdentifier:"firstvc") as? firstvc {
controller = allCollectionViewController
}
} else if indexPath.item == 1 {
if let allCollec = alertStoryBoard.instantiateViewController(withIdentifier:"secondvc") as? secondvc {
controller = allCollec
}
}else if indexPath.item == 2 {
if let wController = alertStoryBoard.instantiateViewController(withIdentifier:"Thirdvc") as? Thirdvc {
controller = wController
}
}
addChildViewController(controller)
// Add the child's View as a subview
contentSubView.addSubview(controller.view)
controller.view.frame = contentSubView.bounds
controller.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// tell the childviewcontroller it's contained in it's parent
controller.didMove(toParentViewController: self)
}
我的完整项目 zip:https://www.dropbox.com/s/fwj745kdgqvgjxa/Collection%20view%20example.zip?dl=0
您应该只将 UISwipeGestureRecognizer
添加到主视图控制器的视图中。
主视图控制器将负责管理手势的调用
基本上在代码中:
在viewDidLoad
中:
let swipeToLeft = UISwipeGestureRecognizer(target: self, action: #selector(changePageOnSwipe(_:)))
let swipeToRight = UISwipeGestureRecognizer(target: self, action: #selector(changePageOnSwipe(_:)))
swipeToLeft.direction = .right
swipeToRight.direction = .left
self.contentSubView.addGestureRecognizer(swipeToLeft) // Gesture are added to the top view that should handle them
self.contentSubView.addGestureRecognizer(swipeToRight)
由于您必须从一个索引处的 VC 移动到另一个索引,您可能需要一个 属性 来跟踪当前选定的视图控制器:
var currentIndexPath: IndexPath?
您可以在每次选择新的 VC 时更改它的值。所以:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
print("You selected cell #\(indexPath.item)!")
self.currentIndexPath = indexPath
// ... Other settings
}
在您的主 ViewController 中添加 changePageOnSwipe(_ gesture: UISwipeGestureRecognizer)
方法。由于 "chief" 视图控制器拥有 collectionView
,它将处理滑动并告诉其子项出现:
func changePageOnSwipe(_ gesture: UISwipeGestureRecognizer) {
guard let indexPath = self.currentIndexPath else {
// When the page loads and there is no current selected VC, the swipe will not work
// unless you set an initial value for self.currentIndexPath
return
}
var newIndex = indexPath // if self.collectionview.indexPathsForSelectedItems is not empty, you can also use it instead of having a self.currentIndexPath property
// move in the opposite direction for the movement to be intuitive
// So swiping " <-- " should show index on the right (row + 1)
if gesture.direction == .left {
newIndex = IndexPath(row: newIndex.row+1, section: newIndex.section)
} else {
newIndex = IndexPath(row: newIndex.row-1, section: self.currentIndexPath!.section)
}
if canPresentPageAt(indexPath: newIndex) {
// Programmatically select the item and make the collectionView scroll to the correct number
self.collectionview.selectItem(at: newIndex, animated: true, scrollPosition: UICollectionViewScrollPosition.centeredHorizontally)
// The delegate method is not automatically called when you select programmatically
self.collectionView(self.collectionview, didSelectItemAt: newIndex!)
} else {
// Do something when the landing page is invalid (like if the swipe would got to page at index -1 ...)
// You could choose to direct the user to the opposite side of the collection view (like the VC at index self.items.count-1
print("You are tying to navigate to an invalid page")
}
}
并且由于您是以编程方式进行滑动,因此在尝试实际移动之前,您必须确保滑动有效。您必须添加安全检查:
/** You can use an helper method for those checks
*/
func canPresentPageAt(indexPath: IndexPath) -> Bool {
// Do necessary checks to ensure that the user can indeed go to the desired page
// Like: check if you have a non-nil ViewController at the given index. (If you haven't implemented index 3,4,5,... it should return false)
//
// This method can be called either from a swipe
// or another way when you need it
if indexPath.row < 0 || indexPath.row >= self.items.count {
print("You are trying to go to a non existing page")
return false
} else {
print("If you haven't implemented a VC for page 4 it will crash here")
return true;
}
}
最后,您可以在 viewDidLoad
中为 self.currentIndexPath
设置一个默认的 indexPath,这样用户在到达您的主 VC 时就可以滑动,而无需选择另一个 VC 在 collectionView 中。
注意:如果你碰巧在子ViewController中有手势识别器,一些手势可能会发生冲突,你将不得不学习如何使用委托方法解决此类冲突,例如gestureRecognizer(_:shouldRequireFailureOf:)
.