Hiệu ứng thị sai iOS 7 trong bộ điều khiển chế độ xem của tôi


112

Tôi đang phát triển một ứng dụng cho iOS 7 trong Objective-C. Tôi có một màn hình trong ứng dụng của mình với một vài nút và hình nền đẹp. (Đó là một xib đơn giản với UIButtonsphía trên là a UIImageView.)

Tôi đã nghĩ rằng sẽ thật tuyệt nếu những nút đó có hiệu ứng thị sai mà màn hình chính của iOS 7 có, vì vậy nếu bạn nghiêng điện thoại, bạn có thể thấy nền.

Làm cách nào để triển khai hiệu ứng đó trong ứng dụng của riêng tôi?



Cho nhanh chóng, hãy thử với điều đó: github.com/ArvindPrakashJoshi/AJParallaxEffect
Arvind

Câu trả lời:


273

Với iOS 7, Apple đã giới thiệu UIMotionEffectthêm các hiệu ứng Chuyển động liên quan đến hướng thiết bị của người dùng. Ví dụ: để mô phỏng hiệu ứng thị sai trên màn hình chính, bạn có thể sử dụng lớp con UIInterpolationMotionEffect, như được giải thích ở đâyở đây , chỉ với một vài dòng mã.

Mục tiêu-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 (Cảm ơn @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)

Ngoài ra, bạn có thể tìm thấy một loạt thư viện để thực hiện việc này dễ dàng hơn hoặc thêm chức năng này vào các phiên bản iOS cũ hơn:


2
NGAParallaxMotion dành cho iOS 7+, không dành cho các phiên bản iOS cũ hơn. Nó cung cấp một danh mục cho UIView, cho phép bạn đặt giá trị .parallaxIntensity, thiết lập các tham số UIMotionEffect bằng một dòng mã.
Dan Fabulich

2
Cảm ơn! Tôi đã cập nhật câu trả lời để bao gồm các phiên bản và yêu cầu được hỗ trợ.
veducm

1
Trên thực tế, bạn muốn thêm hiệu ứng chuyển động vào chế độ xem nền chứ không phải chế độ xem phía trước. Nhưng khác với điều đó, mã này hoạt động tuyệt vời! Cảm ơn.
gstroup

1
Có ai biết cách kiểm tra xem người dùng đã tắt các hiệu ứng chưa? stackoverflow.com/questions/19132000/…
Eric

3
@gstroup Trên thực tế, trên màn hình chính, cả nền trước và nền sau đều chuyển động. Nhưng nếu bạn chỉ chọn một lớp để áp dụng hiệu ứng thị sai, tôi đồng ý rằng nền có lẽ sẽ là tốt nhất.
Rubberduck

16

Được dịch để nhanh chóng trong trường hợp bất kỳ ai lười biếng. Hãy bình chọn câu trả lời của @veducm nếu bạn thấy điều này hữu ích

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

Cảm ơn @Lucas! Tôi đã cập nhật câu trả lời của mình để bao gồm cả mẫu nhanh. Nó dựa trên cái này. Vui lòng xem lại nó và thực hiện bất kỳ thay đổi nào cần thiết.
veducm

7

Giải pháp của @ veducm có thể ngắn hơn một chút. UIMotionEffectGroup cho chuyển động x và y của nó đã lỗi thời nếu bạn thêm chuyển động trục x và trục y riêng biệt.

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
Cũng giống như một người đứng đầu lên nếu có ai đang sử dụng phiên bản rút gọn này, nhu cầu hiệu quả chuyển động đầu tiên để có một typecủa UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxisvà không UIInterpolatingMotionEffectTypeTiltAlongVerticalAxisvì nó là trong mã đặt ra
Flexicoder

1
@BooHoo Thêm họ vào một nhóm đã lỗi thời? Bạn thấy điều đó ở đâu? Tính đến thời điểm viết bài này, các tài liệu của Apple không có bất cứ điều gì về việc nó đã lỗi thời. Toàn bộ mục đích của việc nhóm chúng là để cải thiện hiệu suất. Tất cả các hiệu ứng trong nhóm được hiển thị một lần. Khi bạn áp dụng chúng một cách riêng biệt, chúng phải được hiển thị riêng biệt. Cảm thấy tự do để sửa cho tôi nếu tôi sai (và chỉ cho tôi tài liệu của Apple trên đó.)
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 theo gợi ý của bạn đã cập nhật câu trả lời
damithH

5

Đây là một danh mục dễ dàng để tích hợp hiệu ứng trên 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
Mặc dù liên kết này có thể trả lời câu hỏi, nhưng tốt hơn hết bạn nên đưa các phần thiết yếu của câu trả lời vào đây và cung cấp liên kết để tham khảo. Các câu trả lời chỉ có liên kết có thể trở nên không hợp lệ nếu trang được liên kết thay đổi.
Maciej Swic

Nó sẽ được khó khăn để tích hợp toàn bộ dự án github đây
Bejil

1
Bạn không cần phải mang toàn bộ dự án, chỉ phần thiết yếu như tôi đã chứng minh bằng cách chỉnh sửa câu trả lời. Điều này để mã bám xung quanh trong trường hợp Github không hoạt động, bạn kéo repo hoặc trên trời rơi xuống.
Maciej Swic


3

Điều này sẽ giúp những người đang tìm cách triển khai thị sai cho tableView hoặc collectionView.

  • trước hết tạo ô cho dạng xem bảng và đặt dạng xem hình ảnh vào đó.

  • đặt chiều cao hình ảnh nhiều hơn chiều cao ô một chút. nếu chiều cao ô = 160, hãy để chiều cao hình ảnh là 200 (để tạo hiệu ứng thị sai và bạn có thể thay đổi nó cho phù hợp)

  • đặt hai biến này trong viewController của bạn hoặc bất kỳ lớp nào mà đại biểu tableView của bạn được mở rộng

let imageHeight:CGFloat = 150.0
let OffsetSpeed: CGFloat = 25.0
  • thêm mã sau vào cùng một lớp
 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))
        }
    }
}
  • trong đó seriesTabelView là UItableview của tôi

  • và bây giờ hãy truy cập vào ô của tableView này và thêm mã sau

func offset(offset: CGPoint) {
        posterImage.frame = CGRectOffset(self.posterImage.bounds, offset.x, offset.y)
    }
  • được áp phích Hình ảnh là UIImageView của tôi

Nếu bạn muốn triển khai điều này cho collectionView, chỉ cần thay đổi tableView có thể có được thành biến collectionView của bạn

và đó là nó. tôi không chắc liệu đây có phải là cách tốt nhất. Nhưng nó làm việc cho tôi. Hi vọng nó có ích cho bạn. và cho tôi biết nếu có bất kỳ vấn đề nào


2

Thực sự dễ làm như vậy tại sao lại đề cập đến mã phức tạp. hãy thử nó. Đang làm việc

Xem trên imageview chính xác kích thước của chế độ xem hình ảnh. theo mặc định alpha cho chế độ xem đặt 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

Bản dịch nhanh:

// 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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.