【问题标题】:iOS7 UISwitch its Event ValueChanged: Calling continuously is this Bug or what..?iOS7 UISwitch its Event ValueChanged: 连续调用是这个Bug还是什么..?
【发布时间】:2013-11-06 20:13:09
【问题描述】:

编辑

现在已修复
不要做任何调整来修复它。

编辑2

显然同样的问题在 iOS 8.0 和 8.1 中再次发生

编辑3

现在已修复
不要做任何调整来修复它。


嗨,今天我在UISwitch's 事件ValueChanged: 中看到调用continuously 而我将On 更改为OffOff 到开,我的手指仍然在右侧和左侧移动.我使用 NSLog 制作了 GIF 图像,以便更清晰。

我的值更改方法是:

- (IBAction)changeSwitch:(id)sender{

    if([sender isOn]){
        NSLog(@"Switch is ON");
    } else{
        NSLog(@"Switch is OFF");
    }
    
}

iOS6 的 Switch 代码和我们预期的一样工作正常:

所以任何人都可以建议我只在其状态打开或关闭时调用一次。或者这是一个错误还是什么..?

更新

这是我的演示:

programmatic Add UISwitch

from XIB adding UISwitch

【问题讨论】:

  • 我仍然在模拟器上的 iOS7.1 中遇到此错误,尚未尝试设备,运行 xcode 5.1.1
  • 我在 7.1.2 ipad 上遇到了同样的问题
  • 我可以在 iOS 8.0 和 8.1 中看到与 UISwitch 相同/相似的问题
  • 在 9.1 中仍然存在。请提交openradar.appspot.com/15555929 所有人的副本。这是我们解决这个问题的唯一方法。
  • 好像又回到了9.3

标签: ios7.1 ios9.2 ios iphone ios7 xcode5 uiswitch


【解决方案1】:

这对我有用。

DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()){
    self.switch.isOn = true
}

【讨论】:

    【解决方案2】:
    DispatchQueue.main.async {
            self.mySwitch.setOn(false, animated: true)
        }
    

    这工作正常,不会再次调用选择器函数。

    【讨论】:

      【解决方案3】:

      这类问题通常是由 ValueChanged 引起的。您无需按下按钮即可使功能运行。这不是触摸事件。每次您以编程方式将开关更改为开/关时,值都会更改并且它会再次调用 IBAction 函数。

      @RoNiT 的正确答案是:

      斯威夫特

      func doToggle(switch: UISwitch) {
          if switch.on && !switch.selected {
              switch.selected = true
              // SWITCH ACTUALLY CHANGED -- DO SOMETHING HERE
          } else {
              switch.selected = false
          }
      }
      

      【讨论】:

        【解决方案4】:

        当我将开关与其他行为联系起来时,这个问题困扰着我。一般来说,事情不喜欢从on 转到on。这是我的简单解决方案:

        @interface MyView : UIView
        @parameter (assign) BOOL lastSwitchState;
        @parameter (strong) IBOutlet UISwitch *mySwitch;
        @end
        
        @implementation MyView
        
        // Standard stuff goes here
        
        - (void)mySetupMethodThatsCalledWhenever
        {
            [self.mySwitch addTarget:self action:@selector(switchToggled:) forControlEvents:UIControlEventValueChanged];
        }
        
        - (void)switchToggled:(UISwitch *)someSwitch
        {
            BOOL newSwitchState = self.mySwitch.on;
            if (newSwitchState == self.lastSwitchState)
            {
                return;
            }
            self.lastSwitchState = newSwitchState;
        
            // Do your thing
        }
        

        每次手动更改mySwitch.on时,请务必同时设置self.lastSwitchState! :)

        【讨论】:

          【解决方案5】:

          这个问题在 iOS 9.3 测试版中仍然存在。如果您不介意用户无法拖动到开关之外,我发现使用.TouchUpInside 而不是.ValueChanged 可以可靠地工作。

          【讨论】:

            【解决方案6】:

            您可以使用UISwitch.selected 属性来确保您的代码仅在值实际更改时执行一次。我认为这是一个很好的解决方案,因为它避免了子类化或添加新属性。

             //Add action for `ValueChanged`
             [toggleSwitch addTarget:self action:@selector(switchTwisted:) forControlEvents:UIControlEventValueChanged];
            
             //Handle action
            - (void)switchTwisted:(UISwitch *)twistedSwitch
            {
                if ([twistedSwitch isOn] && (![twistedSwitch isSelected]))
                {
                    [twistedSwitch setSelected:YES];
            
                    //Write code for SwitchON Action
                }
                else if ((![twistedSwitch isOn]) && [twistedSwitch isSelected])
                {
                    [twistedSwitch setSelected:NO];
            
                    //Write code for SwitchOFF Action
                }
            }
            

            它在 Swift 中:

            func doToggle(switch: UISwitch) {
                if switch.on && !switch.selected {
                    switch.selected = true
                    // SWITCH ACTUALLY CHANGED -- DO SOMETHING HERE
                } else {
                    switch.selected = false
                }
            }
            

            【讨论】:

            • 我觉得这个最简单。
            • +1 是因为当我想忽略切换逻辑时,它导致我使用类似的填充 .tag 值的解决方案。我有时需要在开启和关闭模式下触发逻辑,所以上述内容还不够。
            【解决方案7】:

            我在 iOS 9.2 中仍然面临同样的问题

            我得到了解决方案并冒充它可能会帮助其他人

            1. 创建计数变量以跟踪方法被调用的次数

              int switchMethodCallCount = 0;
              
            2. 保存开关值的布尔值

              bool isSwitchOn = No;
              
            3. 在 Switch 的值更改方法中,仅对第一个方法调用执行期望的操作。当 switch 值再次将 set count 值和 t bool 变量值更改为默认值时

              - (IBAction)frontCameraCaptureSwitchToggle:(id)sender {
              
              
              
              //This method will be called multiple times if user drags on Switch,
              //But desire action should be perform only on first call of this method
              
              
              //1. 'switchMethodCallCount' variable is maintain to check number of calles to method,
              //2. Action is peform for 'switchMethodCallCount = 1' i.e first call
              //3. When switch value change to another state, 'switchMethodCallCount' is reset and desire action perform
              
              switchMethodCallCount++ ;
              
              //NSLog(@"Count --> %d", switchMethodCallCount);
              
              if (switchMethodCallCount == 1) {
              
              //NSLog(@"**************Perform Acction******************");
              
              isSwitchOn = frontCameraCaptureSwitch.on
              
              [self doStuff];
              
              }
              else
              {
              //NSLog(@"Do not perform");
              
              
              if (frontCameraCaptureSwitch.on != isSwitchOn) {
              
                  switchMethodCallCount = 0;
              
                  isSwitchOn = frontCameraCaptureSwitch.on
              
                  //NSLog(@"Count again start");
              
                  //call value change method again 
                  [self frontCameraCaptureSwitchToggle:frontCameraCaptureSwitch];
              
              
                  }
              }
              
              
              }
              

            【讨论】:

            • 我在 9.2 中仍然面临这个问题。我实现了你的逻辑,现在它正在按我的预期工作。
            【解决方案8】:

            请看以下代码:

            -(void)viewDidLoad
            {
                [super viewDidLoad];    
                UISwitch *mySwitch = [[UISwitch alloc] initWithFrame:CGRectMake(130, 235, 0, 0)];    
                [mySwitch addTarget:self action:@selector(changeSwitch:) forControlEvents:UIControlEventValueChanged];
                [self.view addSubview:mySwitch];
            }
            
            - (void)changeSwitch:(id)sender{
                if([sender isOn]){
                    NSLog(@"Switch is ON");
                } else{
                    NSLog(@"Switch is OFF");
                }
            }
            

            【讨论】:

            • 谢谢回答,因为我说我正在尝试两种方式并得到相同的结果。 atlist 我知道如何添加 swtich 程序化以及来自 xib 先生。
            【解决方案9】:

            如果您在应用程序中使用了这么多开关,那么在所有需要更改的地方更改代码都会有问题 定义了 UISwitch 的 action 方法。只有当值发生变化时,您才能进行自定义切换和处理事件。

            CustomSwitch.h

            #import <UIKit/UIKit.h>
            
            @interface Care4TodayCustomSwitch : UISwitch
            @end
            

            CustomSwitch.m

            @interface CustomSwitch(){
                BOOL previousValue;
            }
            @end
            
            @implementation CustomSwitch
            
            
            
            - (id)initWithFrame:(CGRect)frame
            {
                self = [super initWithFrame:frame];
                if (self) {
                    // Initialization code
                    previousValue = self.isOn;
                }
                return self;
            }
            
            
            -(void)awakeFromNib{
                [super awakeFromNib];
                previousValue = self.isOn;
                self.exclusiveTouch = YES;
            }
            
            
            - (void)setOn:(BOOL)on animated:(BOOL)animated{
            
                [super setOn:on animated:animated];
                previousValue = on;
            }
            
            
            -(void)sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event{
            
                if(previousValue != self.isOn){
                    for (id targetForEvent in [self allTargets]) {
                        for (id actionForEvent in [self actionsForTarget:targetForEvent forControlEvent:UIControlEventValueChanged]) {
                            [super sendAction:NSSelectorFromString(actionForEvent) to:targetForEvent forEvent:event];
                        }
                    }
                    previousValue = self.isOn;
                }
            }
            
            @end
            

            如果值与更改的值相同,我们将忽略事件。将 CustomSwitch 放在情节提要中 UISwitch 的所有类中。这将解决问题并在值更改时仅调用一次目标

            【讨论】:

            • 这对我有用。这是理想的,因为它不会导致在您的实现文件中手动添加无关的代码,因为它是可重用的并将其实现隐藏在类实现中。这只是很好的设计。如果这个答案有更多的 cmets 那就太好了,因为我真的不明白为什么所有的代码都在那里。
            • 谢谢,它对我有用。你能解释一下代码吗? @codester
            【解决方案10】:

            这里有同样的错误。我想我找到了一个简单的解决方法。我们只需要使用一个新的BOOL 来存储UISwitch 的先前状态,并在我们的IBAction 中使用一个if 语句(Value Changed 被触发)来检查switch 的值是否真的发生了变化。

            previousValue = FALSE;
            
            [...]
            
            -(IBAction)mySwitchIBAction {
                if(mySwitch.on == previousValue)
                    return;
                // resetting the new switch value to the flag
                previousValue = mySwitch.on;
             }
            

            不再有奇怪的行为。希望对您有所帮助。

            【讨论】:

            • 这应该只是说 if(mySwitch.on == previousValue)
            【解决方案11】:

            如果您不需要立即对开关的值更改做出反应,以下可能是一种解决方案:

            - (IBAction)switchChanged:(id)sender {
              [NSObject cancelPreviousPerformRequestsWithTarget:self];
            
              if ([switch isOn]) {
                  [self performSelector:@selector(enable) withObject:nil afterDelay:2];
              } else {
                  [self performSelector:@selector(disable) withObject:nil afterDelay:2];
              }
            }
            

            【讨论】:

            • 在 iOS 11.2 中的工作就像一个魅力。在我的情况下,它连续触发了 2 个事件(状态:关闭,滑动:关闭,第一个事件:打开,第二个事件:关闭),所以 0.1 秒的延迟对我来说就足够了,用户不会注意到。跨度>
            【解决方案12】:

            我有很多用户面临同样的问题,所以这可能是UISwitch 的错误,所以我刚刚找到了临时解决方案。我找到了一个 gitHub 自定义 KLSwitch 现在使用它希望苹果会在下一次 xCode 更新中解决这个问题:-

            https://github.com/KieranLafferty/KLSwitch

            【讨论】:

              猜你喜欢
              • 2023-03-19
              • 2020-01-25
              • 1970-01-01
              • 2013-06-15
              • 1970-01-01
              • 2014-08-21
              • 1970-01-01
              • 2012-01-22
              • 1970-01-01
              相关资源
              最近更新 更多