Efekt paralaksy iOS 7 w moim kontrolerze widoku


112

Rozwijam aplikację na iOS 7 w Objective-C. Mam ekran w mojej aplikacji z kilkoma przyciskami i ładnym obrazem tła. (To prosty xib z UIButtonsgórną częścią a UIImageView.)

Pomyślałem, że byłoby fajnie, gdyby te przyciski miały efekt paralaksy, który ma ekran główny iOS 7, więc jeśli przechylisz telefon, zobaczysz tło.

Jak mogę zaimplementować ten efekt we własnej aplikacji?


1
Zajrzyj do tej biblioteki: github.com/Przytua/UIView-MWParallax
— CRDave

Odpowiedzi:


273

W iOS 7 firma Apple wprowadziła UIMotionEffectdodawanie efektów ruchu, które są związane z orientacją urządzenia użytkownika. Na przykład, aby emulować efekt paralaksy na ekranie głównym, możesz użyć podklasy UIInterpolationMotionEffect, jak wyjaśniono tutaj i tutaj , z kilkoma wierszami kodu.

Cel-C :

// Set vertical effect
UIInterpolatingMotionEffect *verticalMotionEffect = 
  [[UIInterpolatingMotionEffect alloc] 
  initWithKeyPath:@"center.y"
             type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
verticalMotionEffect.minimumRelativeValue = @(-10);
verticalMotionEffect.maximumRelativeValue = @(10);

// Set horizontal effect 
UIInterpolatingMotionEffect *horizontalMotionEffect = 
  [[UIInterpolatingMotionEffect alloc] 
  initWithKeyPath:@"center.x"     
             type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
horizontalMotionEffect.minimumRelativeValue = @(-10);
horizontalMotionEffect.maximumRelativeValue = @(10);

// Create group to combine both
UIMotionEffectGroup *group = [UIMotionEffectGroup new];
group.motionEffects = @[horizontalMotionEffect, verticalMotionEffect];

// Add both effects to your view
[myBackgroundView addMotionEffect:group];

Swift (dzięki @Lucas):

// Set vertical effect
let verticalMotionEffect = UIInterpolatingMotionEffect(keyPath: "center.y",
type: .TiltAlongVerticalAxis)
verticalMotionEffect.minimumRelativeValue = -10
verticalMotionEffect.maximumRelativeValue = 10

// Set horizontal effect
let horizontalMotionEffect = UIInterpolatingMotionEffect(keyPath: "center.x",
    type: .TiltAlongHorizontalAxis)
horizontalMotionEffect.minimumRelativeValue = -10
horizontalMotionEffect.maximumRelativeValue = 10

// Create group to combine both
let group = UIMotionEffectGroup()
group.motionEffects = [horizontalMotionEffect, verticalMotionEffect]

// Add both effects to your view
myBackgroundView.addMotionEffect(group)

Możesz również znaleźć kilka bibliotek, aby to zrobić łatwiej lub dodać tę funkcję do starszych wersji iOS:


2
NGAParallaxMotion jest przeznaczone dla systemu iOS 7+, a nie dla starszych wersji iOS. Udostępnia kategorię dla UIView, umożliwiając ustawienie wartości .parallaxIntensity, konfigurując parametry UIMotionEffect za pomocą jednej linii kodu.
— Dan Fabulich,

2
Dzięki! Zaktualizowałem odpowiedź, aby uwzględnić obsługiwane wersje i wymagania.
— veducm

1
Właściwie chcesz dodać efekt ruchu do widoku tła, a nie widoku z przodu. Ale poza tym ten kod działa świetnie! Dzięki.
— gstroup

1
Czy ktoś wie, jak sprawdzić, czy użytkownik wyłączył efekty? stackoverflow.com/questions/19132000/…
— Eric

3
@gstroup Właściwie na ekranie głównym porusza się zarówno pierwszy plan, jak i tło. Ale gdybyś wybrał tylko jedną warstwę, aby zastosować efekt paralaksy, zgadzam się, że tło byłoby prawdopodobnie najlepsze.
— Rubberduck,

16

Przetłumaczone na szybkie na wypadek, gdyby ktoś był leniwy. Zagłosuj na odpowiedź @veducm , jeśli uznasz to za przydatne

@IBOutlet var background : UIImageView!

func parallaxEffectOnBackground() {
    let relativeMotionValue = 50
    var verticalMotionEffect : UIInterpolatingMotionEffect = UIInterpolatingMotionEffect(keyPath: "center.y",
        type: .TiltAlongVerticalAxis)
    verticalMotionEffect.minimumRelativeValue = -relativeMotionValue
    verticalMotionEffect.maximumRelativeValue = relativeMotionValue

    var horizontalMotionEffect : UIInterpolatingMotionEffect = UIInterpolatingMotionEffect(keyPath: "center.x",
        type: .TiltAlongHorizontalAxis)
    horizontalMotionEffect.minimumRelativeValue = -relativeMotionValue
    horizontalMotionEffect.maximumRelativeValue = relativeMotionValue

    var group : UIMotionEffectGroup = UIMotionEffectGroup()
    group.motionEffects = [horizontalMotionEffect, verticalMotionEffect]

    self.background.addMotionEffect(group)
}

Dzięki @Lucas! Zaktualizowałem swoją odpowiedź, aby uwzględnić również szybką próbkę. Opiera się na tym. Zapraszam do przejrzenia go i wprowadzenia potrzebnych zmian.
— veducm

7

Rozwiązanie @ veducm może być trochę krótsze. Grupa UIMotionEffectGroup dla jej ruchu xiy jest przestarzała, jeśli dodasz osobno elementy motionEffects na osi xi y.

UIInterpolatingMotionEffect *motionEffect;
motionEffect = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x"
                                                               type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
motionEffect.minimumRelativeValue = @(-25);
motionEffect.maximumRelativeValue = @(25);
[bgView addMotionEffect:motionEffect];

motionEffect = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y"
                                                               type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
motionEffect.minimumRelativeValue = @(-25);
motionEffect.maximumRelativeValue = @(25);
[bgView addMotionEffect:motionEffect];

2
Podobnie jak heads-up, jeśli ktoś używa tej skróconej wersji, pierwsze potrzeby ruchu skutku mieć typeod UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxisa nie UIInterpolatingMotionEffectTypeTiltAlongVerticalAxisjak to jest w kodzie określonymi
— Flexicoder

1
@BooHoo Dodanie ich jako grupy jest przestarzałe? Gdzie to widzisz? W chwili pisania tego tekstu dokumentacja Apple nie zawiera informacji o tym, że jest przestarzała. Celem ich grupowania jest poprawa wydajności. Wszystkie efekty w grupie są renderowane raz. Kiedy nakładasz je oddzielnie, należy je renderować oddzielnie. Zapraszam do poprawienia mnie, jeśli się mylę (i wskaż mi dokumentację Apple na ten temat).
— David Lari

6
const static CGFloat kCustomIOS7MotionEffectExtent = 10.0; 

- (void)applyMotionEffects:(UIView *YOUR_VIEW) {
     if (NSClassFromString(@"UIInterpolatingMotionEffect")) {
         UIInterpolatingMotionEffect *horizontalEffect = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x"
                                                                                                        type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
         horizontalEffect.minimumRelativeValue = @(-kCustomIOS7MotionEffectExtent);
         horizontalEffect.maximumRelativeValue = @( kCustomIOS7MotionEffectExtent);
         UIInterpolatingMotionEffect *verticalEffect = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y"
                                                                                                      type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
         verticalEffect.minimumRelativeValue = @(-kCustomIOS7MotionEffectExtent);
         verticalEffect.maximumRelativeValue = @( kCustomIOS7MotionEffectExtent);
         UIMotionEffectGroup *motionEffectGroup = [[UIMotionEffectGroup alloc] init];
         motionEffectGroup.motionEffects = @[horizontalEffect, verticalEffect]; 
         [YOUR_VIEW addMotionEffect:motionEffectGroup];
     }
}

1
@Rob zgodnie z twoją sugestią zaktualizował odpowiedź
— damithH

5

Oto prosta kategoria do zintegrowania wpływu na iOs7 +:

NSString *const centerX = @"center.x";
NSString *const centerY = @"center.y";

//#define IS_OS_7_OR_LATER    ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0)

@implementation UIView (TLMotionEffect)

- (void)addCenterMotionEffectsXYWithOffset:(CGFloat)offset {

//    if(!IS_OS_7_OR_LATER) return;
    if(floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) return;

    UIInterpolatingMotionEffect *xAxis;
    UIInterpolatingMotionEffect *yAxis;

    xAxis = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:centerX type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
    xAxis.maximumRelativeValue = @(offset);
    xAxis.minimumRelativeValue = @(-offset);

    yAxis = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:centerY type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
    yAxis.minimumRelativeValue = @(-offset);
    yAxis.maximumRelativeValue = @(offset);

    UIMotionEffectGroup *group = [[UIMotionEffectGroup alloc] init];
    group.motionEffects = @[xAxis, yAxis];

    [self addMotionEffect:group];
}

@end

https://github.com/jvenegas/TLMotionEffect


1
Chociaż ten link może odpowiedzieć na pytanie, lepiej jest zawrzeć tutaj zasadnicze części odpowiedzi i podać link do odniesienia. Odpowiedzi zawierające tylko łącze mogą stać się nieprawidłowe, jeśli połączona strona ulegnie zmianie.
— Maciej Swic

Trudno będzie tutaj zintegrować cały projekt github
— Bejil

1
Nie musisz przynosić całego projektu, tylko istotną część, tak jak pokazałem, edytując odpowiedź. Dzieje się tak, aby kod pozostawał na wypadek awarii Githuba, ściągnięcia repozytorium lub upadku nieba.
— Maciej Swic


3

Pomoże to komuś, kto chce zaimplementować paralaksę dla tableView lub collectionView.

  • przede wszystkim utwórz komórkę dla widoku tabeli i umieść w niej widok obrazu.

  • ustawić wysokość obrazu nieco większą niż wysokość komórki. jeśli wysokość komórki = 160, niech wysokość obrazu wynosi 200 (aby uzyskać efekt paralaksy i można go odpowiednio zmienić)

  • umieść te dwie zmienne w swoim viewController lub dowolnej klasie, w której delegat tableView jest rozszerzony

let imageHeight:CGFloat = 150.0
let OffsetSpeed: CGFloat = 25.0
  • dodaj następujący kod w tej samej klasie
 func scrollViewDidScroll(scrollView: UIScrollView) {
    //  print("inside scroll")

    if let visibleCells = seriesTabelView.visibleCells as? [SeriesTableViewCell] {
        for parallaxCell in visibleCells {
            var yOffset = ((seriesTabelView.contentOffset.y - parallaxCell.frame.origin.y) / imageHeight) * OffsetSpeedTwo
            parallaxCell.offset(CGPointMake(0.0, yOffset))
        }
    }
}
  • gdzie seriesTabelView jest moim UItableview

  • a teraz przejdźmy do komórki tego tableView i dodajmy następujący kod

func offset(offset: CGPoint) {
        posterImage.frame = CGRectOffset(self.posterImage.bounds, offset.x, offset.y)
    }
  • were posterImage jest moim UIImageView

Jeśli chcesz zaimplementować to do collectionView, po prostu zmień tableView vairable na zmienną collectionView

i to wszystko. nie jestem pewien, czy to najlepszy sposób. ale to działa dla mnie. mam nadzieję, że to też działa dla Ciebie. i daj mi znać, jeśli jest jakiś problem


2

Naprawdę bardzo łatwo to zrobić, dlaczego odsyła złożony kod. po prostu spróbuj. Pracujący

Przyjrzyj się widokowi obrazu dokładnie wielkości widoku obrazu. domyślnie alfa dla widoku zestawu 0.

//MARK: Scroll View Delegate methods
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{

NSLog(@"X: %f Y: %f",scrollView.contentOffset.x,scrollView.contentOffset.y);

CGFloat scrollY = _mainScrollView.contentOffset.y;
CGFloat height = _alphaView.frame.size.height;

CGFloat alphaMonitor = scrollY/height;

_alphaView.alpha = alphaMonitor;
}

-1

Szybkie tłumaczenie:

// Set vertical effect
let verticalMotionEffect = UIInterpolatingMotionEffect(keyPath: "center.y", type: .TiltAlongVerticalAxis)
verticalMotionEffect.minimumRelativeValue = -value
verticalMotionEffect.maximumRelativeValue = value

// Set vertical effect
let horizontalMotionEffect = UIInterpolatingMotionEffect(keyPath: "center.x", type: .TiltAlongHorizontalAxis)
verticalMotionEffect.minimumRelativeValue = -value
verticalMotionEffect.maximumRelativeValue = value

let group = UIMotionEffectGroup()
group.motionEffects = [horizontalMotionEffect, verticalMotionEffect]
self.motionEffect = group
self.addMotionEffect(group)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.