8

My goal is to create a slotmachine, in which the rows are spinning and one by one, they need to stop spinning, one by one. However, to make it look nice, the rows needs to spin atleast like 3 seconds. I think PickerView is the best option for this, since I have no idea on how to make this work in a different way.

When this is my code:

self.slotMachine.selectRow(99, inComponent: 1, animated: true)

The PickerView will go to row 99, but in 1 second. How can I control this second (and extend the selecting row process)? One condition is it should look nice and feel like you are playing a slot machine. I tried this:

    UIView.animate(withDuration: 3.0, delay: 0, animations: { () -> Void in
        self.slotMachine.selectRow(99, inComponent: 1, animated: true)
    }, completion: nil )

But this did not work.

Thanks.

J. Doe
  • 12,159
  • 9
  • 60
  • 114
  • Check out http://stackoverflow.com/questions/3832474/uitableview-row-animation-duration-and-completion-callback You might find something that helps. – rmaddy May 02 '17 at 14:34
  • *"But this didn't work."* Asking the obvious, but... what happened? Why didn't it work? And if you are going to say "in one second, not three", you probably need to - at best - subclass UIPickerView and at worst, design your own. –  May 13 '17 at 22:42
  • Take a look at this cocoacontrol: https://www.cocoacontrols.com/controls/zcslotmachine – Mar-k May 16 '17 at 09:25
  • @Mar-k that is the animation I need, but I can not understand Obj-c yet :( jammer. – J. Doe May 16 '17 at 16:19
  • You can include the pod file in your Swift project, there are plenty of tutorials for that. Than you can call the methods of the pod. @J.Doe – Mar-k May 16 '17 at 19:31
  • There is no pod file in the link you supplied & I can nowhere find a pod file on GitHub for Swift for UIPickerView... – J. Doe May 16 '17 at 20:11
  • Just an FYI, most of the slot machines do not use picker views or tableviews for the spinning. They will just use gifs or animated images to represent it spinning. I know it doesn't answer your question, but it may help you get to the final result more easily. – Alexander Li May 17 '17 at 00:15
  • @J.Doe i have created the Swift version of that ObjC library, let me know if you need that. – Shabir jan May 17 '17 at 16:59
  • @Shabirjan that would be amazing! :) – J. Doe May 17 '17 at 17:50
  • @Shabirjan Your git project really helped me out. Thank you! – bhakti123 Mar 11 '18 at 06:50

2 Answers2

3

Swift version:

import UIKit

class ViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate {

    var picker: UIPickerView!

    override func viewDidLoad() {
        super.viewDidLoad()

        picker = UIPickerView(frame: CGRect(x: 0, y: 100, width: 100, height: 375));
        view.addSubview(picker)
        picker.dataSource = self
        picker.delegate = self

        let button = UIButton(frame: CGRect(x: 50, y: 50, width: 100, height: 100))
        button.backgroundColor = .red
        button.addTarget(self, action: #selector(trigger), for: .touchUpInside)
        view.addSubview(button)
    }

    func trigger() {
        let timer = Timer.scheduledTimer(timeInterval: 0.25, target: self, selector: #selector(scrollRandomly), userInfo: nil, repeats: true);
        //call the block 3 seconds later
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(3*NSEC_PER_SEC))/Double(NSEC_PER_SEC)) {
            timer.invalidate()
            //always select 500 finally
            self.picker.selectRow(500, inComponent: 0, animated: true)
        }
    }

    func scrollRandomly() {
        let row:Int = Int(arc4random() % 1000);
        picker.selectRow(row, inComponent: 0, animated: true)
    }


    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return 1000
    }

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return row.description
    }
}

OC version:

#import "ViewController.h"

@interface ViewController () <UIPickerViewDelegate, UIPickerViewDataSource>
@property (weak, nonatomic) UIPickerView *picker;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    UIPickerView *picker = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 100, 100, 375)];
    self.picker = picker;
    [self.view addSubview:picker];
    picker.delegate = self;
    picker.showsSelectionIndicator = true;

    UIButton *b = [[UIButton alloc] initWithFrame:CGRectMake(50, 50, 100, 100)];
    b.backgroundColor = [UIColor redColor];
    [self.view addSubview:b];
    [b addTarget:self action:@selector(bbbb) forControlEvents:UIControlEventTouchUpInside];
}

- (void)bbbb {


    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.25 repeats:true block:^(NSTimer * _Nonnull timer) {
        NSInteger row = arc4random()%1000;
        [self.picker selectRow:row inComponent:0 animated:true];
    }];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [timer invalidate];
        [self.picker selectRow:500 inComponent:0 animated:true];
    });

}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
    return 1000;
}

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
    return 1;
}


- (nullable NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
    return [NSString stringWithFormat:@"%ld",row];
}

@end
Andy Darwin
  • 478
  • 5
  • 19
2

You could use a timer and select the cells one by one like this:

var timer = Timer()
var currentRow = 0

override func viewDidLoad() {
    super.viewDidLoad()
    timer = Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
}

func timerAction() {
    currentRow += 1
    self.slotMachine.selectRow(currentRow, inComponent: 1, animated: true)
    if(currentRow == 99){
        timer.invalidate()
    }
}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
JP Aquino
  • 3,946
  • 1
  • 23
  • 25