跳至主要内容

UICollect重排

原文:UICollectionViews Now Have Easy Reordering

译文:现在,UICollectionViews有了简单的重排功能

我是UICollectionView的忠实粉丝。这个类比起它的老哥UITableView类具有更高的可定制性。现在我用collection view的次数要比用table view还多。随着iOS9的到来,它支持简单的重排。在此之前,重排不可能有现成的方法,同时这样做也是件痛苦的工作。现在让我们来看看API,你可以在GitHub找到相应的Xcode工程。



添加简单重排的最简单的方式是用UICollectionViewController。它现在有了一个新的属性叫installsStandardGestureForInteractiveMovement(为交互式移动工作设置标准手势),这个属性的添加使得我们可以用标准手势来对cell单元进行重新排序。该属性默认值为true,这意味着我们只需要重载一个方法就可以让它正常工作。

override func collectionView(collectionView: UICollectionView,
moveItemAtIndexPath sourceIndexPath: NSIndexPath,
toIndexPath destinationIndexPath: NSIndexPath) {
// move your data order
}


Collection view推断每个item(元素)可以被移动,因为moveItemAtIndexPath函数被重载了。

demo

当我们想使用一个带有collection view的简单的UIViewController时,事情变得更加复杂。我们还需要实现之前提到的UICollectionViewDataSource的方法,但我们需要重写installsStandardGestureForInteractiveMovement。别担心,这些也很容易被支持。UILongPressGestureRecognizer是一个持续的、完全支持平移的手势识别器。

override func viewDidLoad() {
super.viewDidLoad()
longPressGesture = UILongPressGestureRecognizer(target: self, action: "handleLongGesture:")
self.collectionView.addGestureRecognizer(longPressGesture)
}
func handleLongGesture(gesture: UILongPressGestureRecognizer) {
switch(gesture.state) {
case UIGestureRecognizerState.Began:
guard let selectedIndexPath = self.collectionView.indexPathForItemAtPoint(gesture.locationInView(self.collectionView)) else {
break
}
collectionView.beginInteractiveMovementForItemAtIndexPath(selectedIndexPath)
case UIGestureRecognizerState.Changed:
collectionView.updateInteractiveMovementTargetPosition(gesture.locationInView(gesture.view!))
case UIGestureRecognizerState.Ended:
collectionView.endInteractiveMovement()
default:
collectionView.cancelInteractiveMovement()
}
}


我们储存了被选择的索引路径,这个路径从longPressGesture handler(长按手势处理器)中获得,这个路径还取决于它是否有任何我们允许的,跟平移手势相关的值。接下来我们根据手势状态调用一些新的collection view方法:



  • beginInteractiveMovementForItemAtIndexPath(indexPath: NSIndexPath)?开始在特定的索引路径上对cell(单元)进行Interactive Movement(交互式移动工作)。


  • updateInteractiveMovementTargetPosition(targetPosition: CGPoint)?在手势作用期间更新交互移动的目标位置。


  • endInteractiveMovement()?在完成手势动作后,结束交互式移动


  • cancelInteractiveMovement()?取消Interactive Movement。





这让处理平移手势更容易理解了。

demo

机器反应跟标准的UICollectionViewController一样,真的很酷,但是还有更酷的--我们能对自定义的collection view layout(collection集合视图布局)申请重排,下面是在waterfall layout(瀑布布局)里对Interactive Movement的测试。

demo

嗯哼,看起来很酷,但如果我们不想在移动cell(单元)的时候改变它们的大小,那该怎么做?被选择的cell(单元)的大小在Interactive Movement期间应该保持原样。这是可行的。UICollectionViewLayout有附加的方法来处理重排。

func invalidationContextForInteractivelyMovingItems(targetIndexPaths: [NSIndexPath],
withTargetPosition targetPosition: CGPoint,
previousIndexPaths: [NSIndexPath],
previousPosition: CGPoint) -> UICollectionViewLayoutInvalidationContext
func invalidationContextForEndingInteractiveMovementOfItemsToFinalIndexPaths(indexPaths: [NSIndexPath],
previousIndexPaths: [NSIndexPath],
movementCancelled: Bool) -> UICollectionViewLayoutInvalidationContext


第一个函数在元素的Interactive Movement期间被调用,它带有target(目标元素)和先前的cell的indexPaths(索引地址)。第二个与第一个函数类似,但它只在Interactive Movement结束后才调用。通过这些知识我们能通过一点小窍门,实现我们的需求。

internal override func  invalidationContextForInteractivelyMovingItems(targetIndexPaths: [NSIndexPath],
withTargetPosition targetPosition: CGPoint,
previousIndexPaths: [NSIndexPath],
previousPosition: CGPoint) -> UICollectionViewLayoutInvalidationContext {
var context = super.invalidationContextForInteractivelyMovingItems(targetIndexPaths,
withTargetPosition: targetPosition, previousIndexPaths: previousIndexPaths,
previousPosition: previousPosition)
self.delegate?.collectionView!(self.collectionView!, moveItemAtIndexPath: previousIndexPaths[0],
toIndexPath: targetIndexPaths[0])
return context
}


取得当前正在移动的cell的之前的和目标索引路径,然后调用UICollectionViewDataSource方法来移动这些item(元素)。

demo

毫无疑问,collection view的重排是一个出色的附加功能,UIKit前端框架工程师干得漂亮!

评论

此博客中的热门博文

非公开 app 分发

非公开 app  简介 app 除了不能搜索到该 app,其他使用和普通的应用商店一致。 只需要使用对应的链接就可以跳转到该 app 。 非公开 app 上传审核流程 1.appstore connect 新建应用,配置和普通上传应用商店(公开应用)完全一致 2.在备注里面加上一行:该 app 属于非公开 app,提交 app 3.去非公开 app 申请链接app 为非公开 app,https://developer.apple.com/contact/request/unlisted-app/ 4.审核被拒,有两部分,一个是普通appstore审核被拒(可能没有),最后还会多上一个非公开 app 审核被拒的部分。等待只有非公开 app 审核被拒的问题后,再等上两天左右就好了。 5.审核通过后,会通过邮件发送该 app 的链接,此链接其实和其他 app 的链接格式一致,并无区别,唯一的区别是该 app 在应用商店搜索不到。

非公开 app

 1.对用户 用户只能通过特定链接才能使用该 app,其他使用和应用商店 app 一致。 2.对开发 a,以应用商店提交 app 的标准方式提交 app,在备注添加一行,写上“App 将用于非公开分发”,提交 app。 b,  填写非公开 app 申请,https://developer.apple.com/contact/request/unlisted-app/ c,等待审核,整个审核过程会比平常审核慢 2-5 个工作日,后续更新应该会正常。 app分发类型 非公开app ABM App Store 企业包 app分发类型 非公开app ABM App Store 企业包 是否需要https, 自己搭建托管环境 否,文件托管到 App Store 否,文件托管到 App Store 否,文件托管到App Store 是,需要自己托管,需要 https 环境,受信任的 ssl证书 是否可以直接在 App Store 搜索到 否 否 是 否 是否可以在 App Store 展示 应用信息,包括 在应用信息页面 手动点击更新 是 否 是 不上传到App Store无 App Store信息 在应用商店 更新列表点击更新 是 是 是 否 是否需要手 动更新app 开启App Store的自动更新,就自动更新,否则手动更新 开启App Store的自动更新,就自动更新,否则手动更新,只能点我的头像,更新列表里面去更新 开启App Store的自动更新,就自动更新,否则手动更新 必须去 app 里面 点击更新,或者 去下载页面去 下载最新的app 包是否会过期 否,只要账号正常 否,只要账号正常 否,只要账号正常 是,包里面有 两个证书,虽 然只打包进一 个证书文件, 但那个证书文 件关联另一个, (打包的时候一 起使用)打包 的文件有效期1 年,关联的文 件有效期 3 年。打包的时候 是否允许马甲, 重复应用(相似 ui,相似代码) 是 是 否 是 应用商店审核要求 有,除了马甲应用,其他都一样 有,除了马甲应用,其他都一样 不允许马甲应用,其他都一样 不需要审核 是否能用其他 开发者账号上传 我们的定制版应用 未知 可以 不允许 无app store 应用上传权限 哪些版本可以 改成该版本 1.App Store包 2.企业包 1.企业包 1.企业包 ...

iOS企业包下载中的下载

 首先,链接格式是itms-services://?action=download-manifest&url=https://xxxx.plist plist文件格式是 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>items</key> <array> <dict> <key>assets</key> <array> <dict> <key>kind</key> <string>software-package</string> <key>url</key> <string>ipa的完整的url,可以是http的</string> </dict> <dict> <key>kind</key> <string>display-image</string> <key>url</key> <string>小图的完整的url,可以是http的</string> </dict> <dict> <key>kind</key> <string>full-size-image</string> <key>url</key...