How to repeat or re- select the selected segment on HMSegmentedControl? - ios

In HMSegmentedControl, I want to perform repeated segment selection. Means If a segment is selected already, If it's press or select again it should perform/ reload the next functions on the basis of segment selection.

In HMSegmentedControl.swift file, there is tapped(segmentButton:) function in which you can just change indexChanged bool variable to true or you can remove indexChanged variable from if condition then every time you tap selected tab event will occures. Here is actual function code :
Swift
func tapped(segmentButton sender: UIButton) {
let newIndex = sender.tag
//let indexChanged: Bool = newIndex != selectedSegmentIndex
let indexChanged: Bool = true
selectedSegmentIndex = newIndex
if let indexChangedHandler = indexChangedHandler, indexChanged == true {
indexChangedHandler(selectedSegmentIndex)
}
setSelectedSegmentIndex(newIndex, animated: true)
}
OR
func tapped(segmentButton sender: UIButton) {
let newIndex = sender.tag
selectedSegmentIndex = newIndex
if let indexChangedHandler = indexChangedHandler {
indexChangedHandler(selectedSegmentIndex)
}
setSelectedSegmentIndex(newIndex, animated: true)
}
Objective-C
you can remove segment != self.selectedSegmentIndex condition in this method - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
//if (segment != self.selectedSegmentIndex && segment < sectionsCount) {
if (segment < sectionsCount) {
// Check if we have to do anything with the touch event
if (self.isTouchEnabled)
[self setSelectedSegmentIndex:segment animated:self.shouldAnimateUserSelection notify:YES];
}
NOTE : commented line (1st line) is old code and 2nd line is new code.

Related

Add LongPressGesture to many textfields

I have many textfields to enter values for calculation.
For each textfield I also added a LongPressGestureRecognizer so that I can update my calculations with interim results that I store in the placeholders.
#IBAction func lTap1(_ sender: UILongPressGestureRecognizer) {
if sender.state == .began && lTap1.placeholder!.isNumeric
{
lTap1.text = lTap1.placeholder
Calculation()
}
}
Is there a more convenient way with less code to add the long tap function to each text field instead of repeating the #IBAction function for lTap2, lTap3, etc.?
First assign tag to all Textfields
then declare the array of TextFields there are two ways to declare
#IBOutlet var textFields: [UITextField]!
and
let textFields = [lTap1, lTap2, lTap3,...]
then
#objc func textFeildLongPressed(_ sender: UILongPressGestureRecognizer) {
guard let tag = sender.view?.tag else { return }
guard let textField = textFields[tag] else {
return
}
if sender.state == .began && textField.placeholder!.isNumeric {
textField.text = textField.placeholder
Calculation()
}
}
Now assign gesture to all textFields in viewDidLoad function
textFields.forEach {
let tap = UILongPressGestureRecognizer(target: self, action: #selector(textFeildLongPressed(_:)))
tap.view?.tag = $0.tag
$0.isUserInteractionEnabled = true
$0.addGestureRecognizer(tap)
}
Thanks.

How to disable UILongPressGestureRecognizer on UICollectionViewCell after there is a long press?

Currently, I have a collection view with a UILongPressGestureRecognizer on the cell in cellForItemAt:
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPressOnCell))
cell.addGestureRecognizer(longPress)
When the user holds down on a cell, it triggers a function to show a menu called cellDeleteAppear(). However, after the menu is on the screen, the user can then hold down on another cell which will cause the menu to pop up again.
#objc func handleLongPressOnCell(_ sender: UILongPressGestureRecognizer) {
if sender.state == .began {
cellDeleteAppear()
let gestureLocation = sender.location(in: self.trayCollectionView)
if let indexPath = self.trayCollectionView.indexPathForItem(at: gestureLocation) {
indexPathForDeletion = indexPath
trayCollectionView.allowsSelection = false
} else {
print("long press error at index path")
}
}
}
My goal is: while the menu is active, the user should not be able to hold down on another cell to trigger the menu to pop up. Any help is appreciated!
Then do
var menuShown = false
#objc func handleLongPressOnCell(_ sender: UILongPressGestureRecognizer) {
if sender.state == .began {
guard !menuShown else { return }
menuShown = true
And when you hide it do
menuShown = false

how to iterate through functions with button press in Swift

I'm learning swift and building an ARApp but can't seem to understand how to iterate through a few functions with every separate button press. I have created 3 func with animation built in and want to press the button once and funcAnimation#1 activate then tap button again to proceed to funcAnimation#2 and so forth.
#IBAction func nextAnimation(_ sender: UIButton) {
funcAnimation#1()
funcAnimation#2()
funcAnimation#3()
}
of course the problem here is that they all activate at once. I would like to iterate only on button press for each individual press. In addition I would also like to have a backButton that reverses the current animation to previous animation. I read in Apple's documentation that there is a addTarget method but I don't understand how it works or how to implement it. Please Help!
Your code should like this :
// You can define this variable globally...
var counter = 0
#IBAction func nextAnimation(_ sender: UIButton) {
if (counter == 0) {
funcAnimation1()
// Increase counter count by 1 and you can add this line to completion of animation.
// You can also disable your button interaction until your animation gets complete and that way you can handle your UI
count += 1
}
else if (counter == 1) {
funcAnimation2()
// Increase counter count by 1 and you can add this line to completion of animation.
count += 1
}
else if (counter == 2) {
funcAnimation3()
// set your counter to 0 again to loop through your animation.
counter = 0
}
}
Your Back Action should look like this:
#IBAction func backAnimation(_ sender: UIButton) {
if (counter == 0) {
funcAnimation1()
// set your counter to 2 again to loop through your animation.
count = 2
}
else if (counter == 1) {
funcAnimation2()
// decrease counter count by 1 and you can add this line to completion of animation.
// You can also disable your button interaction until your animation gets complete and that way you can handle your UI
count -= 1
}
else if (counter == 2) {
funcAnimation3()
// decrease counter count by 1 and you can add this line to completion of animation.
count -= 1
}
}
Another way!
Just set tag of button 1 (Ex. btnObj.tag=1)
And manage method(s) in action of the button like
My suggestion is also manage flag for animation like if 1st animation is in process then 2nd will be waiting for finish and after finishing 1st animation, button will be clicked so your animation will not mismatch.
var isAnimated = false;
#IBAction func myAnimationMethod(_ sender: UIButton) {
if isAnimated {return} // Or display appropriate message by alert
if (sender.tag == 1) {
isAnimated=true
funcAnimation1(...Your Code... After finish to set isAnimated=false)
sender.tag = 2
}
else if (sender.tag == 2) {
isAnimated=true
funcAnimation2(...Your Code... After finish to set isAnimated=false)
sender.tag = 3
}
else if (sender.tag == 3) {
isAnimated=true
funcAnimation3(...Your Code... After finish to set isAnimated=false)
sender.tag = 1
}
}
You can forward your animations and go back to previous animation state through a back button like this .
Step 1 : Declare two integer type variables
var tapCount = 0 //For forwarding your animations from first to third
var currentAnimation = 0 // For reversing the animation from current animation
Step 2 : In your IBAction Function
#IBAction func nextAnimation(_ sender: Any)
{
if tapCount == 0
{
if currentAnimation == 1
{
Animation2()
}
else
{
Animation1()
}
tapCount += 1
}
else if tapCount == 1
{
if currentAnimation == 2
{
Animation3()
}
else
{
Animation2()
}
tapCount += 1
}
else if tapCount == 2
{
if currentAnimation == 3
{
Animation1()
}
else
{
Animation3()
}
tapCount = 0
}
}
Step 3 : In your functions
func Animation1() {
currentAnimation = 1
print("First Animation")
}
func Animation2() {
currentAnimation = 2
print("Second Animation")
}
func Animation3() {
currentAnimation = 3
print("third Animation")
}
Step 4: Lastly For Reversing the animation from current state
#IBAction func backAnimation(_ sender: Any)
{
if currentAnimation == 2
{
Animation1()
}
else if currentAnimation == 3
{
Animation2()
}
else
{
}
tapCount = 0
}
Hope it helps !!
For addTarget(_:action:for:) method , this can be done without connecting a IBAction and declaring it in viewWillAppear or viewDidLoad as required.It will Associates a target object and action method with the control.
For example :
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
nextButton.addTarget(self, action: #selector(self. nextAnimation), for: .touchUpInside) //Declared outlet as nextButton
backButton.addTarget(self, action: #selector(self. backAnimation), for: .touchUpInside) //Declared outlet as backButton and this adds a target
}
#objc func nextAnimation(sender: UIButton) {
// Do your stuff for next animation
}
#objc func backAnimation(sender: UIButton) {
// Do your stuff for previous animation
}

make 3 random elements in the array invisible

I have 5 buttons in an array I want to make random three of these invisible when pressed on button. so the last two buttons will be visible
I tried like this:
#IBAction func eliminateChoiceClicked(_ sender: Any) {
let buttons:[UIButton] = [buttonA,buttonB,buttonC,buttonD,buttonE]
let randomNumber = Int(arc4random_uniform(UInt32(3)))
buttons[randomNumber].isHidden = !buttons[randomNumber].isHidden
}
but it takes first elements [0,1,2] and only 1 button is invisible at each press
You are currently only selecting one button. Change that to a loop to select 3. Remove the selected button from the array and make it invisible. Finally, make the remaining buttons visible:
#IBAction func eliminateChoiceClicked(_ sender: Any) {
var buttons:[UIButton] = [buttonA,buttonB,buttonC,buttonD,buttonE]
// Select 3 buttons randomly and hide them
for _ in 1...3 {
let randomNumber = Int(arc4random_uniform(UInt32(buttons.count)))
let button = buttons.remove(at: randomNumber)
button.isHidden = true
}
// Make the remaining buttons visible
for button in buttons {
button.isHidden = false
}
}
I've just written a neat extension to get a random elements from an array:
extension Array {
func randomItems(count: Int) -> [Element] {
guard count <= self.count else { fatalError() }
var notUsedElements: [Element] = self
var randomElements: [Element] = []
while randomElements.count != count {
randomElements.append(notUsedElements.remove(at: Int(arc4random_uniform(UInt32(notUsedElements.count)))))
}
return randomElements
}
}
Using this you can achieve what you want this way:
#IBAction func eliminateChoiceClicked(_ sender: Any) {
let buttons:[UIButton] = [buttonA, buttonB, buttonC, buttonD, buttonE]
// make sure all are visible at the beginning
buttons.forEach { (button) in
button.isHidden = false
}
// hide random 3:
buttons.randomItems(count: 3).forEach { (button) in
button.isHidden = true
}
}

Recognize which View calls the Tap function

I know how to add tappability to the UIImageView, however, there are 2 image views and I want to distinguish them to call the correct function. However, I can't seem to get the correct sender.
func addTappability (view imageView:UIImageView){
//add tapping function for image
let tapGestureRecognizer = UITapGestureRecognizer(target:self, action:#selector(IdCardViewController.imageTapped(_:)))
imageView.isUserInteractionEnabled = true
imageView.addGestureRecognizer(tapGestureRecognizer)
}
func imageTapped(_ sender: UIImageView) {
//Problem here, can't get correct sender
if ( sender == photoImageViewLeft) {
//do one thing
}else {
//do the other
}
}
Replace your function with this:
func imageTapped(_ sender: UITapGestureRecognizer) {
if let imageView = sender.view as? UIImageView {
if ( imageView == photoImageViewLeft ) {
print("Image1 Tapped")
}else {
print("Image2 Tapped")
}
}
}
You need to add tag where you're adding imageViews either in storyboard or in code.
then in your imageTapped() method compare them -
func imageTapped(_ sender: UIImageView) {
//Problem here, can't get correct sender
if ( sender.tag == 1) {
//do one thing
}else if(sender.tag ==2){
//do the other
}
}

Resources