ice3-software / between-kit Goto Github PK
View Code? Open in Web Editor NEWA robust drag-and-drop framework for iOS.
License: MIT License
A robust drag-and-drop framework for iOS.
License: MIT License
The lack of sample implementation code make it more time consuming to evaluate your solution. Providing it will reduce barriers to us it and could increase adoption.
Hi, nice library. I have a question: is it possible to make d'n'd between 3 tableviews?
At the moment, it creates a gesture recognizer and attaches it to the superview 'behind the scenes', which causes issues if you have mutilple helpers acting on one superview as they all implicitly set its gesture recognizer.
What would be great is if we could configure a gesture recognizer outside if this class and inject it so that we can use lots of these helpers to express relations between tables/collections without causing conflict.
Its only an idea at the moment but this will make it easier to build drag and drop relations between lots of tables in the future.
In the large majority of cases, the I3Collection
will actually be a UIView
of some sorts.
I think we should look at enforcing this constraint: if a I3Collection
does not implement collectionView
it must itself be a subclass of UIView
, otherwise I3Collection
must implement collectionView
.
Is it possible to edit a UITableViewCell (swipe from right to left) to see the delete button, when i3dnd is active and dragging isn't allowed for the cell?
Include the following:
I3CollectionView
, UICollectionView
subclassI3View
, simple UIView
subclass that allows to drag / droppings its subviews... or, because I3Collection no longer requires a drag data source property, we can just use categories now !
We need a set of written guidelines around how to submit PRs and how to manually changes against the current 'Example App' (that is, until automated testing is in place).
I3DragArea
has strong references both to the superview
and an ordered set of strong references to the collections - need to investigate whether this causes retain cycles
Once I have one item in the dst table, I can DnD without issue. But am unable to add that first item with DnD. I also cannot DnD a cell so that I drop it at the bottom of the table (as the last row in the table) - maybe related?
Again, love this DnD solution. So easy to implement using your helper and example code. Kudos!
I have followed the I32RearrangeableExchangeableTablesViewController and when I reorder it crashes. Assuming my fault but not sure where to start looking. Tried debugging but still not seeing clear root cause.
I see it stating "This view probably hasn't received initWithFrame: or initWithCoder:" but not exactly sure what that means. My app was initially implemented back in 2011, so perhaps a version issue (ARC, or something to that effect).
Here is the debugger output with error below.
If you have any insights, would be much appreciated. This is a really great time saver for me. Thanks for putting it together and making it available.
2014-03-10 17:27:38.949 Lacrosse-Stats[609:70b] Dragging from destination to destination.
2014-03-10 17:27:38.950 Lacrosse-Stats[609:70b] Rearrangeing dst
2014-03-10 17:27:42.128 Lacrosse-Stats[609:70b] *** 6) start isCellInDstAtIndexPathExchangable
2014-03-10 17:27:42.128 Lacrosse-Stats[609:70b] Cell row: 3
2014-03-10 17:27:42.144 Lacrosse-Stats[609:70b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Requesting the window of a view (<UITableViewCell: 0xdca2e00; frame = (0 0; 0 0); transform = [0, 0, 0, 0, 0, 0]; text = '2 - Frick, Andrew'; alpha = 0; autoresize = W; layer = (null)>) with a nil layer. This view probably hasn't received initWithFrame: or initWithCoder:.'
*** First throw call stack:
(
0 CoreFoundation 0x0389b5e4 exceptionPreprocess + 180
1 libobjc.A.dylib 0x02d898b6 objc_exception_throw + 44
2 CoreFoundation 0x0389b3bb +[NSException raise:format:] + 139
3 UIKit 0x01bb2f5b __windowForView + 467
4 UIKit 0x01bb52a0 -[UIView(Hierarchy) _postMovedFromSuperview:] + 28
5 UIKit 0x01bc04c1 -[UIView(Internal) _addSubview:positioned:relativeTo:] + 1847
6 UIKit 0x01bb39b1 -[UIView(Hierarchy) addSubview:] + 56
7 Lacrosse-Stats 0x00083d2f -[I3DragBetweenHelper animateDummyExchange:inContainer:withCompletionBlock:] + 879
8 Lacrosse-Stats 0x00088467 -[I3DragBetweenHelper handleDragFromDstStoppedInDstAtPoint:] + 1031
9 Lacrosse-Stats 0x00086949 -[I3DragBetweenHelper handleDragStopped:] + 1289
10 Lacrosse-Stats 0x0008623e -[I3DragBetweenHelper handlePan:] + 254
11 UIKit 0x01ed0e8c _UIGestureRecognizerSendActions + 230
12 UIKit 0x01ecfb00 -[UIGestureRecognizer _updateGestureWithEvent:buttonEvent:] + 383
13 UIKit 0x01ed156d -[UIGestureRecognizer _delayedUpdateGesture] + 60
14 UIKit 0x01ed4acd ___UIGestureRecognizerUpdate_block_invoke + 57
15 UIKit 0x01ed4a4e _UIGestureRecognizerRemoveObjectsFromArrayAndApplyBlocks + 317
16 UIKit 0x01ecb148 _UIGestureRecognizerUpdate + 199
17 UIKit 0x01b9719a -[UIWindow _sendGesturesForEvent:] + 1291
18 UIKit 0x01b980ba -[UIWindow sendEvent:] + 1030
19 UIKit 0x01b6be86 -[UIApplication sendEvent:] + 242
20 UIKit 0x01b5618f _UIApplicationHandleEventQueue + 11421
21 CoreFoundation 0x0382483f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION + 15
22 CoreFoundation 0x038241cb __CFRunLoopDoSources0 + 235
23 CoreFoundation 0x0384129e __CFRunLoopRun + 910
24 CoreFoundation 0x03840ac3 CFRunLoopRunSpecific + 467
25 CoreFoundation 0x038408db CFRunLoopRunInMode + 123
26 GraphicsServices 0x037559e2 GSEventRunModal + 192
27 GraphicsServices 0x03755809 GSEventRun + 104
28 UIKit 0x01b58d3b UIApplicationMain + 1225
29 Lacrosse-Stats 0x0000300d main + 125
30 libdyld.dylib 0x03270701 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
If Src or Dst do not create duplicate views on dragging, when triggering a UITableViewCellAnimation via insertRowsAtIndexPaths, deleteRowsAtIndexPaths, etc, in the delegate method the dragging view (the original cell view object) is translated back to its previous parent and then animates.
To fix this: create duplicate views and hide the original one in the helper.
This is a pretty premature ticket as there are lots of issues to sort, but it would be cool if in the future we supported normal views as 'container's and their subviews as 'draggables', not just tables, collections and cells.
The basic render delegate unhides the source item view before the dragging view has been completely snapped back. The result is a transition that doesn't look entirely convincing...
A LICENSE.txt needs to be added so that this codebase can be used accordingly.
The implementation of exchange does not actually ever exchange. It drops.
We need to review 'append' vs 'exchange'.
... more examples to come.
To... BetweenKit !
hidesItemWhileDraggingAtPoint:(CGPoint) at inCollection:(id<I3Collection>) collection
is used by the basic render delegate to determine whether an item at a given point should be hidden whilst dragging. The questions as to whether we should hide the dragging item or not is really the responsibility of the render delegate to answer, not the data source. A user could easily implement a render delegate to just ignore this method completely; its a bit redundant.
Having said that, if we completely removed it how would one go about specifying different cells in a collection to be hidden / remain visible ?
At the moment, if the frames of the source and destination tables overlap only items from the src table are draggable in the overlapping areas. This applies even if the dst container is on-top of the src in the view hierarchy.
Deletion is only triggered iff the data source says its OK and the valid drag is stopped outside of all collections. As a user I may want to add a deletion area hovering over a given collection.
I propose that we change the implementation of handleDragStoppedInCollection:atPoint:
to route drag handling to handleDragStoppedOutsideAtPoint:at
if neither rearrange nor exchange occurs, instead of snapping back. This of course, highlights the limitation that if we stop a drag from a collection on a deletable area that also happens to be on top of the original collection, it will only be considered a delete if no rearrange occurs.
The main objective for V2 is to act upon the feedback given thus far in order to bring the codebase from just a helper class
to a proper user interface framework
.
UITableViewRow
moveable
and editable
properties). This framework needs to work alongside, and integrate with, these vendor-provided features.Currently I am aiming to dedicate 1, 8 hour day per week to this project (probably on a Sunday).
This might not be that big a deal but in my case, I don't want the tables to scroll with single touch. So I disable single finger/touch scroll and force 2 finger scrolling. This has a side effect of allowing drag in any direction to initiate the DnD.
Just do the following in viewDidLoad:
self.myLeftSideTable.panGestureRecognizer.minimumNumberOfTouches = 2;
NSIndexPath
is a much cleaner* way of providing the metadata around the items that are being drag / dropped. If we are drag/dropping between UI[Collection | Table]View
s, at the moment users have to implement boilerplate code to map a given point to an index path in the drag data source. It makes sense to do the following:
indexPathForItemAtPoint
to I3Collection
itemAtPoint
to itemAtIndexPath
in I3Collection
NSIndexPath
category for use with their own I3Collection
implementations. For example, a UIView
that implements I3Collection
may extend NSIndexPath
to provide metadata about the position of its subviews.Refactor the coordinator and other related classes to deal only in NSIndexPath
s. Now we can adequately encapsulate the responsibility of mapping a given point to an associated data index to the collection.
*its cleaner in my opinion, because CGPoint
s are meant to specify exactly where the item is on the screen. NSIndexPath provides data about 'which items belong where' in a more abstract data-oriented way
Hello,
In (UIView_) copyOfView:(UIView_) viewToCopy function
{
...
NSData* viewCopyData = [NSKeyedArchiver archivedDataWithRootObject:viewToCopy];
UIView* viewCopy = [NSKeyedUnarchiver unarchiveObjectWithData:viewCopyData];
...
}
, i am having this issue: " [NSKeyedUnarchiver decodeBoolForKey:]: value for key (UIHighlighted) is not a boolean' "....
Its happening when i DOUBLE TAP on my item AND THEN try TO DRAG
After little research, some people fixed the problem with unsetting Highlighted but its not working for me....
Please, how i have to implement some double Tap function for ignoring double tap.
I3DragArea
has strong references both to the superview
and an ordered set of strong references to the collections. Might cause retain cycles.
I might be able to leverage your work, but I don't want to dig through your code to see how to get it running.
Any way to include a simple implementation example to allow for quick review of your solution? It would remove a barrier to adoption.
While using this I3DragBetweenHelper code for rearranging rows in the same table view, app get crashed in the line (+[NSKeyedArchiver archivedDataWithRootObject:]) with exception as follows,
NSConcreteAttributedString initWithString:: nil value
SampleApp-[I3DragBetweenHelper copyOfView:]
in I3DragBetweenHelper.m on Line 163
0 CoreFoundation 0x2f277e8b exceptionPreprocess
1 libobjc.A.dylib 0x395726c7 objc_exception_throw
2 CoreFoundation 0x2f277dcd -[NSException initWithCoder:]
3 Foundation 0x2fba9f95 -[NSConcreteAttributedString initWithString:]
4 Foundation 0x2fba9e71 -[NSConcreteAttributedString initWithString:attributes:]
5 UIKit 0x31cf10e5 -[UILabel _attributedStringHasAttributesNotCoveredByPrimitives]
6 UIKit 0x31cf1475 -[UILabel encodeWithCoder:]
7 Foundation 0x2fbf2891 _encodeObject
8 Foundation 0x2fbf3a6f -[NSKeyedArchiver _encodeArrayOfObjects:forKey:]
9 Foundation 0x2fbf4045 -[NSArray(NSArray) encodeWithCoder:]
10 Foundation 0x2fbf2891 _encodeObject
11 UIKit 0x31c90151 -[UIView encodeWithCoder:]
12 Foundation 0x2fbf2891 _encodeObject
13 Foundation 0x2fbf3a6f -[NSKeyedArchiver _encodeArrayOfObjects:forKey:]
14 Foundation 0x2fbf4045 -[NSArray(NSArray) encodeWithCoder:]
15 Foundation 0x2fbf2891 _encodeObject
16 UIKit 0x31c90151 -[UIView encodeWithCoder:]
17 UIKit 0x31d41ced -[UITableViewCell encodeWithCoder:]
18 Foundation 0x2fbf2891 _encodeObject
19 Foundation 0x2fbf8cb1 +[NSKeyedArchiver archivedDataWithRootObject:]
20 SampleApp 0x00059b47 -[I3DragBetweenHelper copyOfView:] in I3DragBetweenHelper.m on Line 163
21 SampleApp 0x0005a50b -[I3DragBetweenHelper startDragFromView:atPoint:] in I3DragBetweenHelper.m on Line 346
22 SampleApp 0x0005b8bd -[I3DragBetweenHelper handleDragStartedInSrcAtPoint:] in I3DragBetweenHelper.m on Line 696
23 SampleApp 0x0005b23f -[I3DragBetweenHelper handleDragStarted:] in I3DragBetweenHelper.m on Line 583
24 SampleApp 0x0005b093 -[I3DragBetweenHelper handlePan:] in I3DragBetweenHelper.m on Line 528
25 UIKit 0x31b84171 _UIGestureRecognizerSendActions
26 UIKit 0x31a2e943 -[UIGestureRecognizer _updateGestureWithEvent:buttonEvent:]
27 UIKit 0x31db9437 ___UIGestureRecognizerUpdate_block_invoke
28 UIKit 0x319f57af _UIGestureRecognizerRemoveObjectsFromArrayAndApplyBlocks
29 UIKit 0x319f3f13 _UIGestureRecognizerUpdate
30 UIKit 0x31a2d1b5 -[UIWindow _sendGesturesForEvent:]
31 UIKit 0x31a2cb63 -[UIWindow sendEvent:]
32 UIKit 0x31a01f59 -[UIApplication sendEvent:]
33 SampleApp 0x000989cd -[UIApplication(InstabugApplication) InstabugSendEvent:] in InstabugSession.m on Line 42
34 UIKit 0x31a00747 _UIApplicationHandleEventQueue
35 CoreFoundation 0x2f242f27 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION
36 CoreFoundation 0x2f2423ef __CFRunLoopDoSources0
37 CoreFoundation 0x2f240bdf __CFRunLoopRun
38 CoreFoundation 0x2f1ab541 CFRunLoopRunSpecific
39 CoreFoundation 0x2f1ab323 CFRunLoopRunInMode
40 GraphicsServices 0x33ee22eb GSEventRunModal
41 UIKit 0x31a621e5 UIApplicationMain
42 SampleApp 0x00068137 main in main.m on Line 16
43 libdyld.dylib 0x39a6bab7 start
Device used:
iPhone 5
OS 7.0.2
Please help on this issue.
Thanks.
The class uses NSLog
to log regardless of the build environment. It should use its own logging macro that wraps NSLog
and this should be 'turned off' in production.
CGPoint
parameters.Would be nice to have a 'manager' class responsible for abstracting away all the boilerplate of setting up and configuring between components.
We need some sort of automated coverage so that we can detect regressions caused by external PRs easily.
As the delegate protocol does not include a parameter for the helper class that sent the delegate message, there is no way of implementing delegates for multiple helpers in a single class. Here is an example of what we need:
-(void) dragFromDstAtIndex:(NSIndexPath*) from toSrcAtIndex:(NSIndexPath*) to fromHelper:(I3DragBetweenHelper*) sender{
if(sender == self.helper1){
// Helper 1 impl
}
else if(sender == self.helper2){
// Helper 2 impl
}
}
...vs what we have at the moment:
-(void) dragFromDstAtIndex:(NSIndexPath*) from toSrcAtIndex:(NSIndexPath*) to{
// How can I tell if this message was sent form helper1 or helper2?
}
This is currently being implemented in the delegate-refactor branch
I thought it was not as intuitive to force the user to drop the first item at the very top on an empty table, so I made some mods that I think could improve the UX but I am not certain if there are any negative repercussions as I have not done extensive testing, yet, but so far it looks good. Here's what I did.
In I3DragBetweenHelper, I commented out lines 792 - 797 (if nil check on drop index)
https://github.com/ice3-software/i3-dragndrop/blob/master/Classes/I3DragBetweenHelper.m#L792
Then in the delegate method, droppedOnDstAtIndexPath:to fromSrcIndexPath:from, I check for index==nil and just create a new NSIndexPath with row set to the size of the datasource of the target table. I have to do the same in the srcTable as I did in the dstTable, obviously.
if (to == nil)
{
to = [NSIndexPath indexPathForRow:(self.dstDataSource.count) inSection:0];
}
Hope this can make it into your sources as feature if you see it as useful.
Currently, rearrange swaps the drag indexPath with the drop indexPath. It would be useful if the DnD could be optionally configured to just reorder the all indexPaths above the drop by -1.
OCLint
, etc
See closing comment on #41.
Including xcuserdata and DS_STORE files.
On iOS 6, if you subclass UITableViewCell or UICollectionViewCell and add subviews as properties to your custom cell they are issues with the duplicate dragging cell - the new subviews that you've added are usually not encoded/decoded for the duplicate dragging view. At present you must implement your own archiving mechanism in the subclass for your custom cell subviews.
I will provide examples on how to do this shortly.
there is an issue with type casting to BOOL
e.g.
BOOL isExchangable = (BOOL)cell;
-(BOOL) startDragFromView:(UIView*) container atPoint:(CGPoint) point makeCopy:(BOOL) makeCopy{
UIView* cell;
NSIndexPath* index = [self determineIndexForContainer:container
atPoint:point
forCell:&cell];
DLog(@"index = %@, cell = %@", index, cell);
BOOL isDraggable = (BOOL)cell;
DLog(@"isDraggable = %i, %i, %i", isDraggable, !!cell, (cell != nil));
I've got result
2013-11-28 11:34:25.039 Templater[1104:c07] -[I3DragBetweenHelper startDragFromView:atPoint:makeCopy:] [Line 183] index = <NSIndexPath 0x947ccc0> 2 indexes [0, 6], cell = <BTBannerModuleCell: 0x9074b00; baseClass = UICollectionViewCell; frame = (50 1106; 280 179); gestureRecognizers = <NSArray: 0x90795b0>; layer = <CALayer: 0x90788a0>>
2013-11-28 11:34:25.039 Templater[1104:c07] -[I3DragBetweenHelper startDragFromView:atPoint:makeCopy:] [Line 187] isDraggable = 0, 1, 1
2013-11-28 11:34:25.039 Templater[1104:c07] -[I3DragBetweenHelper startDragFromView:atPoint:makeCopy:] [Line 196] isDraggable = 0
2013-11-28 11:34:25.040 Templater[1104:c07] -[I3DragBetweenHelper startDragFromView:atPoint:makeCopy:] [Line 200] Invalid Cell or Cell not Draggable.
so all (BOOL)cell should be replaced with (cell != nil) or !!cell
http://stackoverflow.com/questions/7123743/objective-c-result-of-casting-id-to-bool
See 3rd revision of the plan in comment on #28
Methods in the framework should use NSParameterAssert
and NSAssert
to verify preconditions / postconditions.
... should I assert invariants?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.