เอฟเฟกต์พารัลแลกซ์ iOS 7 ในตัวควบคุมมุมมองของฉัน


112

ฉันกำลังพัฒนาแอปสำหรับ iOS 7 ใน Objective-C ฉันมีหน้าจอในแอพพร้อมปุ่มไม่กี่ปุ่มและภาพพื้นหลังสวย ๆ (มันคือ xib ธรรมดาที่UIButtonsอยู่ด้านบนของไฟล์UIImageView )

ฉันคิดว่ามันจะดีมากถ้าปุ่มเหล่านั้นมีเอฟเฟกต์พารัลแลกซ์ที่หน้าจอหลักของ iOS 7 มีดังนั้นหากคุณเอียงโทรศัพท์คุณจะเห็นพื้นหลัง

ฉันจะใช้เอฟเฟกต์นั้นในแอพของตัวเองได้อย่างไร


1
ดูห้องสมุดนี้: github.com/Przytua/UIView-MWParallax
CRDave

เพื่อความรวดเร็วให้ลองใช้: github.com/ArvindPrakashJoshi/AJParallaxEffect
Arvind

คำตอบ:


273

ด้วย iOS 7 Apple แนะนำUIMotionEffectให้เพิ่มเอฟเฟกต์การเคลื่อนไหวที่เกี่ยวข้องกับการวางแนวอุปกรณ์ของผู้ใช้ ตัวอย่างเช่นในการจำลองเอฟเฟกต์พารัลแลกซ์บนหน้าจอหลักคุณสามารถใช้คลาสย่อยUIInterpolationMotionEffectตามที่อธิบายไว้ที่นี่และที่นี่โดยใช้โค้ดเพียงไม่กี่บรรทัด

วัตถุประสงค์ -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 (ขอบคุณ @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)

นอกจากนี้คุณสามารถค้นหาไลบรารีจำนวนมากเพื่อทำสิ่งนี้ได้ง่ายขึ้นหรือเพิ่มฟังก์ชันนี้ใน iOS เวอร์ชันเก่า:


2
NGAParallaxMotion สำหรับ iOS 7+ ไม่ใช่สำหรับ iOS เวอร์ชันเก่า มีหมวดหมู่สำหรับ UIView ช่วยให้คุณสามารถตั้งค่า. parallaxIntensity ตั้งค่าพารามิเตอร์ UIMotionEffect ด้วยโค้ดหนึ่งบรรทัด
Dan Fabulich

2
ขอบคุณ! ฉันได้อัปเดตคำตอบเพื่อรวมเวอร์ชันและข้อกำหนดที่รองรับ
veducm

1
ที่จริงคุณต้องการเพิ่มเอฟเฟกต์การเคลื่อนไหวให้กับมุมมองพื้นหลังไม่ใช่มุมมองด้านหน้า แต่นอกเหนือจากนั้นรหัสนี้ใช้งานได้ดี! ขอบคุณ
gstroup

1
มีใครทราบวิธีตรวจสอบว่าผู้ใช้ปิดการใช้งานเอฟเฟกต์หรือไม่? stackoverflow.com/questions/19132000/…
Eric

3
@gstroup จริงๆแล้วบนหน้าจอหลักทั้งเบื้องหน้าและเบื้องหลังจะเคลื่อนไหว แต่ถ้าคุณต้องเลือกเพียงเลเยอร์เดียวเพื่อใช้เอฟเฟกต์พารัลแลกซ์ฉันยอมรับว่าพื้นหลังน่าจะดีที่สุด
Rubberduck

16

แปลว่าวูบเผื่อว่าใครขี้เกียจ กรุณาโหวต @veducm ตอบหากคุณพบว่าสิ่งนี้มีประโยชน์

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

ขอบคุณ @Lucas! ฉันได้อัปเดตคำตอบเพื่อรวมตัวอย่างรวดเร็วด้วย มันขึ้นอยู่กับอันนี้ อย่าลังเลที่จะตรวจสอบและทำการเปลี่ยนแปลงที่จำเป็น
veducm

7

วิธีแก้ปัญหาของ @ veducm อาจสั้นลงเล็กน้อย UIMotionEffectGroup สำหรับการเคลื่อนที่ x และ y จะล้าสมัยหากคุณเพิ่มผลการเคลื่อนที่แกน x และ 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
เช่นเดียวกับหัวขึ้นถ้าใครจะใช้คร่าวนี้เป็นครั้งแรกความต้องการผลการเคลื่อนไหวที่จะมีเป็นtypeของUIInterpolatingMotionEffectTypeTiltAlongHorizontalAxisและไม่ได้UIInterpolatingMotionEffectTypeTiltAlongVerticalAxisเป็นอยู่ในรหัสออกมาวาง
Flexicoder

1
@BooHoo การเพิ่มเป็นกลุ่มนั้นล้าสมัยหรือไม่? คุณเห็นสิ่งนั้นที่ไหน? ในช่วงเวลาของการเขียนนี้เอกสารของ Apple ไม่มีอะไรเกี่ยวกับการล้าสมัย จุดประสงค์ทั้งหมดของการจัดกลุ่มคือการปรับปรุงประสิทธิภาพ เอฟเฟกต์ทั้งหมดในกลุ่มจะแสดงผลครั้งเดียว เมื่อคุณใช้แยกกันต้องแสดงผลแยกกัน อย่าลังเลที่จะแก้ไขฉันถ้าฉันผิด (และชี้ให้ฉันดูเอกสารของ Apple)
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 ตามคำแนะนำของคุณปรับปรุงคำตอบ
damithH

5

นี่คือหมวดหมู่ที่ง่ายในการรวมเอฟเฟกต์บน 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
แม้ว่าลิงก์นี้อาจตอบคำถามได้ แต่ควรรวมส่วนสำคัญของคำตอบไว้ที่นี่และระบุลิงก์เพื่อการอ้างอิง คำตอบแบบลิงก์เท่านั้นอาจไม่ถูกต้องหากหน้าที่เชื่อมโยงเปลี่ยนไป
Maciej Swic

จะเป็นการยากที่จะรวมโครงการ github ทั้งหมดที่นี่
เบจิล

1
คุณไม่จำเป็นต้องนำโครงการทั้งหมดมาเฉพาะส่วนที่สำคัญเช่นฉันแสดงให้เห็นโดยการแก้ไขคำตอบ เพื่อให้โค้ดเกาะติดในกรณีที่ Github หยุดทำงานคุณดึง repo หรือท้องฟ้าตกลงมา
Maciej Swic


3

สิ่งนี้จะช่วยให้ผู้ที่ต้องการใช้พารัลแลกซ์สำหรับ tableView หรือ collectionView

  • ก่อนอื่นให้สร้างเซลล์สำหรับมุมมองตารางและใส่มุมมองภาพไว้ในนั้น

  • ตั้งค่าความสูงของภาพให้มากกว่าความสูงของเซลล์เล็กน้อย ถ้าความสูงของเซลล์ = 160 ให้ความสูงของภาพเป็น 200 (เพื่อสร้างเอฟเฟกต์พารัลแลกซ์และคุณสามารถเปลี่ยนได้ตามนั้น)

  • ใส่ตัวแปรสองตัวนี้ใน viewController ของคุณหรือคลาสใด ๆ ที่ขยายผู้รับมอบสิทธิ์ tableView ของคุณ

let imageHeight:CGFloat = 150.0
let OffsetSpeed: CGFloat = 25.0
  • เพิ่มรหัสต่อไปนี้ในคลาสเดียวกัน
 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))
        }
    }
}
  • โดยที่ seriesTabelView คือ UItableview ของฉัน

  • และตอนนี้ให้ไปที่เซลล์ของ tableView นี้และเพิ่มรหัสต่อไปนี้

func offset(offset: CGPoint) {
        posterImage.frame = CGRectOffset(self.posterImage.bounds, offset.x, offset.y)
    }
  • ถูก posterImage เป็น UIImageView ของฉัน

หากคุณต้องการใช้สิ่งนี้กับ collectionView เพียงแค่เปลี่ยน tableView ที่ใช้งานได้กับตัวแปร collectionView ของคุณ

และนั่นคือมัน ฉันไม่แน่ใจว่านี่เป็นวิธีที่ดีที่สุดหรือไม่ แต่มันได้ผลสำหรับฉัน หวังว่ามันจะเหมาะกับคุณเช่นกัน และแจ้งให้เราทราบหากมีปัญหาใด ๆ


2

จริงๆเขื่อนทำง่ายทำไมถึงอ้างถึงรหัสที่ซับซ้อน แค่ลองดู.การทำงาน

ใช้มุมมองภาพขนาดพอดีของมุมมองภาพ โดยค่าเริ่มต้นอัลฟาสำหรับมุมมองชุด 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

การแปลอย่างรวดเร็ว:

// 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)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.