Почему слой перейти на другую (х, у) кадра при изменении это узловая точка? [Дубликат]

Мне кажется, что для того, чтобы быть эффективным, вам нужно: 1) создать случайное число от 0 до единицы меньше, чем количество записей в базе данных, и 2) иметь возможность выбирать строку в этой позиции. К сожалению, разные базы данных имеют разные генераторы случайных чисел и различные способы выбора строки в позиции в наборе результатов - обычно вы указываете, сколько строк нужно пропустить и сколько строк вы хотите, но для разных баз данных это делается по-разному. Вот что работает для меня в SQLite:

select * 
from Table 
limit abs(random()) % (select count(*) from Words), 1;

Это зависит от возможности использования подзапроса в предложении limit (который в SQLite является LIMIT & lt; recs для пропуска & gt;, & lt; recs взять & gt;) Выбор количества записей в таблице должен быть особенно эффективным, являясь частью метаданных базы данных, но это зависит от реализации базы данных. Кроме того, я не знаю, будет ли запрос фактически создавать набор результатов до получения N-й записи, но я надеюсь, что это не понадобится. Обратите внимание, что я не указываю предложение «order by». Возможно, лучше «упорядочить» что-то вроде первичного ключа, который будет иметь индекс - получение N-й записи из индекса может быть более быстрым, если база данных не сможет получить N-й запись из самой базы данных, не создавая набор результатов .

121
задан rounak 10 May 2015 в 14:21
поделиться

11 ответов

Раздел Layer Geometry and Transforms в Руководстве по программированию основной анимации объясняет взаимосвязь между позицией CALayer и свойствами anchorPoint. В принципе, положение слоя определяется с точки зрения местоположения anchorPoint слоя. По умолчанию, anchorPoint слоя (0.5, 0.5), который лежит в центре слоя. Когда вы устанавливаете положение слоя, вы затем устанавливаете расположение центра слоя в его системе координат суперслоя.

Поскольку позиция относительно привязанного уровня слоя, изменение этого anchorPoint во время поддержание той же позиции перемещает слой. Чтобы предотвратить это движение, вам нужно будет отрегулировать позицию слоя для учета нового anchorPoint. Один из способов, которым я это сделал, - захватить границы слоя, умножить ширину и высоту границ на старые и новые нормальные значения anchorPoint, различить два якорных точки и применить эту разницу к положению слоя.

Возможно, вы даже сможете учесть ротацию таким образом, используя CGPointApplyAffineTransform() с CGAffineTransform вашего UIView.

130
ответ дан Brad Larson 22 August 2018 в 07:05
поделиться
  • 1
    См. Пример функции от Магнуса, чтобы узнать, как ответ Брэда может быть реализован в Objective-C. – Jim Jeffers 9 February 2012 в 07:30
  • 2
    Спасибо, но я не понимаю, как связаны anchorPoint и position вместе? – dumbfingers 6 February 2013 в 14:11
  • 3
    @ ss1271 - Как я описал выше, опорная точка слоя лежит в основе его системы координат. Если он установлен на (0,5, 0,5), тогда, когда вы устанавливаете положение слоя, вы устанавливаете, где его центр будет лежать в системе координат его суперслоя. Если вы установите для anchorPoint значение (0.0, 0.5), установка положения будет установлена ​​там, где будет находиться центр его левого края. Опять же, Apple имеет несколько хороших изображений в вышеупомянутой документации (которую я обновил ссылку). – Brad Larson♦ 6 February 2013 в 17:27
  • 4
    @BradLarson thx mate, я думаю, что на этот раз я получил вашу мысль. : D – dumbfingers 7 February 2013 в 14:43
  • 5
    Я использовал метод, предоставленный Магнусом. Когда позиция и рамка NSLog выглядят правильно, но мой взгляд все еще перемещается. Любая идея почему? Это похоже на то, что новая позиция не учитывается. – Alexis 19 June 2014 в 14:29

Для меня понимание position и anchorPoint было проще всего, когда я начал сравнивать его с моим пониманием frame.origin в UIView. UIView с frame.origin = (20,30) означает, что UIView составляет 20 точек слева и 30 точек от верхней части его родительского вида. Это расстояние рассчитывается из какой точки UIView? Его вычисляли из верхнего левого угла UIView.

В слое anchorPoint отмечается точка (в нормализованной форме, то есть от 0 до 1), от которой это расстояние вычисляется так, например, layer.position = (20, 30) означает, что слой anchorPoint равен 20 точкам слева и 30 точкам от вершины его родительского слоя. По умолчанию слой anchorPoint равен (0,5, 0,5), поэтому точка вычисления расстояния находится прямо в центре слоя. Следующий пример поможет пояснить мою точку зрения:

enter image description here [/g0]

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

25
ответ дан 2cupsOfTech 22 August 2018 в 07:05
поделиться
  • 1
    Пожалуйста, можете ли вы рассказать, как я могу решить эту точку привязки, которую UIView задает с помощью автоматического макета, означает, что с автоматическим макетом мы не предполагаем, чтобы получить или установить свойства фреймов и границ. – S.J 27 August 2015 в 09:35

Для Swift 3:

func setAnchorPoint(_ anchorPoint: CGPoint, forView view: UIView) {
    var newPoint = CGPoint(x: view.bounds.size.width * anchorPoint.x, y: view.bounds.size.height * anchorPoint.y)
    var oldPoint = CGPoint(x: view.bounds.size.width * view.layer.anchorPoint.x, y: view.bounds.size.height * view.layer.anchorPoint.y)

    newPoint = newPoint.applying(view.transform)
    oldPoint = oldPoint.applying(view.transform)

    var position = view.layer.position
    position.x -= oldPoint.x
    position.x += newPoint.x

    position.y -= oldPoint.y
    position.y += newPoint.y

    view.layer.position = position
    view.layer.anchorPoint = anchorPoint
}
2
ответ дан AJ9 22 August 2018 в 07:05
поделиться
  • 1
    Спасибо за это :) Я просто вложил его в свой проект как статический func и работает как шарм: D – Kjell 12 December 2016 в 19:12

Расширение на Magnus 'great & amp; полный ответ, я создал версию, которая работает на подслоях:

-(void)setAnchorPoint:(CGPoint)anchorPoint forLayer:(CALayer *)layer
{
    CGPoint newPoint = CGPointMake(layer.bounds.size.width * anchorPoint.x, layer.bounds.size.height * anchorPoint.y);
    CGPoint oldPoint = CGPointMake(layer.bounds.size.width * layer.anchorPoint.x, layer.bounds.size.height * layer.anchorPoint.y);
    CGPoint position = layer.position;
    position.x -= oldPoint.x;
    position.x += newPoint.x;
    position.y -= oldPoint.y;
    position.y += newPoint.y;
    layer.position = position;
    layer.anchorPoint = anchorPoint;
}
0
ответ дан Charles Robertson 22 August 2018 в 07:05
поделиться

Для тех, кому это нужно, вот решение Магнуса в Swift:

func setAnchorPoint(anchorPoint: CGPoint, view: UIView) {
    var newPoint: CGPoint = CGPointMake(view.bounds.size.width * anchorPoint.x, view.bounds.size.height * anchorPoint.y)
    var oldPoint: CGPoint = CGPointMake(view.bounds.size.width * view.layer.anchorPoint.x, view.bounds.size.height * view.layer.anchorPoint.y)

    newPoint = CGPointApplyAffineTransform(newPoint, view.transform)
    oldPoint = CGPointApplyAffineTransform(oldPoint, view.transform)

    var position: CGPoint = view.layer.position

    position.x -= oldPoint.x
    position.x += newPoint.x

    position.y -= oldPoint.y
    position.y += newPoint.y

    view.setTranslatesAutoresizingMaskIntoConstraints(true)     // Added to deal with auto layout constraints
    view.layer.anchorPoint = anchorPoint
    view.layer.position = position
}
8
ответ дан Corey Davis 22 August 2018 в 07:05
поделиться
  • 1
    upvote для view.setTranslatesAutoresizingMaskIntoConstraints(true). Спасибо чувак – Oscar Yuandinata 22 March 2018 в 04:09
  • 2
    view.setTranslatesAutoresizingMaskIntoConstraints(true) необходим при использовании ограничений автоматического макета. – SamirChen 8 June 2018 в 09:56
  • 3

Ключом к решению этого вопроса было использование свойства frame, которое, как ни странно, меняется только.

Swift 2

let oldFrame = self.frame
self.layer.anchorPoint = CGPointMake(1, 1)
self.frame = oldFrame

Swift 3

let oldFrame = self.frame
self.layer.anchorPoint = CGPoint(x: 1, y: 1)
self.frame = oldFrame

Затем я делаю свой размер, где он масштабируется из anchorPoint. Затем мне нужно восстановить старый anchorPoint;

Swift 2

let oldFrame = self.frame
self.layer.anchorPoint = CGPointMake(0.5,0.5)
self.frame = oldFrame

Swift 3

let oldFrame = self.frame
self.layer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
self.frame = oldFrame

РЕДАКТИРОВАТЬ: это сбрасывается, если просмотр повернут , поскольку свойство кадра не определено, если применяется CGAffineTransform.

42
ответ дан luk2302 22 August 2018 в 07:05
поделиться
  • 1
    Просто хотел добавить, почему это работает и кажется самым простым способом: согласно документам, свойство frame является «составленным», свойство: "Значение фрейма выводится из границ, свойств привязки и местоположения. & quot; . Именно поэтому" кадр " свойство не является анимированным. – DarkDust 24 November 2010 в 10:36
  • 2
    Хороший ответ. благодаря – Peymankh 10 December 2015 в 12:40
  • 3
    Это, честно, мой предпочтительный подход. Если вы не пытаетесь манипулировать границами и располагать независимо или анимировать любой из них, обычно достаточно захватить кадр, прежде чем менять опорную точку. Нет необходимости в математике. – LucasTizma 6 October 2016 в 19:33

Если вы измените anchorPoint, его положение также изменится, ЕСЛИ вы не указали нулевую точку CGPointZero.

position.x == origin.x + anchorPoint.x;
position.y == origin.y + anchorPoint.y;
4
ответ дан Mahendra GP 22 August 2018 в 07:05
поделиться
  • 1
    Вы не можете сравнивать позицию и anchorPoint, шкалы anchorPoint от 0 до 1.0 – Edward Anthony 26 June 2016 в 22:07

Редактировать и Anchor Point знакомства UIView Праворежущий на раскадровку (Swift 3)

Это альтернативное решение, которое позволяет изменить точку привязки через инспектора атрибутов и имеет еще одно свойство, чтобы просмотреть точку привязки для подтверждение.

Создать новый файл для включения в ваш проект

import UIKit

@IBDesignable
class UIViewAnchorPoint: UIView {

    @IBInspectable var showAnchorPoint: Bool = false
    @IBInspectable var anchorPoint: CGPoint = CGPoint(x: 0.5, y: 0.5) {
        didSet {
            setAnchorPoint(anchorPoint: anchorPoint)
        }
    }

    override func draw(_ rect: CGRect) {
        if showAnchorPoint {
            let anchorPointlayer = CALayer()
            anchorPointlayer.backgroundColor = UIColor.red.cgColor
            anchorPointlayer.bounds = CGRect(x: 0, y: 0, width: 6, height: 6)
            anchorPointlayer.cornerRadius = 3

            let anchor = layer.anchorPoint
            let size = layer.bounds.size

            anchorPointlayer.position = CGPoint(x: anchor.x * size.width, y: anchor.y * size.height)
            layer.addSublayer(anchorPointlayer)
        }
    }

    func setAnchorPoint(anchorPoint: CGPoint) {
        var newPoint = CGPoint(x: bounds.size.width * anchorPoint.x, y: bounds.size.height * anchorPoint.y)
        var oldPoint = CGPoint(x: bounds.size.width * layer.anchorPoint.x, y: bounds.size.height * layer.anchorPoint.y)

        newPoint = newPoint.applying(transform)
        oldPoint = oldPoint.applying(transform)

        var position = layer.position
        position.x -= oldPoint.x
        position.x += newPoint.x

        position.y -= oldPoint.y
        position.y += newPoint.y

        layer.position = position
        layer.anchorPoint = anchorPoint
    }
}

Добавить View в Storyboard и установить пользовательский класс

Теперь установите новую опорную точку для UIView

Включение Show Anchor Point отобразит красную точку, чтобы вы лучше видеть, где точка привязки будет визуально. Вы всегда можете отключить его позже.

Это действительно помогло мне при планировании преобразований в UIViews.

5
ответ дан Mark Moeykens 22 August 2018 в 07:05
поделиться
  • 1
    Нет точки на UIView, я использовал Objective-C с Swift, добавил пользовательский класс UIView из вашего кода и включил Show anch ... но ни одна точка – Genevios 20 April 2018 в 07:31

У меня была та же проблема. Решение Брэда Ларсона отлично справилось, даже когда вид повернут. Вот его решение, переведенное в код.

-(void)setAnchorPoint:(CGPoint)anchorPoint forView:(UIView *)view
{
    CGPoint newPoint = CGPointMake(view.bounds.size.width * anchorPoint.x, 
                                   view.bounds.size.height * anchorPoint.y);
    CGPoint oldPoint = CGPointMake(view.bounds.size.width * view.layer.anchorPoint.x, 
                                   view.bounds.size.height * view.layer.anchorPoint.y);

    newPoint = CGPointApplyAffineTransform(newPoint, view.transform);
    oldPoint = CGPointApplyAffineTransform(oldPoint, view.transform);

    CGPoint position = view.layer.position;

    position.x -= oldPoint.x;
    position.x += newPoint.x;

    position.y -= oldPoint.y;
    position.y += newPoint.y;

    view.layer.position = position;
    view.layer.anchorPoint = anchorPoint;
}

И быстрый эквивалент:

func setAnchorPoint(anchorPoint: CGPoint, forView view: UIView) {
    var newPoint = CGPointMake(view.bounds.size.width * anchorPoint.x, view.bounds.size.height * anchorPoint.y)
    var oldPoint = CGPointMake(view.bounds.size.width * view.layer.anchorPoint.x, view.bounds.size.height * view.layer.anchorPoint.y)

    newPoint = CGPointApplyAffineTransform(newPoint, view.transform)
    oldPoint = CGPointApplyAffineTransform(oldPoint, view.transform)

    var position = view.layer.position
    position.x -= oldPoint.x
    position.x += newPoint.x

    position.y -= oldPoint.y
    position.y += newPoint.y

    view.layer.position = position
    view.layer.anchorPoint = anchorPoint
}
187
ответ дан redent84 22 August 2018 в 07:05
поделиться
  • 1
    подобный butta. благодаря – Jason Cragun 22 January 2012 в 06:22
  • 2
    Идеальна и имеет полный смысл, как только я смог увидеть ваш пример здесь. Спасибо за это! – Jim Jeffers 9 February 2012 в 07:29
  • 3
    Я использую этот код в своих методах awakeFromNib / initWithFrame, но он по-прежнему не работает, мне нужно обновить отображение? edit: setNeedsDisplay не работает – Adam Carter 16 December 2012 в 16:52
  • 4
    Отличный кусок кода, он отлично работал для меня – Rifinio 24 July 2014 в 11:11
  • 5
    FWIW, мне пришлось обернуть метод setAnchor в блок dispatch_async, чтобы он работал. Не уверен, почему, когда я вызываю его внутри viewDidLoad. Является ли viewDidLoad больше не в очереди основного потока? – John Fowler 23 September 2015 в 08:56

Вот ответ user945711 , настроенный для NSView в OS X. Помимо NSView, не имеющего свойства .center, кадр NSView не изменяется (вероятно, потому, что NSViews не имеют CALayer по умолчанию ), но исходное состояние CALayer изменяется при изменении привязки.

func setAnchorPoint(anchorPoint: NSPoint, view: NSView) {
    guard let layer = view.layer else { return }

    let oldOrigin = layer.frame.origin
    layer.anchorPoint = anchorPoint
    let newOrigin = layer.frame.origin

    let transition = NSMakePoint(newOrigin.x - oldOrigin.x, newOrigin.y - oldOrigin.y)
    layer.frame.origin = NSMakePoint(layer.frame.origin.x - transition.x, layer.frame.origin.y - transition.y)
}
5
ответ дан Shmidt 22 August 2018 в 07:05
поделиться

Существует такое простое решение. Это основано на ответе Кенни. Но вместо применения старого фрейма используйте его начало и новые для вычисления перехода, затем примените этот переход к центру. Он также работает с повернутым видом! Вот код, намного проще, чем другие решения:

- (void) setAnchorPoint:(CGPoint)anchorPoint forView:(UIView *)view {
   CGPoint oldOrigin = view.frame.origin;
   view.layer.anchorPoint = anchorPoint;
   CGPoint newOrigin = view.frame.origin;

   CGPoint transition;
   transition.x = newOrigin.x - oldOrigin.x;
   transition.y = newOrigin.y - oldOrigin.y;

   view.center = CGPointMake (view.center.x - transition.x, view.center.y - transition.y);
}

И версия Swift:

func setAnchorPoint(anchorPoint: CGPoint, view: UIView) {
   let oldOrigin = view.frame.origin
   view.layer.anchorPoint = anchorPoint
   let newOrigin = view.frame.origin

   let transition = CGPoint(x: newOrigin.x - oldOrigin.x, y: newOrigin.y - oldOrigin.y)

   view.center = CGPoint(x: view.center.x - transition.x, y: view.center.y - transition.y)
}
14
ответ дан user945711 22 August 2018 в 07:05
поделиться
  • 1
    Хороший небольшой метод ... работает нормально с несколькими незначительными исправлениями: Строка 3: капитал P в anchorPoint. Строка 8: TRANS.Y = NEW - OLD – bob 6 December 2013 в 10:26
  • 2
    Исправлено, спасибо! – user945711 6 December 2013 в 14:54
  • 3
    Это работало для меня как шарм. Спасибо и поддержал ... – NSPratik 19 June 2015 в 11:29
  • 4
    все еще я в замешательстве, как я могу его использовать. Сейчас я столкнулся с той же проблемой, что и вращение моего представления с помощью uigesturerotation. Я странно, что, где я должен назвать этот метод. Если я звоню в обработчик распознавания жестов. Это делает вид исчезающим. – JAck 16 August 2016 в 09:30
  • 5
    Этот ответ настолько мил, что у меня сейчас диабет. – GeneCode 23 April 2017 в 04:37
Другие вопросы по тегам:

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