найти время оставленным в setTimeout ()?

Вы можете рассчитать высоту клетки с помощью функции systemLayoutSizeFitting.

https://developer.apple.com/documentation/uikit/uiview/1622623-systemlayoutsizefitting

Например: (UICollectionViewCell является подклассом UICollectionReusableView, поэтому вы можно использовать это и для ячеек и верхнего / нижнего колонтитула)

public extension UICollectionReusableView {
    static func autoResizingView(type: T.Type) -> T {
        let nibViews = Bundle.main.loadNibNamed(T.identifier, owner: nil, options: nil)
        return nibViews?.first as? T ?? T()
    }

    static func autoLayoutSize(type: T.Type, targetWidth: CGFloat, configure: ((T) -> Void)?) -> CGSize {
        let resizingView = UICollectionReusableView.autoResizingView(type: type)
        resizingView.prepareForReuse()
        configure?(resizingView)
        resizingView.setNeedsLayout()
        resizingView.layoutIfNeeded()

        let targetSize = CGSize(width: targetWidth, height: 0)
        let calculateView: UIView
        if let contentView = (resizingView as? UICollectionViewCell)?.contentView {
            calculateView = contentView
        } else {
            calculateView = resizingView
        }
        // Calculate the size (height) using Auto Layout
        let autoLayoutSize = calculateView.systemLayoutSizeFitting(
            targetSize,
            withHorizontalFittingPriority: .required,
            verticalFittingPriority: .defaultLow)
        return autoLayoutSize
    }
}

84
задан Andreas Niedermair 17 January 2016 в 17:27
поделиться

4 ответа

Если вы не можете изменить код библиотеки, вам нужно переопределить setTimeout в соответствии с вашими целями.Вот пример того, что вы могли бы сделать:

(function () {
var nativeSetTimeout = window.setTimeout;

window.bindTimeout = function (listener, interval) {
    function setTimeout(code, delay) {
        var elapsed = 0,
            h;

        h = window.setInterval(function () {
                elapsed += interval;
                if (elapsed < delay) {
                    listener(delay - elapsed);
                } else {
                    window.clearInterval(h);
                }
            }, interval);
        return nativeSetTimeout(code, delay);
    }

    window.setTimeout = setTimeout;
    setTimeout._native = nativeSetTimeout;
};
}());
window.bindTimeout(function (t) {console.log(t + "ms remaining");}, 100);
window.setTimeout(function () {console.log("All done.");}, 1000);

Это не рабочий код, но он должен направить вас на верный путь. Обратите внимание, что вы можете привязать только одного слушателя за тайм-аут. Я не проводил обширного тестирования с этим, но он работает в Firebug.

Более надежное решение могло бы использовать ту же технику обертывания setTimeout, но вместо этого использовать карту из возвращенного timeoutId для слушателей для обработки нескольких слушателей за тайм-аут. Вы также можете подумать о переносе clearTimeout, чтобы вы могли отсоединить слушателя, если тайм-аут очищен.

25
ответ дан 24 November 2019 в 08:36
поделиться

Вы можете изменять setTimeout, чтобы сохранить время окончания каждого тайм-аута в карте и создать функцию, вызванную getTimeout , чтобы уехать на время тайм-аут с определенным идентификатором.

Это было супер решение , но я изменил его для использования немного меньшей памяти

let getTimeout = (() => { // IIFE
    let _setTimeout = setTimeout, // Reference to the original setTimeout
        map = {}; // Map of all timeouts with their end times

    setTimeout = (callback, delay) => { // Modify setTimeout
        let id = _setTimeout(callback, delay); // Run the original, and store the id
        map[id] = Date.now() + delay; // Store the end time
        return id; // Return the id
    };

    return (id) => { // The actual getTimeout function
        // If there was no timeout with that id, return NaN, otherwise, return the time left clamped to 0
        return map[id] ? Math.max(map[id] - Date.now(), 0) : NaN;
    }
})();

Использование:

// go home in 4 seconds
let redirectTimeout = setTimeout(() => {
    window.location.href = "/index.html";
}, 4000);

// display the time left until the redirect
setInterval(() => {
    document.querySelector("#countdown").innerHTML = `Time left until redirect ${getTimeout(redirectTimeout)}`;
},1);

Вот уменьшенная версия этого getTimeout IIFE:

let getTimeout=(()=>{let t=setTimeout,e={};return setTimeout=((a,o)=>{let u=t(a,o);return e[u]=Date.now()+o,u}),t=>e[t]?Math.max(e[t]-Date.now(),0):NaN})();

я надеюсь, что это столь же полезно для Вас, как это было для меня!:)

0
ответ дан 24 November 2019 в 08:36
поделиться

Стек событий Javascript работает не так, как вы думаете.

Когда создается событие тайм-аута, оно добавляется в очередь событий, но другие события могут иметь приоритет, пока это событие запускается, задерживая время выполнения и откладывая время выполнения.

Пример: Вы создаете тайм-аут с задержкой в ​​10 секунд, чтобы что-то предупредить на экране. Он будет добавлен в стек событий и будет выполняться после запуска всех текущих событий (вызывая некоторую задержку). Затем, когда истечет время ожидания, браузер по-прежнему продолжает перехватывать другие события, добавляя их в стек, что вызывает дополнительные задержки в обработке. Если пользователь щелкает или набирает много клавиш ctrl +, их события имеют приоритет над текущим стеком. Ваши 10 секунд могут превратиться в 15 секунд или больше.


При этом есть много способов подделать, сколько времени прошло. Один из способов - выполнить setInterval сразу после добавления setTimeout в стек.

Пример: Выполнить установку тайм-аута с 10-секундной задержкой (сохранить эту задержку в глобальном). Затем выполните setInterval, который запускается каждую секунду, чтобы вычесть 1 из задержки и вывести оставшуюся задержку. Из-за того, как стек событий может влиять на фактическое время (описанное выше), это все равно не будет точным, но дает счет.


Короче говоря, нет реального способа узнать оставшееся время. Есть только способы попытаться донести оценку до пользователя.

4
ответ дан 24 November 2019 в 08:36
поделиться

Нет, но у вас может быть собственный setTimeout / setInterval для анимации в вашей функции.

Допустим, ваш вопрос выглядит так:

function myQuestion() {
  // animate the progress bar for 1 sec
  animate( "progressbar", 1000 );

  // do the question stuff
  // ...
}

И ваша анимация будет обрабатываться этими двумя функциями:

function interpolate( start, end, pos ) {
  return start + ( pos * (end - start) );
}

function animate( dom, interval, delay ) {

      interval = interval || 1000;
      delay    = delay    || 10;

  var start    = Number(new Date());

  if ( typeof dom === "string" ) {
    dom = document.getElementById( dom );
  }

  function step() {

    var now     = Number(new Date()),
        elapsed = now - start,
        pos     = elapsed / interval,
        value   = ~~interpolate( 0, 500, pos ); // 0-500px (progress bar)

    dom.style.width = value + "px";

    if ( elapsed < interval )
      setTimeout( step, delay );
  }

  setTimeout( step, delay );
}
0
ответ дан 24 November 2019 в 08:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: