Customisable tableview cell swipe to stop on full expansion? - ios

Is there any way to easily achieve the results in the pictures below (maybe by using MGSwipeTableCell or SwipeCellKit or any other pod you know of). I'm pretty sure you can't do that using the default iOS UIKit.
There are 2 things here to consider:
1) The table view cell swipe actions, should be completely customisable (putting an UIView there, so you can put anything you want inside the UIView) or at least, get closer to the screenshot, using 1 and then 5 buttons (therefore, different swipe-actions for smallswipe and fullswipe) ?
2) The tableview cell swipe action, must first (small-swipe) only show the "alarm' icon like in the first picture, and if you click on it, or swipe even further it should look like in the second picture, and most importantly, stay like that, no auto-unswiping (no action to be done, except waiting for input from user, to either select another cell, or any of the buttons there).
I'm not asking for a complete solution, I just want to know if it's possible and relatively easy to do, so I won't waste weeks in order to try to achieve this and find out in the end that it's not possible.
SmallSwipe
FullSwipeOrClick

I think in you tableCell, you can add view to contentView, that will be fill all cell and drag it via UIPanGestureRecognizer. Your action views will be under scrollable view. Something like this:
class SwipableTableViewCell: UITableViewCell {
#IBOutlet var actionView: UIView // under mainView
#IBOutlet var mainView: UIView // take whole place of contentView
#IBOutlet var panGesture: UIPanGestureRecognizer
#IBAction func panAction(_ sender: UIPanGestureRecognizer) {
// drag main view left or right and logic of auto swiping
}
}

I really don't know if you can make a small and full swipe native. The method for swipe for iOS 11 is tableView(_:trailingSwipeActionsConfigurationForRowAt:).
From there, I know there is performFirsActionWithFullSwipe, that doesn't allow full swipe on the first time. I think you can play with this two. In configuration you can add UIContextualAction that has an action, image and even background color that you can set.
I hope it helps.

Related

How to change the render order of UIImageViews created in Storyboard

I am working on an iPhone application using Swift 4 which creates characters.
About this application: on the Storyboard I created some UIImageViews that render on top of each other which represent some parts of the character such as socks, shoes, pants, shirts. I then combine all these layers in the code to create the full character. I have buttons in the user interface to choose a category. When a category is chosen, I display all possible items the character can wear in a UICollectionView. The user then selects an item from this collection and so the corresponding image changes accordingly.
The problem: since I have created these UIImageViews on top of each other using the Storyboard already, they already have an order while rendering. But sometimes the items have to render in a different order. For example, sometimes shoes have to render on top of pants as in wearing a skinny jeans, while other times shoes have to render under the pants as in wearing a bootcut jeans. Sometimes the user doesn't want to bring a layer all the way to the top but between some certain layers.
I want to give the users the ability to change the render order of items or move them a layer up or down.
What would be a good approach to solve this problem?
Thanks in advance for the answers.
A UIView renders it child views from first to last. Thus the rear subviews cover the front subviews. There are several methods to change the order of subviews. You may use bringSubview(toFront:).
view.bringSubview(toFront: shoeView)
Will render the subview shoeView at last such that is on top of all other subviews of view.
If you want to move a view, you might use insertSubview(_:at:). If the view always a subview, it is simply moved to the new index.
You will have to do it programmatically, and I think the best way is to keep #IBOutlets to those UIImageViews and then at the appropriate time just switch their order in their superview.subviews - the view uses the order of it's subviews to determine the order of rendering them.
So just to illustrate a short example:
#IBOutlet var shoesImageView: UIImageView!
#IBOutlet var pantsImageView: UIImageView!
#IBAction func putShoesOnTop() {
let superView = shoesImageView.superview!
superView.bringSubview(toFront: shoesImageView)
}
#IBAction func putPantsOnTop() {
let superView = pantsImageView.superview!
superView.bringSubview(toFront: pantsImageView)
}

Swift, button part is outside view, and i wont handle events

So i have a layout in swift:
basically the greyed out part of the selected button wont handle events, i tried:
bottomView.bringSubview(toFront: startButton)
But its not working, im new to swift, but im thinking its because
the greyed out part is outside de UIView and thats why it can't handle the event. Any suggestions or workarounds?
Is the button over the grey area view(kind of Z index)? You can always verify if the button is above the view in storyboard's Document outline (that is on left).Below is a sample view in a view controller. Look at how rabbitButton is over the snailButton
There are a few possibilities here :
Make sure that your gray view is at the top of the view stack. To do that, identify your parent view and : parentView.bringSubview(toFront: grayStartView) just as you did. So the only thing you need to make sure in your case is that bottomView is indeed the parent view of grayStartView.
If grayStartView is a UIView or a UIImageView and not a UIButton, then you need to make sure that it allows user touches, by using : grayStartView.isUserInteractionEnabled = true.
Now it might sound trivial but just in case make sure that you add the target properly if its a button : grayStartButton.addTarget(self, action: #selector(yourMethod), for: .touchUpInside) or a view : grayStartView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(yourMethod))).
Also you need to make sure that, if you add any subview to your grayStartView, or your grayStartButton, you need to call subviewOfGrayButton.isUserInteractionEnabled = false otherwise the subview would then absorb the touches.
Finally I would check that your method (especially the sender) is properly written :
#IBAction func yourMethod(sender: UIButton) {
// ... Do some cool things here
}
If it's still doesn't work, well it would be helpful to learn more about your view hierarchy :)
Note: From what I can see it seems like you're missing a width constraint here (or maybe is it intentional?) so even though it's not related to your problem you may want to check this as well

Swift : View in a UIScrollView is unable to detect touch

So I have A UIButton in a UIView within a UIScrollView within a UIViewController within a UIScrollView.. that is whole lot of layers I know but that was required. But the result I got is that the UIButton cannot be tapped because the touch can't be detected on the button. ScrollViews are working perfectly but the elements in the final layer are not detecting touches.
The Layers are as follow:
UIViewController
~UIScrollView
~~UIViewController
~~~UIScrollView
~~~~UIView
~~~~~UIButton
Kindly tell me how can I detect the touch on the last UIView?
you should debug view hierarchy by clicking debug view hierarchy button
look like this.
So you come to know that your button actually get touch events or it is hidden by other views.
Update :
I am uploading another screenshot
You have to run your project then you will able to see this button above console pane.
You can refer Apple documentation for more details.
Hope this will help :)
To solve your current problem, you need to iterate through all gestures on each super view and call requireGestureRecognizerToFail for relevant gestures on subviews. This way you make sure that the subviews get the touches 'first' and superviews handle only those touches which are ignored or not recognize by subviews for whatever reason. (I know this sounds as ridiculous as having a view hierarchy like UIViewController -> UIScrollView -> UIViewController -> UIScrollView -> UIView -> UIButton)
It seems unlikely that you could not have solved your visual design using either UITableView or UICollectionView. So reconsider!! It will save you a lot of such issues.

Touch Down/Up and Scroll in UITableViewController

I'm having a bit of of a pain point in figuring something out.
I have a uitableviewcontroller, and each cell is static. Inside each cell is a textbox. When the user TAPS on a textbox, I'd like an event to fire.
So while I'd like my table to still scroll, i'd also like tap events to work when you tape the textbox.
Apparently in uitableviews, they add a delay to your tap so you have to hold your finger down for a second or so for 'tap' to register. I felt this was not intuitive to a user, so I did this to fix it:
for subview in self.tableView.subviews as [UIView]
{
if subview is UIScrollView
{
let scroll = subview as UIScrollView
scroll.delaysContentTouches = false
break
}
}
This works perfectly, and now when I tap my textbox, it instantly executes my tap event! The problem now, however, is some of my textboxes are positioned right where a user would naturally scroll. When they put their finger down (touch down event) to scroll, it's unfortunately being intercepted by the tap event, and prevents scrolling and instead executes my event.
What i'd really want is if the user puts their finger down, and then swipes, it doesn't execute the touch down event. I thought to be clever and switch touch down to touch up, but when I put my finger down and then pick it back up, it does nothing (touch up inside seems to do nothing). I read this was because it only works on buttons and things like that, and not textfields. So, yes, now I can scroll without my action, but when I tap the textbox and lift my finger up it doesn't execute that, either.
Any ideas on how to either
1) permit touch downs and scrolling to co-exist without having to hold my finger down for a second and deal with that delayContentTouches?
2) somehow get a tap up inside event to fire when I tap on a textbox?
I saw some info here but didn't seem to help much:
UIButton inside UITableViewCell steals touch from UITableView
Thanks!
Well, as luck would have it, I was able to figure this out. Would love some criticism/advice if something might not be ideal here, but what I did was add this to my subclassed textfield:
override func canBecomeFirstResponder() -> Bool {
performMyFunctionHere()
return false
}
So I am returning false on first responder which prevents any sort of keyboard appearing (which is what I wanted) and instead using performMyFunctionHere() I can do what I wanted to do (in my case, make an action sheet picker appear). I assign the action sheet picker in my view controller and assign it to each specific instance of my subclassed uitextfield. Nothing really complicated, to be honest. I'm surprised this works as well as it does.
By the way one thing that didn't seem extremely important was setting the delaysContentTouches as I mentioned above. I guess because now it's using the responder it will always work? It didn't seem to matter whether I removed it or not, but would love thoughts on whether it's better to leave it in or not.
Thanks!

Touch Down firing in a weird way

I'm adding a touch down action to a uitextfield (actually it's a subclass, but I think that might not be important). I created a simple view controller and added this textbox to it, and wired up the event to println("Hello").
When I quickly tap the item (both in simulator, and on my phone) it works perfectly and says hello!
I then created a UITableViewController subclass, and in one of the static cells I added the same textbox.
In this case, when I quickly tap the textbox nothing happens! When I actually hold down the mouse or my finger for about 1/2 a second, it works. But not if I quickly tap it.
This is different from the previous textbox, which always works perfectly no matter how fast I tap it.
Are there some problems with different events being intercepted ors something of that sort?
I even went so far as to add a tap gesture recognizer to both the table cell, and the textbox, but neither work unless I hold it down (the table cell action won't even fire unless I click off the textbox and into the cell proper, of course).
Thanks so much this is very strange.
UIButton not showing highlight on tap in iOS7
and
iOS - Delayed "Touch Down" event for UIButton in UITableViewCell
have a lot of information about this. Apparently there is a delay for uitableviewcells that can be avoided by taking some of the approaches above.
I'll post the solution that works for me once I work on it. thanks!
EDIT OP DID DELIVER!! (lol sorry)
in IOS8, the idea is that table cells no longer have the uiscrollview that would basically delay the touching, so what you can do instead is something like this in your page did load:
for subview in self.tableView.subviews as [UIView]
{
if subview is UIScrollView
{
let scroll = subview as UIScrollView
scroll.delaysContentTouches = false
break
}
}
So see how we're iterating over self.tableview's subviews, and anytime we hit a scrollview set delaysContentTouches to false. This worked for me on both the simulator and on my phone.

Resources