문제

사용자가 특정 기간 동안 화면을 터치하지 않은 경우 특정 조치를 취하는 기능을 구현 한 사람이 있습니까? 나는 그렇게하는 가장 좋은 방법을 알아 내려고 노력하고 있습니다.

UIAPplication에는이 다소 관련된 방법이 있습니다.

[UIApplication sharedApplication].idleTimerDisabled;

대신 다음과 같은 것이 있다면 좋을 것입니다.

NSTimeInterval timeElapsed = [UIApplication sharedApplication].idleTimeElapsed;

그런 다음 타이머를 설정하고 주기적 으로이 값을 확인하고 임계 값을 초과 할 때 약간의 조치를 취할 수 있습니다.

바라건대 그것은 내가 찾고있는 것을 설명합니다. 누구 든지이 문제를 이미 다루었거나 어떻게 할 것인지에 대한 생각이 있습니까? 감사.

도움이 되었습니까?

해결책

내가 찾고 있던 대답은 다음과 같습니다.

응용 프로그램이 서브 클래스 UIAPplication을 대표하십시오. 구현 파일에서 SendEvent : SO와 같은 메소드를 재정의합니다.

- (void)sendEvent:(UIEvent *)event {
    [super sendEvent:event];

    // Only want to reset the timer on a Began touch or an Ended touch, to reduce the number of timer resets.
    NSSet *allTouches = [event allTouches];
    if ([allTouches count] > 0) {
        // allTouches count only ever seems to be 1, so anyObject works here.
        UITouchPhase phase = ((UITouch *)[allTouches anyObject]).phase;
        if (phase == UITouchPhaseBegan || phase == UITouchPhaseEnded)
            [self resetIdleTimer];
    }
}

- (void)resetIdleTimer {
    if (idleTimer) {
        [idleTimer invalidate];
        [idleTimer release];
    }

    idleTimer = [[NSTimer scheduledTimerWithTimeInterval:maxIdleTime target:self selector:@selector(idleTimerExceeded) userInfo:nil repeats:NO] retain];
}

- (void)idleTimerExceeded {
    NSLog(@"idle time exceeded");
}

MaxIdletime 및 Idletimer가 인스턴스 변수 인 경우.

이 작업을 수행하려면 Main.m을 수정하여 UIAPplicationMain에게 대의원 클래스 (이 예에서 AppDelegate)를 주요 클래스로 사용하도록 지시해야합니다.

int retVal = UIApplicationMain(argc, argv, @"AppDelegate", @"AppDelegate");

다른 팁

uiapplication을 서브 클래스링 할 필요가없는 유휴 타이머 솔루션의 변형이 있습니다. 특정 UIViewController 서브 클래스에서 작동하므로 대화식 앱이나 게임과 같은 뷰 컨트롤러가 하나만 있거나 특정보기 컨트롤러에서 유휴 시간 초과 만 처리하려는 경우 유용합니다.

또한 유휴 타이머가 재설정 될 때마다 NSTIMER 객체를 다시 제작하지 않습니다. 타이머가 발사되는 경우에만 새로운 것을 만듭니다.

코드가 호출 할 수 있습니다 resetIdleTimer 유휴 타이머를 무효화해야 할 다른 이벤트 (예 : 상당한 가속도계 입력).

@interface MainViewController : UIViewController
{
    NSTimer *idleTimer;
}
@end

#define kMaxIdleTimeSeconds 60.0

@implementation MainViewController

#pragma mark -
#pragma mark Handling idle timeout

- (void)resetIdleTimer {
    if (!idleTimer) {
        idleTimer = [[NSTimer scheduledTimerWithTimeInterval:kMaxIdleTimeSeconds
                                                      target:self
                                                    selector:@selector(idleTimerExceeded)
                                                    userInfo:nil
                                                     repeats:NO] retain];
    }
    else {
        if (fabs([idleTimer.fireDate timeIntervalSinceNow]) < kMaxIdleTimeSeconds-1.0) {
            [idleTimer setFireDate:[NSDate dateWithTimeIntervalSinceNow:kMaxIdleTimeSeconds]];
        }
    }
}

- (void)idleTimerExceeded {
    [idleTimer release]; idleTimer = nil;
    [self startScreenSaverOrSomethingInteresting];
    [self resetIdleTimer];
}

- (UIResponder *)nextResponder {
    [self resetIdleTimer];
    return [super nextResponder];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    [self resetIdleTimer];
}

@end

(간결성을 위해 제외 된 메모리 정리 코드.)

Swift v 3.1의 경우

AppDelegate 에서이 라인을 언급하는 것을 잊지 마십시오 //@uiapplicationMain

extension NSNotification.Name {
   public static let TimeOutUserInteraction: NSNotification.Name = NSNotification.Name(rawValue: "TimeOutUserInteraction")
}


class InterractionUIApplication: UIApplication {

static let ApplicationDidTimoutNotification = "AppTimout"

// The timeout in seconds for when to fire the idle timer.
let timeoutInSeconds: TimeInterval = 15 * 60

var idleTimer: Timer?

// Listen for any touch. If the screen receives a touch, the timer is reset.
override func sendEvent(_ event: UIEvent) {
    super.sendEvent(event)

    if idleTimer != nil {
        self.resetIdleTimer()
    }

    if let touches = event.allTouches {
        for touch in touches {
            if touch.phase == UITouchPhase.began {
                self.resetIdleTimer()
            }
        }
    }
}

// Resent the timer because there was user interaction.
func resetIdleTimer() {
    if let idleTimer = idleTimer {
        idleTimer.invalidate()
    }

    idleTimer = Timer.scheduledTimer(timeInterval: timeoutInSeconds, target: self, selector: #selector(self.idleTimerExceeded), userInfo: nil, repeats: false)
}

// If the timer reaches the limit as defined in timeoutInSeconds, post this notification.
func idleTimerExceeded() {
    NotificationCenter.default.post(name:Notification.Name.TimeOutUserInteraction, object: nil)
   }
} 

main.swif 파일을 만들고 이것을 추가하십시오 (이름은 중요합니다)

CommandLine.unsafeArgv.withMemoryRebound(to: UnsafeMutablePointer<Int8>.self, capacity: Int(CommandLine.argc)) {argv in
_ = UIApplicationMain(CommandLine.argc, argv, NSStringFromClass(InterractionUIApplication.self), NSStringFromClass(AppDelegate.self))
}

다른 클래스에서 알림 관찰

NotificationCenter.default.addObserver(self, selector: #selector(someFuncitonName), name: Notification.Name.TimeOutUserInteraction, object: nil)

이 스레드는 큰 도움이되었으며 알림을 보내는 UIWindow 서브 클래스로 싸 었습니다. 실제 느슨한 커플 링으로 만들기 위해 알림을 선택했지만 쉽게 대의원을 추가 할 수 있습니다.

여기에 요점이 있습니다.

http://gist.github.com/365998

또한 UIAPPLICATION 서브 클래스 문제의 이유는 NIB가 응용 프로그램과 대의원이 포함되어 있기 때문에 2 개의 UIAPPLICATION 객체를 생성하기 위해 설정 되었기 때문입니다. Ui -Window 서브 클래스는 훌륭하게 작동합니다.

모션에 의해 제어되는 게임 에서이 문제를 해결했습니다. 즉, 화면 잠금 장치가 비활성화되어 있지만 메뉴 모드에서 다시 활성화해야합니다. 타이머 대신 모든 통화를 캡슐화했습니다 setIdleTimerDisabled 다음 방법을 제공하는 작은 클래스 내에서 :

- (void) enableIdleTimerDelayed {
    [self performSelector:@selector (enableIdleTimer) withObject:nil afterDelay:60];
}

- (void) enableIdleTimer {
    [NSObject cancelPreviousPerformRequestsWithTarget:self];
    [[UIApplication sharedApplication] setIdleTimerDisabled:NO];
}

- (void) disableIdleTimer {
    [NSObject cancelPreviousPerformRequestsWithTarget:self];
    [[UIApplication sharedApplication] setIdleTimerDisabled:YES];
}

disableIdleTimer 유휴 타이머를 비활성화하고 enableIdleTimerDelayed 메뉴를 입력하거나 유휴 타이머를 활성화하여 실행해야 할 때 enableIdleTimer AppDelegate에서 호출됩니다 applicationWillResignActive 방법 모든 변경 사항이 시스템 기본 동작에 올바르게 재설정되도록하는 방법.
기사를 작성하고 싱글 톤 클래스 IdletimerManager의 코드를 제공했습니다. 아이폰 게임에서 유휴 타이머 처리

활동을 감지하는 또 다른 방법은 다음과 같습니다.

타이머가 추가됩니다 UITrackingRunLoopMode, 그래서 그것은 있다면 해고 할 수 있습니다 UITracking 활동. 또한 모든 터치 이벤트에 대해 스팸을 보내지 않는 좋은 이점이 있으므로 마지막에 활동이 있는지 알 수 있습니다. ACTIVITY_DETECT_TIMER_RESOLUTION 초. 나는 선택기를 지명했다 keepAlive 이에 대한 적절한 사용 사례처럼 보입니다. 물론 최근 활동이 있었던 정보로 원하는 것을 할 수 있습니다.

_touchesTimer = [NSTimer timerWithTimeInterval:ACTIVITY_DETECT_TIMER_RESOLUTION
                                        target:self
                                      selector:@selector(keepAlive)
                                      userInfo:nil
                                       repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:_touchesTimer forMode:UITrackingRunLoopMode];

실제로 서브 클래스 아이디어는 훌륭하게 작동합니다. 대의원으로 만들지 마십시오 UIApplication 아강. 상속하는 다른 파일을 만듭니다 UIApplication (예 : myapp). IB에서 클래스를 설정하십시오 fileOwner 대상 myApp 그리고 myapp.m에서 sendEvent 위와 같은 방법. main.m do :

int retVal = UIApplicationMain(argc,argv,@"myApp.m",@"myApp.m")

et voilà!

궁극적으로 유휴 상태로 생각하는 것을 정의해야합니다. 유휴 상태 인 경우 사용자의 결과가 화면을 만지지 않거나 컴퓨팅 리소스를 사용하지 않는 경우 시스템 상태입니까? 많은 응용 프로그램에서 사용자가 터치 스크린을 통해 장치와 적극적으로 상호 작용하지 않더라도 무언가를 수행 할 수 있습니다. 사용자는 아마도 장치의 개념과 화면 디밍을 통해 발생한다는 통지에 익숙 할 것입니다. 반드시 유휴 상태에서 어떤 일이 일어날 것으로 예상되는 것은 아닙니다. 조심해야합니다. 당신이 할 일에 대해. 그러나 원래 진술로 돌아가서 첫 번째 사례를 정의라고 생각한다면이 작업을 수행하는 쉬운 방법은 없습니다. 각 터치 이벤트를 받아야하며, 수신 된 시간을 주목하면서 필요에 따라 응답자 체인에 전달해야합니다. 그것은 당신에게 유휴 계산을위한 기초를 줄 것입니다. 두 번째 사례가 귀하의 정의로 간주되면, 그 당시 논리를 시도하고 수행하기 위해 NSPOST를 사용하여 재생할 수 있습니다.

개별 컨트롤러가 무엇이든 할 필요 없이이 앱을 넓게 수행 할 수있는 방법이 있습니다. 터치를 취소하지 않는 제스처 인식기를 추가하십시오. 이런 식으로, 모든 터치는 타이머에 대해 추적되며 다른 터치와 제스처는 전혀 영향을받지 않으므로 다른 사람은 그것에 대해 알아야 할 사람이 없습니다.

fileprivate var timer ... //timer logic here

@objc public class CatchAllGesture : UIGestureRecognizer {
    override public func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesBegan(touches, with: event)
    }
    override public func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
        //reset your timer here
        state = .failed
        super.touchesEnded(touches, with: event)
    }
    override public func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
        super.touchesMoved(touches, with: event)
    }
}

@objc extension YOURAPPAppDelegate {

    func addGesture () {
        let aGesture = CatchAllGesture(target: nil, action: nil)
        aGesture.cancelsTouchesInView = false
        self.window.addGestureRecognizer(aGesture)
    }
}

앱 Delegate 's Mind Finish Launch Method에서 호출 Addgesture만으로도 모두 설정되었습니다. 모든 터치는 다른 사람의 기능을 방지하지 않고 포획의 방법을 거치게됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top