iOS7 UISchuyển đổi Giá trị sự kiện của nó Thay đổi: Gọi liên tục là lỗi này hay sao ..?


93

Biên tập

Nó hiện đã được sửa
Đừng thực hiện bất kỳ tinh chỉnh nào để sửa chữa nó.

Edit2

Rõ ràng vấn đề tương tự lại xảy ra trong iOS 8.0 và 8.1

Chỉnh sửa3

Nó hiện đã được sửa
Đừng thực hiện bất kỳ tinh chỉnh nào để sửa chữa nó.


Xin chào Hôm nay tôi đã thấy trong phần Gọi điện trong UISwitch'ssự kiện khi tôi chuyển sang hoặc thành Bật và ngón tay của tôi vẫn di chuyển ở bên phải cũng như bên trái. Tôi đã chỉnh sửa ảnh GIF để rõ ràng hơn với NSLog.ValueChanged:continuouslyOnOffOff

nhập mô tả hình ảnh ở đây

Phương pháp Thay đổi Giá trị của Tôi là:

- (IBAction)changeSwitch:(id)sender{

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

iOS6 giống như mã Switch hoạt động tốt như chúng tôi mong đợi:

nhập mô tả hình ảnh ở đây

vì vậy bất cứ ai có thể gợi ý cho tôi rằng chỉ gọi một lần trạng thái của nó Bật hoặc tắt. hoặc đây là một lỗi hay gì ..?

CẬP NHẬT

Đây là bản Demo của tôi về nó:

có lập trình Thêm UISwitch

từ XIB thêm UISwitch


1
Tôi vẫn gặp lỗi này trong iOS7.1 trên trình mô phỏng, chưa thử thiết bị nào, chạy xcode 5.1.1
Fonix

3
Tôi nhận được cùng một vấn đề với 7.1.2 ipad
Hassy

7
Tôi có thể thấy sự cố giống hệt / tương tự với UISwitch trong iOS 8.0 và 8.1
Sea Coast of Tibet

2
Vẫn ở đây trong 9.1. Vui lòng gửi một bản sao của openradar.appspot.com/15555929 mọi người. Đây là cách duy nhất chúng tôi sẽ khắc phục sự cố này.
Guillaume Algis,

1
Có vẻ như nó đã trở lại vào 9.3
Ben Leggiero

Câu trả lời:


44

Vui lòng xem đoạn mã sau:

-(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");
    }
}

thx cho câu trả lời như tôi đã nói tôi đã thử cả hai cách và có kết quả tương tự. atlist tôi đã biết cách thêm swtich lập trình cũng như từ xib thưa ông.
Nitin Gohel

12

Cùng một lỗi ở đây. Tôi nghĩ rằng tôi đã tìm thấy một giải pháp đơn giản. Chúng ta chỉ cần sử dụng một lệnh mới BOOLlưu trữ trạng thái trước đó của UISwitchcâu lệnh và if trong IBAction(Giá trị đã thay đổi được kích hoạt) để kiểm tra xem giá trị của công tắc đã thực sự thay đổi hay chưa.

previousValue = FALSE;

[...]

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

Không còn những hành vi kỳ quặc. Hy vọng nó giúp.


2
điều này chỉ nên nói nếu (mySwitch.on == trước đóValue)
Keegan Jay

12

Bạn có thể sử dụng UISwitch's .selectedtài sản để đảm bảo mã của bạn chỉ thực hiện một lần khi thay đổi thực tế giá trị. Tôi nghĩ đây là một giải pháp tuyệt vời vì nó tránh phải phân lớp hoặc thêm các thuộc tính mới.

 //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
    }
}

Và đây là trong Swift:

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

6
Tôi thấy điều này là đơn giản nhất.
zekel

+1 điều này vì nó đã dẫn tôi đến việc sử dụng một giải pháp tương tự là điền giá trị .tag khi tôi muốn bỏ qua logic chuyển đổi. Tôi cần logic để kích hoạt đôi khi ở cả chế độ bật và tắt nên phần trên không hoàn toàn đủ.
davidethell

9

Nếu bạn đang sử dụng quá nhiều công tắc trong ứng dụng của mình thì sẽ có vấn đề khi thay đổi mã ở tất cả những nơi có phương thức hành động của UISwitch được xác định. Bạn có thể thực hiện chuyển đổi tùy chỉnh và xử lý các sự kiện chỉ khi giá trị thay đổi.

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

Chúng tôi sẽ bỏ qua các sự kiện nếu giá trị giống với giá trị đã thay đổi. Đặt CustomSwitch trong tất cả các lớp của UISwitch trong bảng phân cảnh. Điều này sẽ giải quyết vấn đề và chỉ gọi đích một lần khi giá trị thay đổi


Điều này đã làm việc cho tôi. Nó lý tưởng ở chỗ nó không khiến mã không liên quan được thêm theo cách thủ công vào các tệp triển khai của bạn, vì nó có thể tái sử dụng và ẩn việc triển khai bên trong triển khai lớp. Đây chỉ là một thiết kế tốt. Sẽ rất tốt nếu câu trả lời này có nhiều nhận xét hơn, bởi vì tôi không thực sự hiểu tại sao tất cả các mã lại ở đó.
James C

Cảm ơn, nó đã làm việc cho tôi. Bạn có thể giải thích mã nhiều hơn một chút. @codester
Swayambhu

7

Tôi có nhiều người dùng phải đối mặt với cùng một vấn đề nên có thể đây là lỗi của UISwitchnó, vì vậy tôi đã tìm thấy giải pháp tạm thời cho nó ngay bây giờ. Tôi đã tìm thấy một gitHubtùy chỉnh KLSwitchsử dụng này bây giờ hy vọng apple sẽ sửa lỗi này trong bản cập nhật tiếp theo của xCode: -

https://github.com/KieranLafferty/KLSwitch


6

Nếu bạn không cần phản ứng ngay lập tức với sự thay đổi giá trị của công tắc, thì sau đây có thể là một giải pháp:

- (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];
  }
}

Hoạt động như một sự quyến rũ trong iOS 11.2. Trong tình huống của tôi, nó đã kích hoạt 2 sự kiện liên tiếp (trạng thái: tắt, vuốt: tắt, sự kiện thứ nhất: bật, sự kiện thứ 2: tắt), vì vậy độ trễ 0,1 giây là đủ đối với tôi và không gây chú ý cho người dùng.
Paul Semionov

3

Vấn đề này vẫn còn ở đây kể từ iOS 9.3 beta. Nếu bạn không phiền người dùng không thể kéo ra ngoài công tắc, tôi thấy rằng việc sử dụng .TouchUpInsidethay vì .ValueChangedhoạt động đáng tin cậy.


2

Tôi vẫn gặp phải vấn đề tương tự trong iOS 9.2

Tôi có giải pháp và đặt ra vì nó có thể giúp ích cho người khác

  1. Tạo biến đếm để theo dõi số lần phương thức được gọi

    int switchMethodCallCount = 0;
  2. Lưu giá trị bool cho giá trị chuyển đổi

    bool isSwitchOn = No;
  3. Trong phương thức thay đổi giá trị của Switch chỉ thực hiện hành động mong muốn cho lệnh gọi phương thức đầu tiên. Khi giá trị chuyển đổi lại thay đổi, đặt giá trị đếm và giá trị biến bool thành mặc định

    - (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];
    
    
        }
    }
    
    
    }

Tôi cũng đang đối mặt với vấn đề này trong 9.2. Tôi đã thực hiện logic của bạn và bây giờ nó đang hoạt động như tôi đã dự định.
Nick Kohrn

2

Vấn đề này xảy ra với tôi khi tôi chuyển sang các hành vi khác. Nói chung mọi thứ không thích đi từ onđến on. Đây là giải pháp đơn giản của tôi:

@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
}

Chỉ cần đảm bảo cũng đặt self.lastSwitchStatemỗi khi bạn thay đổi theo cách thủ công mySwitch.on! :)


1

Loại sự cố này thường do ValueChanged gây ra. Bạn không cần phải nhấn nút để chạy chức năng. Nó không phải là một sự kiện liên lạc. Mỗi khi bạn thay đổi công tắc thành bật / tắt theo chương trình, giá trị sẽ thay đổi và nó sẽ gọi lại hàm IBAction.

@RoNiT đã có câu trả lời đúng với:

Nhanh

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

0
DispatchQueue.main.async {
        self.mySwitch.setOn(false, animated: true)
    }

Điều này hoạt động tốt và không gọi lại chức năng bộ chọn.


0

Điều này đã làm việc cho tôi.

DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()){
    self.switch.isOn = true
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.