mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
add updated Obj-C version of SubtleVolume
This commit is contained in:
parent
58206f4fe7
commit
cb83ff598b
4 changed files with 360 additions and 3 deletions
|
@ -722,10 +722,12 @@ elseif(IOS)
|
|||
ios/PPSSPPUIApplication.mm
|
||||
ios/SmartKeyboardMap.cpp
|
||||
ios/SmartKeyboardMap.hpp
|
||||
ios/SubtleVolume.h
|
||||
ios/SubtleVolume.mm
|
||||
ios/iCade/iCadeReaderView.h
|
||||
ios/iCade/iCadeReaderView.m
|
||||
ios/iCade/iCadeState.h)
|
||||
set(nativeExtraLibs ${nativeExtraLibs} "-framework Foundation -framework AudioToolbox -framework CoreGraphics -framework QuartzCore -framework UIKit -framework GLKit -framework OpenAL -framework AVFoundation")
|
||||
set(nativeExtraLibs ${nativeExtraLibs} "-framework Foundation -framework MediaPlayer -framework AudioToolbox -framework CoreGraphics -framework QuartzCore -framework UIKit -framework GLKit -framework OpenAL -framework AVFoundation")
|
||||
if(EXISTS "${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks/GameController.framework")
|
||||
set(nativeExtraLibs ${nativeExtraLibs} "-weak_framework GameController")
|
||||
endif()
|
||||
|
|
83
ios/SubtleVolume.h
Normal file
83
ios/SubtleVolume.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
//
|
||||
// SubtleVolume.h
|
||||
// subtleVolumeObjC
|
||||
//
|
||||
// Created by iMokhles on 24/03/16.
|
||||
// Copyright © 2016 iMokhles. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import <MediaPlayer/MediaPlayer.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
|
||||
/**
|
||||
The style of the volume indicator
|
||||
- Plain: A plain bar
|
||||
- RoundedLine: A plain bar with rounded corners
|
||||
- Dashes: A bar divided in dashes
|
||||
- Dots: A bar composed by a line of dots
|
||||
*/
|
||||
typedef NS_ENUM(NSInteger, SubtleVolumeStyle) {
|
||||
SubtleVolumeStylePlain,
|
||||
SubtleVolumeStyleRoundedLine,
|
||||
SubtleVolumeStyleDashes,
|
||||
SubtleVolumeStyleDots
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
The entry and exit animation of the volume indicator
|
||||
- None: The indicator is always visible
|
||||
- SlideDown: The indicator fades in/out and slides from/to the top into position
|
||||
- FadeIn: The indicator fades in and out
|
||||
*/
|
||||
typedef NS_ENUM(NSInteger, SubtleVolumeAnimation) {
|
||||
SubtleVolumeAnimationNone,
|
||||
SubtleVolumeAnimationSlideDown,
|
||||
SubtleVolumeAnimationFadeIn
|
||||
};
|
||||
|
||||
@class SubtleVolume;
|
||||
/**
|
||||
Delegate protocol fo `SubtleVolume`.
|
||||
Notifies the delegate when a change is about to happen (before the entry animation)
|
||||
and when a change occurred (and the exit animation is complete)
|
||||
*/
|
||||
@protocol SubtleVolumeDelegate <NSObject>
|
||||
/**
|
||||
The volume is about to change. This is fired before performing any entry animation
|
||||
- parameter subtleVolume: The current instance of `SubtleVolume`
|
||||
- parameter value: The value of the volume (between 0 an 1.0)
|
||||
*/
|
||||
- (void)subtleVolume:(SubtleVolume *)volumeView willChange:(CGFloat)value;
|
||||
/**
|
||||
The volume did change. This is fired after the exit animation is done
|
||||
- parameter subtleVolume: The current instance of `SubtleVolume`
|
||||
- parameter value: The value of the volume (between 0 an 1.0)
|
||||
*/
|
||||
- (void)subtleVolume:(SubtleVolume *)volumeView didChange:(CGFloat)value;
|
||||
|
||||
@end
|
||||
|
||||
/**
|
||||
Replace the system volume popup with a more subtle way to display the volume
|
||||
when the user changes it with the volume rocker.
|
||||
*/
|
||||
@interface SubtleVolume : UIView
|
||||
/**
|
||||
The style of the volume indicator
|
||||
*/
|
||||
@property (nonatomic, assign) SubtleVolumeStyle style;
|
||||
/**
|
||||
The entry and exit animation of the indicator. The animation is triggered by the volume
|
||||
If the animation is set to `SubtleVolumeAnimationNone`, the volume indicator is always visible
|
||||
*/
|
||||
@property (nonatomic, assign) SubtleVolumeAnimation animation;
|
||||
@property (nonatomic, strong) UIColor *barBackgroundColor;
|
||||
@property (nonatomic, strong) UIColor *barTintColor;
|
||||
@property (nonatomic, assign) id <SubtleVolumeDelegate> delegate;
|
||||
@property (nonatomic, assign) BOOL animatedByDefault;
|
||||
|
||||
- (instancetype)initWithStyle:(SubtleVolumeStyle)style;
|
||||
- (instancetype)initWithStyle:(SubtleVolumeStyle)style frame:(CGRect)frame;
|
||||
@end
|
250
ios/SubtleVolume.mm
Normal file
250
ios/SubtleVolume.mm
Normal file
|
@ -0,0 +1,250 @@
|
|||
//
|
||||
// SubtleVolume.m
|
||||
// subtleVolumeObjC
|
||||
//
|
||||
// Created by iMokhles on 24/03/16.
|
||||
// Copyright © 2016 iMokhles. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SubtleVolume.h"
|
||||
|
||||
MPVolumeView *volume = [[MPVolumeView alloc] initWithFrame:CGRectZero];
|
||||
UIView *overlay = [[UIView alloc] init];
|
||||
CGFloat volumeLevel = 0;
|
||||
|
||||
@interface SubtleVolume (){
|
||||
BOOL runningShowAnimation;
|
||||
BOOL showing;
|
||||
BOOL runningHideAnimation;
|
||||
BOOL lastAnimated;
|
||||
};
|
||||
|
||||
@property (nonatomic, strong) NSTimer *timer;
|
||||
|
||||
- (void)timerComplete;
|
||||
- (void)doHide:(BOOL)animated;
|
||||
- (void)doShow:(BOOL)animated;
|
||||
- (void)stopAnimations;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation SubtleVolume
|
||||
|
||||
- (instancetype)initWithStyle:(SubtleVolumeStyle)style frame:(CGRect)frame {
|
||||
|
||||
self = [super initWithFrame:frame];
|
||||
|
||||
if (self) {
|
||||
self.animatedByDefault = YES;
|
||||
self.style = style;
|
||||
[self setup];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithStyle:(SubtleVolumeStyle)style {
|
||||
return [self initWithStyle:style frame:CGRectZero];
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
|
||||
self = [super initWithCoder:aDecoder];
|
||||
if (self) {
|
||||
[self setup];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
|
||||
self = [super initWithFrame:frame];
|
||||
|
||||
if (self) {
|
||||
[self setup];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
self = nil;
|
||||
NSAssert(false, @"To init this class please use the designated initializer: initWithStyle or initWithStyle:frame:");
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)setup {
|
||||
@try {
|
||||
[[AVAudioSession sharedInstance] setActive:YES error:nil];
|
||||
} @catch (NSException *e) {
|
||||
NSLog(@"Unable to initialize AVAudioSession");
|
||||
}
|
||||
|
||||
volumeLevel = [[AVAudioSession sharedInstance] outputVolume];
|
||||
// [self updateVolume:[[AVAudioSession sharedInstance] outputVolume] animated:NO];
|
||||
[[AVAudioSession sharedInstance] addObserver:self forKeyPath:@"outputVolume" options:NSKeyValueObservingOptionNew context:NULL];
|
||||
[volume setVolumeThumbImage:[[UIImage alloc] init] forState:UIControlStateNormal];
|
||||
[volume setUserInteractionEnabled:NO];
|
||||
[volume setAlpha:0.0001];
|
||||
[volume setShowsRouteButton:NO];
|
||||
self.alpha = 0.0001;
|
||||
|
||||
[self addSubview:volume];
|
||||
|
||||
[self addSubview:overlay];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
overlay.frame = self.frame;
|
||||
overlay.frame = CGRectMake(0, 0, self.frame.size.width*volumeLevel, self.frame.size.height);
|
||||
|
||||
self.backgroundColor = self.barBackgroundColor;
|
||||
overlay.backgroundColor = self.barTintColor;
|
||||
|
||||
}
|
||||
- (void)updateVolume:(CGFloat)value animated:(BOOL)animated {
|
||||
NSLog(@"updateVolume: value:%f animated:%@", value, animated?@"YES":@"NO");
|
||||
[self.delegate subtleVolume:self willChange:value];
|
||||
volumeLevel = value;
|
||||
lastAnimated = animated;
|
||||
[UIView animateWithDuration:(animated ? 0.1 : 0) animations:^{
|
||||
CGRect rectOverlayView = overlay.frame;
|
||||
CGFloat overlyWidth = self.frame.size.width * volumeLevel;
|
||||
rectOverlayView.size.width = overlyWidth;
|
||||
overlay.frame = rectOverlayView;
|
||||
}];
|
||||
|
||||
|
||||
if(self.timer) {
|
||||
[self.timer invalidate];
|
||||
self.timer = nil;
|
||||
}
|
||||
|
||||
NSLog(@"Spinning up timer with timeInterval 2 ...");
|
||||
self.timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self selector:@selector(timerComplete) userInfo:nil repeats:NO];
|
||||
|
||||
[self doShow:animated];
|
||||
|
||||
[self.delegate subtleVolume:self didChange:value];
|
||||
}
|
||||
|
||||
- (void)timerComplete {
|
||||
NSLog(@"timerComplete!");
|
||||
[self doHide:lastAnimated];
|
||||
self.timer = nil;
|
||||
}
|
||||
|
||||
- (void)doHide:(BOOL)animated {
|
||||
NSLog(@"doHide:%@, runningShowAnimation: %@, runningHideAnimation: %@, showing: %@",
|
||||
animated?@"YES":@"NO",
|
||||
runningShowAnimation?@"YES":@"NO",
|
||||
runningHideAnimation?@"YES":@"NO",
|
||||
showing?@"YES":@"NO");
|
||||
|
||||
if(!showing) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(runningHideAnimation && !animated) {
|
||||
[self stopAnimations];
|
||||
}
|
||||
|
||||
if(runningHideAnimation) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(animated) {
|
||||
runningHideAnimation = YES;
|
||||
[UIView animateWithDuration:0.333 animations:^{
|
||||
switch (self.animation) {
|
||||
case SubtleVolumeAnimationNone:
|
||||
break;
|
||||
case SubtleVolumeAnimationFadeIn:
|
||||
self.alpha = 0.0001;
|
||||
break;
|
||||
case SubtleVolumeAnimationSlideDown:
|
||||
self.alpha = 0.0001;
|
||||
self.transform = CGAffineTransformMakeTranslation(0, -self.frame.size.height);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} completion:^(BOOL finished) {
|
||||
NSLog(@"Hide animation complete; finished? %@", finished?@"YES":@"NO");
|
||||
showing = NO;
|
||||
runningHideAnimation = NO;
|
||||
}];
|
||||
} else {
|
||||
NSLog(@"Hide immediate complete.");
|
||||
showing = NO;
|
||||
self.alpha = 0.0001;
|
||||
if(self.animation == SubtleVolumeAnimationSlideDown) {
|
||||
self.transform = CGAffineTransformMakeTranslation(0, -self.frame.size.height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)doShow:(BOOL)animated {
|
||||
NSLog(@"doShow:%@, runningShowAnimation: %@, runningHideAnimation: %@, showing: %@",
|
||||
animated?@"YES":@"NO",
|
||||
runningShowAnimation?@"YES":@"NO",
|
||||
runningHideAnimation?@"YES":@"NO",
|
||||
showing?@"YES":@"NO");
|
||||
|
||||
if(showing) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(runningShowAnimation && !animated) {
|
||||
[self stopAnimations];
|
||||
}
|
||||
|
||||
if(runningShowAnimation) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(animated) {
|
||||
runningShowAnimation = YES;
|
||||
[UIView animateWithDuration:0.333 animations:^{
|
||||
switch (self.animation) {
|
||||
case SubtleVolumeAnimationNone:
|
||||
break;
|
||||
case SubtleVolumeAnimationFadeIn:
|
||||
self.alpha = 1;
|
||||
break;
|
||||
case SubtleVolumeAnimationSlideDown:
|
||||
self.alpha = 1;
|
||||
self.transform = CGAffineTransformIdentity;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} completion:^(BOOL finished) {
|
||||
NSLog(@"Show animation complete; finished? %@", finished?@"YES":@"NO");
|
||||
showing = YES;
|
||||
runningShowAnimation = NO;
|
||||
}];
|
||||
} else {
|
||||
NSLog(@"Show immediate complete.");
|
||||
showing = YES;
|
||||
self.alpha = 1;
|
||||
self.transform = CGAffineTransformIdentity;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)stopAnimations {
|
||||
[self.layer removeAllAnimations];
|
||||
runningHideAnimation = NO;
|
||||
runningShowAnimation = NO;
|
||||
}
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
|
||||
if ([keyPath isEqual:@"outputVolume"]) {
|
||||
CGFloat value = [change[@"new"] floatValue];
|
||||
[self updateVolume:value animated:self.animatedByDefault];
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@end
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
|
||||
#import "ViewController.h"
|
||||
#import "SubtleVolume.h"
|
||||
#import <GLKit/GLKit.h>
|
||||
#include <cassert>
|
||||
|
||||
|
@ -81,8 +82,7 @@ static bool threadStopped = false;
|
|||
__unsafe_unretained ViewController* sharedViewController;
|
||||
static GraphicsContext *graphicsContext;
|
||||
|
||||
@interface ViewController ()
|
||||
{
|
||||
@interface ViewController () {
|
||||
std::map<uint16_t, uint16_t> iCadeToKeyMap;
|
||||
}
|
||||
|
||||
|
@ -95,6 +95,12 @@ static GraphicsContext *graphicsContext;
|
|||
|
||||
@end
|
||||
|
||||
@interface ViewController () <SubtleVolumeDelegate> {
|
||||
SubtleVolume *volume;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@implementation ViewController
|
||||
|
||||
-(id) init {
|
||||
|
@ -129,6 +135,13 @@ static GraphicsContext *graphicsContext;
|
|||
return self;
|
||||
}
|
||||
|
||||
- (void)subtleVolume:(SubtleVolume *)volumeView willChange:(CGFloat)value {
|
||||
// NSLog(@"%f alpha: %f", value, volumeView.alpha);
|
||||
}
|
||||
- (void)subtleVolume:(SubtleVolume *)volumeView didChange:(CGFloat)value {
|
||||
// NSLog(@"END %f alpha: %f", value, volumeView.alpha);
|
||||
}
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
|
@ -197,6 +210,15 @@ static GraphicsContext *graphicsContext;
|
|||
}
|
||||
#endif
|
||||
|
||||
volume = [[SubtleVolume alloc] initWithStyle:SubtleVolumeStylePlain frame:CGRectMake(10, 0, self.view.frame.size.width-20, 4)];
|
||||
// volume.animatedByDefault = NO;
|
||||
volume.barTintColor = [UIColor whiteColor];
|
||||
volume.barBackgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.3];
|
||||
volume.animation = SubtleVolumeAnimationSlideDown;
|
||||
volume.delegate = self;
|
||||
[self.view addSubview:volume];
|
||||
[self.view bringSubviewToFront:volume];
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
|
||||
NativeInitGraphics(graphicsContext);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue