hyzp_ybqx-Commit001:代码刚转换好,编译通过
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// NSString+URL.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by xcoderliu on 12/10/20.
|
||||
// Copyright © 2020 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSString (URL)
|
||||
/// 获取 URL GET 参数
|
||||
/// @param parameter key
|
||||
/// @param originUrl url
|
||||
+ (NSString *)getParameter:(NSString *)parameter WithOriginUrl:(NSString *)originUrl;
|
||||
|
||||
/// 删除 URL GET 参数
|
||||
/// @param parameter key
|
||||
/// @param originUrl url
|
||||
+ (NSString *)deleteParameter:(NSString *)parameter WithOriginUrl:(NSString *)originUrl;
|
||||
|
||||
|
||||
/// 追加 URL GET 参数
|
||||
/// @param queryString (@"key=value")
|
||||
/// @param originUrl url
|
||||
+ (NSString *)appendParameter:(NSString *)queryString WithOriginUrl:(NSString *)originUrl;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// NSString+URL.m
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by xcoderliu on 12/10/20.
|
||||
// Copyright © 2020 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSString+URL.h"
|
||||
|
||||
@implementation NSString (URL)
|
||||
+ (NSString *)getParameter:(NSString *)parameter WithOriginUrl:(NSString *)originUrl {
|
||||
NSError *error;
|
||||
if (originUrl.length == 0) {
|
||||
return @"";
|
||||
}
|
||||
NSString *regTags = [[NSString alloc] initWithFormat:@"(^|&|\\?)+%@=+([^&]*)(&|$)",parameter];
|
||||
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regTags options:NSRegularExpressionCaseInsensitive error:&error];
|
||||
NSArray *matches = [regex matchesInString:originUrl options:0 range:NSMakeRange(0, [originUrl length])];
|
||||
for (NSTextCheckingResult *match in matches) {
|
||||
NSString *tagValue = [originUrl substringWithRange:[match rangeAtIndex:2]];
|
||||
return tagValue;
|
||||
}
|
||||
return @"";
|
||||
}
|
||||
|
||||
+ (NSString *)deleteParameter:(NSString *)parameter WithOriginUrl:(NSString *)originUrl {
|
||||
NSString *finalStr = [NSString string];
|
||||
NSMutableString * mutStr = [NSMutableString stringWithString:originUrl];
|
||||
NSArray *strArray = [mutStr componentsSeparatedByString:parameter];
|
||||
NSMutableString *firstStr = [strArray objectAtIndex:0];
|
||||
NSMutableString *lastStr = [strArray lastObject];
|
||||
NSRange characterRange = [lastStr rangeOfString:@"&"];
|
||||
|
||||
if (characterRange.location !=NSNotFound) {
|
||||
NSArray *lastArray = [lastStr componentsSeparatedByString:@"&"];
|
||||
NSMutableArray *mutArray = [NSMutableArray arrayWithArray:lastArray];
|
||||
[mutArray removeObjectAtIndex:0];
|
||||
NSString *modifiedStr = [mutArray componentsJoinedByString:@"&"];
|
||||
finalStr = [[strArray objectAtIndex:0]stringByAppendingString:modifiedStr];
|
||||
} else {
|
||||
finalStr = [firstStr substringToIndex:[firstStr length] -1];
|
||||
}
|
||||
return finalStr;
|
||||
}
|
||||
|
||||
+ (NSString *)appendParameter:(NSString *)queryString WithOriginUrl:(NSString *)originUrl {
|
||||
if (![queryString length]) {
|
||||
return originUrl;
|
||||
}
|
||||
return [NSString stringWithFormat:@"%@%@%@", originUrl,
|
||||
[originUrl rangeOfString:@"?"].length > 0 ? @"&" : @"?", queryString];
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface UINavigationController (SuperPlayerRotation)<UIGestureRecognizerDelegate>
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,34 @@
|
||||
#import "UINavigationController+SuperPlayerRotation.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@implementation UINavigationController (SuperPlayerRotation)
|
||||
|
||||
/**
|
||||
* 如果window的根视图是UINavigationController,则会先调用这个Category,然后调用UIViewController+SuperPlayerRotation
|
||||
* 只需要在支持除竖屏以外方向的页面重新下边三个方法
|
||||
*/
|
||||
|
||||
// 是否支持自动转屏
|
||||
- (BOOL)shouldAutorotate {
|
||||
return [self.topViewController shouldAutorotate];
|
||||
}
|
||||
|
||||
// 支持哪些屏幕方向
|
||||
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
|
||||
return [self.topViewController supportedInterfaceOrientations];
|
||||
}
|
||||
|
||||
// 默认的屏幕方向(当前ViewController必须是通过模态出来的UIViewController(模态带导航的无效)方式展现出来的,才会调用这个方法)
|
||||
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
|
||||
return [self.topViewController preferredInterfaceOrientationForPresentation];
|
||||
}
|
||||
|
||||
- (UIViewController *)childViewControllerForStatusBarStyle {
|
||||
return self.topViewController;
|
||||
}
|
||||
|
||||
- (UIViewController *)childViewControllerForStatusBarHidden {
|
||||
return self.topViewController;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,93 @@
|
||||
//
|
||||
// UIView+MM.h
|
||||
/*
|
||||
杜蒙 iOS开发
|
||||
annidy
|
||||
*/
|
||||
|
||||
#define m_weakify(object) autoreleasepool {} __weak typeof(object) weak##object = object
|
||||
#define m_strongify(object) autoreleasepool {} __strong typeof(weak##object) object = weak##object
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
@class MMLayout;
|
||||
@interface UIView (Layout)
|
||||
@property (strong , nonatomic , readonly) MMLayout *mm_selfLayout;
|
||||
- (void)setMm_x:(CGFloat)mm_x; ///<< set frame.x
|
||||
- (CGFloat)mm_x; ///<< get frame.x
|
||||
- (void)setMm_y:(CGFloat)mm_y; ///<< set frame.y
|
||||
- (CGFloat)mm_y; ///<< get frame.y
|
||||
- (void)setMm_w:(CGFloat)mm_w; ///<< set frame.bounds.size.width
|
||||
- (CGFloat)mm_w; ///<< get frame.bounds.size.width
|
||||
- (void)setMm_h:(CGFloat)mm_h; ///<< set frame.bounds.size.height
|
||||
- (CGFloat)mm_h; ///<< get frame.bounds.size.height
|
||||
- (void)setMm_center:(CGPoint )mm_center; ///<< set frame.origin
|
||||
- (CGPoint)mm_center; ///<< get frame origin
|
||||
- (CGFloat)mm_centerX; ///<< get self.center.x
|
||||
- (CGFloat)mm_centerY; ///<< get self.center.y
|
||||
- (CGFloat)mm_maxY; ///<< get CGRectGetMaxY
|
||||
- (CGFloat)mm_minY; ///<< get CGRectGetMinY
|
||||
- (CGFloat)mm_maxX; ///<< get CGRectGetMaxX
|
||||
- (CGFloat)mm_minX; ///<< get CGRectGetMinX
|
||||
- (CGFloat)mm_halfW; ///<< get self.width / 2
|
||||
- (CGFloat)mm_halfH; ///<< get self.height / 2
|
||||
- (CGFloat)mm_halfX; ///<< get self.x / 2
|
||||
- (CGFloat)mm_halfY; ///<< get self.y / 2
|
||||
- (CGFloat)mm_halfCenterX; ///<< get self.centerX / 2
|
||||
- (CGFloat)mm_halfCenterY; ///<< get self.centerY / 2
|
||||
- (void)setMm_size:(CGSize)mm_size;
|
||||
- (CGSize)mm_size; ///<< get self.bounds.size
|
||||
|
||||
// iPhoneX adapt
|
||||
|
||||
@property (readonly) CGFloat mm_safeAreaBottomGap;
|
||||
@property (readonly) CGFloat mm_safeAreaTopGap;
|
||||
@property (readonly) CGFloat mm_safeAreaLeftGap;
|
||||
@property (readonly) CGFloat mm_safeAreaRightGap;
|
||||
|
||||
/*
|
||||
示例链接编程
|
||||
self.m_width(100).m_height(100).m_left(10).m_top(10)
|
||||
*/
|
||||
- (UIView * (^)(CGFloat top))m_top; ///< set frame y
|
||||
- (UIView * (^)(CGFloat right))m_flexToTop; ///< set frame y by change height
|
||||
- (UIView * (^)(CGFloat bottom))m_bottom; ///< set frame y
|
||||
- (UIView * (^)(CGFloat right))m_flexToBottom; ///< set frame y by change height
|
||||
- (UIView * (^)(CGFloat left))m_left; ///< set frame x
|
||||
- (UIView * (^)(CGFloat right))m_flexToLeft; ///< set frame right by chang width
|
||||
- (UIView * (^)(CGFloat right))m_right; ///< set frame x
|
||||
- (UIView * (^)(CGFloat right))m_flexToRight; ///< set frame right by chang width
|
||||
- (UIView * (^)(CGFloat width))m_width; ///< set frame width
|
||||
- (UIView * (^)(CGFloat height))m_height; ///< set frame height
|
||||
- (UIView * (^)(CGSize size))m_size; ///< set frame size
|
||||
- (UIView * (^)(CGPoint center))m__center; ///< set frame center point
|
||||
- (UIView * (^)(void))m_center; ///< set frame center 前提是有w h 调用次方法居中父类
|
||||
- (UIView * (^)(void))m_centerY; ///< set frame Ycenter 前提是有h调用次方法居中父类
|
||||
- (UIView * (^)(void))m_centerX; ///< set frame Xcenter 前提是有w调用次方法居中父类
|
||||
|
||||
/*
|
||||
相对父View
|
||||
*/
|
||||
-(UIView *(^)(void))m_fill; ///< 填充
|
||||
|
||||
|
||||
- (UIView * (^)(UIView *obj))m_equalToFrame; /// equalTo frame
|
||||
- (UIView * (^)(UIView *obj))m_equalToTop; /// equalTo top
|
||||
- (UIView * (^)(UIView *obj))m_equalToBottom; /// equalTo Bottom
|
||||
- (UIView * (^)(UIView *obj))m_equalToLeft; /// equalTo left
|
||||
- (UIView * (^)(UIView *obj))m_equalToRight; /// equalTo right
|
||||
- (UIView * (^)(UIView *obj))m_equalToWidth; /// equalTo width
|
||||
- (UIView * (^)(UIView *obj))m_equalToHeight; /// equalTo height
|
||||
- (UIView * (^)(UIView *obj))m_equalToSize; /// equalTo size
|
||||
- (UIView * (^)(UIView *obj))m_equalToCenter; /// equalTo center
|
||||
|
||||
- (UIView * (^)(void))m_sizeToFit; /// call sizeToFit
|
||||
|
||||
- (NSData *)mm_createPDF;/// create self PDF
|
||||
|
||||
- (UIViewController *)viewController; //self Responder UIViewControler
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,525 @@
|
||||
|
||||
|
||||
#import "UIView+MMLayout.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#pragma mark - MMLayout
|
||||
@interface MMLayout : NSObject
|
||||
/*
|
||||
@LayoutView 传入进去 View
|
||||
*/
|
||||
-(instancetype)initWithLayoutView:(UIView *)LayoutView;
|
||||
@property (assign , nonatomic) CGFloat top; ///<< frame y
|
||||
@property (assign , nonatomic) CGFloat bottom; ///<< y = super.h - LayoutView.h - bottom
|
||||
@property (assign , nonatomic) CGFloat left; ///<< frame x
|
||||
@property (assign , nonatomic) CGFloat right; ///<< x = super.w - LayoutView.h - right
|
||||
@property (assign , nonatomic) CGFloat width; ///<< frame w
|
||||
@property (assign , nonatomic) CGFloat height; ///<< frame height
|
||||
@property (assign , nonatomic) CGSize size; ///<< frame bounds size width height
|
||||
@property (assign , nonatomic) CGPoint point; ///<< frame point
|
||||
- (void)center; ///<<调用此方法前必须先设置自己的宽高 (默认是居中父控件)
|
||||
- (void)centerX; ///<<调用此方法前必须先设置自己的宽 (默认是居中父控件)
|
||||
- (void)centerY; ///<<调用此方法前必须先设置自己的高 (默认是居中父控件)
|
||||
@property (weak , nonatomic) UIView *layoutView;
|
||||
@end
|
||||
@implementation MMLayout
|
||||
-(instancetype)initWithLayoutView:(UIView *)LayoutView{
|
||||
if (self=[super init]) {
|
||||
self.layoutView = LayoutView;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
-(void)setLeft:(CGFloat)left{
|
||||
CGRect frame = self.layoutView.frame;
|
||||
frame.origin.x = left;
|
||||
self.layoutView.frame = frame;
|
||||
}
|
||||
- (CGFloat)left {
|
||||
return self.layoutView.frame.origin.x;
|
||||
}
|
||||
-(void)setTop:(CGFloat)top{
|
||||
_top = top;
|
||||
CGRect frame = self.layoutView.frame;
|
||||
frame.origin.y = top;
|
||||
self.layoutView.frame = frame;
|
||||
}
|
||||
-(void)setRight:(CGFloat)right{
|
||||
UIView *superview = self.layoutView.superview;
|
||||
self.layoutView.mm_x = superview.mm_w - self.layoutView.mm_w - right;
|
||||
}
|
||||
- (CGFloat)right {
|
||||
UIView *superview = self.layoutView.superview;
|
||||
return superview.mm_w - self.layoutView.mm_x - self.layoutView.mm_w;
|
||||
}
|
||||
|
||||
-(void)setBottom:(CGFloat)bottom{
|
||||
UIView *superview = self.layoutView.superview;
|
||||
self.layoutView.mm_y = superview.mm_h - self.layoutView.mm_h - bottom;
|
||||
}
|
||||
|
||||
- (CGFloat)bottom {
|
||||
UIView *superview = self.layoutView.superview;
|
||||
return superview.mm_h - self.layoutView.mm_maxY;
|
||||
}
|
||||
|
||||
-(void)setHeight:(CGFloat)height{
|
||||
_height = height;
|
||||
CGRect frame = self.layoutView.frame;
|
||||
frame.size.height = height;
|
||||
self.layoutView.frame = frame;
|
||||
}
|
||||
-(void)setWidth:(CGFloat)width{
|
||||
_width = width;
|
||||
CGRect frame = self.layoutView.frame;
|
||||
frame.size.width = width;
|
||||
self.layoutView.frame = frame;
|
||||
}
|
||||
-(void)setPoint:(CGPoint)point{
|
||||
CGRect frame = self.layoutView.frame;
|
||||
frame.origin = point;
|
||||
self.layoutView.frame = frame;
|
||||
}
|
||||
-(CGPoint)point{
|
||||
return CGPointMake(self.layoutView.mm_x, self.layoutView.mm_w);
|
||||
}
|
||||
-(void)setSize:(CGSize )size{
|
||||
CGRect frame = self.layoutView.frame;
|
||||
frame.size = size;
|
||||
self.layoutView.frame = frame;
|
||||
}
|
||||
-(CGSize)size{
|
||||
return self.layoutView.mm_size;
|
||||
}
|
||||
|
||||
-(void)setCenter:(CGPoint)center{
|
||||
CGRect frame = self.layoutView.frame;
|
||||
frame.origin = CGPointMake(center.x-frame.size.width/2, center.y-frame.size.height/2);
|
||||
self.layoutView.frame = frame;
|
||||
}
|
||||
-(void)center{
|
||||
UIView *superview = self.layoutView.superview;
|
||||
self.layoutView.mm_x = superview.mm_halfW - self.layoutView.mm_halfW;
|
||||
self.layoutView.mm_y = superview.mm_halfH - self.layoutView.mm_halfH;
|
||||
}
|
||||
-(void)centerY{
|
||||
UIView *superview = self.layoutView.superview;
|
||||
self.layoutView.mm_y = superview.mm_halfH - self.layoutView.mm_halfH;
|
||||
}
|
||||
-(void)centerX{
|
||||
UIView *superview = self.layoutView.superview;
|
||||
self.layoutView.mm_x = superview.mm_halfW - self.layoutView.mm_halfW;
|
||||
}
|
||||
@end
|
||||
const void *_layoutKey;
|
||||
@implementation UIView (Layout)
|
||||
#pragma mark - frame
|
||||
- (void)setMm_x:(CGFloat)mm_x{
|
||||
[self mm_selfLayout].left = mm_x;
|
||||
}
|
||||
- (CGFloat)mm_x{
|
||||
return self.frame.origin.x;
|
||||
}
|
||||
- (void)setMm_y:(CGFloat)mm_y{
|
||||
[self mm_selfLayout].top = mm_y;
|
||||
}
|
||||
- (CGFloat)mm_y{
|
||||
return self.frame.origin.y;
|
||||
}
|
||||
- (void)setMm_w:(CGFloat)mm_w{
|
||||
[self mm_selfLayout].width = mm_w;
|
||||
}
|
||||
- (CGFloat)mm_w{
|
||||
return self.frame.size.width;
|
||||
}
|
||||
- (void)setMm_h:(CGFloat)mm_h{
|
||||
[self mm_selfLayout].height = mm_h;
|
||||
}
|
||||
- (CGFloat)mm_h{
|
||||
return self.frame.size.height;
|
||||
}
|
||||
-(void)setMm_center:(CGPoint)mm_center{
|
||||
[self mm_selfLayout].point = mm_center;
|
||||
|
||||
}
|
||||
-(CGPoint)mm_center{
|
||||
return self.frame.origin;
|
||||
}
|
||||
-(CGFloat)mm_centerX{
|
||||
return self.center.x;
|
||||
}
|
||||
-(CGFloat)mm_centerY{
|
||||
return self.center.y;
|
||||
}
|
||||
- (CGFloat)mm_maxY{
|
||||
return CGRectGetMaxY(self.frame);
|
||||
}
|
||||
- (CGFloat)mm_minY{
|
||||
return CGRectGetMinY(self.frame);
|
||||
}
|
||||
- (CGFloat)mm_maxX{
|
||||
return CGRectGetMaxX(self.frame);
|
||||
}
|
||||
- (CGFloat)mm_minX{
|
||||
return CGRectGetMinX(self.frame);
|
||||
}
|
||||
- (CGFloat)mm_halfW{
|
||||
return self.mm_w / 2;
|
||||
}
|
||||
- (CGFloat)mm_halfH{
|
||||
return self.mm_h / 2;
|
||||
}
|
||||
- (CGFloat)mm_halfX{
|
||||
return self.mm_x / 2;
|
||||
}
|
||||
- (CGFloat)mm_halfY{
|
||||
return self.mm_y / 2;
|
||||
}
|
||||
-(CGFloat)mm_halfCenterX{
|
||||
return self.mm_centerX / 2;
|
||||
}
|
||||
-(CGFloat)mm_halfCenterY{
|
||||
return self.mm_centerY / 2;
|
||||
}
|
||||
-(void)setMm_size:(CGSize)mm_size{
|
||||
[self mm_selfLayout].size = mm_size;
|
||||
}
|
||||
-(CGSize)mm_size{
|
||||
return self.bounds.size;
|
||||
}
|
||||
#pragma mark - set_ frame
|
||||
- (MMLayout *)mm_selfLayout{
|
||||
MMLayout *layout = objc_getAssociatedObject(self, &_layoutKey);
|
||||
if (layout == nil) {
|
||||
layout = [[MMLayout alloc] initWithLayoutView:self];
|
||||
objc_setAssociatedObject(self, &_layoutKey, layout, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
return layout;
|
||||
}
|
||||
-(UIView *(^)(CGFloat))m_top{
|
||||
@m_weakify(self);
|
||||
return ^(CGFloat m_top){
|
||||
@m_strongify(self);
|
||||
[self mm_selfLayout].top = m_top;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(CGFloat))m_flexToTop{
|
||||
@m_weakify(self);
|
||||
return ^(CGFloat m_flexToTop){
|
||||
@m_strongify(self);
|
||||
CGFloat top = [self mm_selfLayout].top;
|
||||
[self mm_selfLayout].top = m_flexToTop;
|
||||
[self mm_selfLayout].height += top-m_flexToTop;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(CGFloat))m_bottom{
|
||||
@m_weakify(self);
|
||||
return ^(CGFloat m_bottom){
|
||||
@m_strongify(self);
|
||||
[self mm_selfLayout].bottom = m_bottom;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(CGFloat))m_flexToBottom{
|
||||
@m_weakify(self);
|
||||
return ^(CGFloat m_flexToBottom){
|
||||
@m_strongify(self);
|
||||
CGFloat bottom = [self mm_selfLayout].bottom;
|
||||
[self mm_selfLayout].height += bottom-m_flexToBottom;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(CGFloat))m_left{
|
||||
@m_weakify(self);
|
||||
return ^(CGFloat m_left){
|
||||
@m_strongify(self);
|
||||
[self mm_selfLayout].left = m_left;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(CGFloat))m_flexToLeft{
|
||||
@m_weakify(self);
|
||||
return ^(CGFloat m_flexToLeft){
|
||||
@m_strongify(self);
|
||||
CGFloat left = [self mm_selfLayout].left;
|
||||
[self mm_selfLayout].left = m_flexToLeft;
|
||||
[self mm_selfLayout].width += left-m_flexToLeft;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(CGFloat))m_right{
|
||||
@m_weakify(self);
|
||||
return ^(CGFloat m_right){
|
||||
@m_strongify(self);
|
||||
[self mm_selfLayout].right = m_right;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(CGFloat))m_flexToRight{
|
||||
@m_weakify(self);
|
||||
return ^(CGFloat m_flexToRight){
|
||||
@m_strongify(self);
|
||||
CGFloat right = [self mm_selfLayout].right;
|
||||
[self mm_selfLayout].width += right-m_flexToRight;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(CGFloat))m_width{
|
||||
@m_weakify(self);
|
||||
return ^(CGFloat m_width){
|
||||
@m_strongify(self);
|
||||
[self mm_selfLayout].width = m_width;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(CGFloat))m_height{
|
||||
@m_weakify(self);
|
||||
return ^(CGFloat m_height){
|
||||
@m_strongify(self);
|
||||
[self mm_selfLayout].height = m_height;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(CGSize))m_size{
|
||||
@m_weakify(self);
|
||||
return ^(CGSize m_size){
|
||||
@m_strongify(self);
|
||||
[self mm_selfLayout].size = m_size;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
- (UIView *(^)(CGPoint))m__center{
|
||||
@m_weakify(self);
|
||||
return ^(CGPoint m__center){
|
||||
@m_strongify(self);
|
||||
[self mm_selfLayout].center = m__center;
|
||||
return self;
|
||||
};
|
||||
|
||||
}
|
||||
-(UIView *(^)(void))m_center{
|
||||
@m_weakify(self);
|
||||
return ^{
|
||||
@m_strongify(self);
|
||||
[[self mm_selfLayout] center];
|
||||
return self;
|
||||
};
|
||||
}
|
||||
|
||||
-(UIView *(^)(void))m_centerY{
|
||||
@m_weakify(self);
|
||||
return ^{
|
||||
@m_strongify(self);
|
||||
[[self mm_selfLayout] centerY];
|
||||
return self;
|
||||
};
|
||||
}
|
||||
|
||||
-(UIView *(^)(void))m_centerX{
|
||||
@m_weakify(self);
|
||||
return ^{
|
||||
@m_strongify(self);
|
||||
[[self mm_selfLayout] centerX];
|
||||
return self;
|
||||
};
|
||||
}
|
||||
|
||||
-(UIView *(^)(void))m_fill {
|
||||
@m_weakify(self);
|
||||
return ^{
|
||||
@m_strongify(self);
|
||||
if (self.superview) {
|
||||
self.mm_x = self.mm_y = 0;
|
||||
self.mm_w = self.superview.mm_w;
|
||||
self.mm_h = self.superview.mm_h;
|
||||
}
|
||||
return self;
|
||||
};
|
||||
}
|
||||
|
||||
#pragma mark - m_equalTo
|
||||
-(UIView *(^)(UIView *))m_equalToFrame{
|
||||
@m_weakify(self);
|
||||
return ^(UIView *obj){
|
||||
@m_strongify(self);
|
||||
self.frame = obj.frame;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(UIView *))m_equalToTop{
|
||||
@m_weakify(self);
|
||||
return ^(UIView *obj){
|
||||
@m_strongify(self);
|
||||
self.mm_selfLayout.top = obj.mm_selfLayout.top;
|
||||
return self;
|
||||
};
|
||||
|
||||
}
|
||||
-(UIView *(^)(UIView *))m_equalToBottom{
|
||||
@m_weakify(self);
|
||||
return ^(UIView *obj){
|
||||
@m_strongify(self);
|
||||
self.mm_selfLayout.bottom = obj.mm_selfLayout.bottom;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(UIView *))m_equalToLeft{
|
||||
@m_weakify(self);
|
||||
return ^(UIView *obj){
|
||||
@m_strongify(self);
|
||||
self.mm_selfLayout.left = obj.mm_selfLayout.left;
|
||||
return self;
|
||||
};
|
||||
|
||||
}
|
||||
-(UIView *(^)(UIView *))m_equalToRight{
|
||||
@m_weakify(self);
|
||||
return ^(UIView *obj){
|
||||
@m_strongify(self);
|
||||
self.mm_selfLayout.right = obj.mm_selfLayout.right;
|
||||
return self;
|
||||
};
|
||||
|
||||
}
|
||||
-(UIView *(^)(UIView *))m_equalToWidth{
|
||||
@m_weakify(self);
|
||||
return ^(UIView *obj){
|
||||
@m_strongify(self);
|
||||
self.mm_selfLayout.width = obj.mm_selfLayout.width;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(UIView *))m_equalToHeight{
|
||||
@m_weakify(self);
|
||||
return ^(UIView *obj){
|
||||
@m_strongify(self);
|
||||
self.mm_selfLayout.height = obj.mm_selfLayout.height;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(UIView *))m_equalToSize{
|
||||
@m_weakify(self);
|
||||
return ^(UIView *obj){
|
||||
@m_strongify(self);
|
||||
[self mm_selfLayout].size = obj.mm_selfLayout.size;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
- (UIView *(^)(UIView *))m_equalToCenter{
|
||||
@m_weakify(self);
|
||||
return ^(UIView *obj){
|
||||
@m_strongify(self);
|
||||
[self mm_selfLayout].point = obj.mm_selfLayout.point;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
|
||||
- (UIView *(^)(void))m_sizeToFit{
|
||||
@m_weakify(self);
|
||||
return ^(void){
|
||||
@m_strongify(self);
|
||||
[self sizeToFit];
|
||||
return self;
|
||||
};
|
||||
}
|
||||
|
||||
- (NSData *)mm_createPDF{
|
||||
CGRect bounds = self.bounds;
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
CGDataConsumerRef consumer = CGDataConsumerCreateWithCFData((__bridge CFMutableDataRef)data);
|
||||
CGContextRef context = CGPDFContextCreate(consumer, &bounds, NULL);
|
||||
CGDataConsumerRelease(consumer);
|
||||
if (!context) return nil;
|
||||
CGPDFContextBeginPage(context, NULL);
|
||||
CGContextTranslateCTM(context, 0, bounds.size.height);
|
||||
CGContextScaleCTM(context, 1.0, -1.0);
|
||||
[self.layer renderInContext:context];
|
||||
CGPDFContextEndPage(context);
|
||||
CGPDFContextClose(context);
|
||||
CGContextRelease(context);
|
||||
return data;
|
||||
}
|
||||
|
||||
- (UIViewController *)viewController {
|
||||
UIView *view = self;
|
||||
while (view) {
|
||||
UIResponder *nextResponder = [view nextResponder];
|
||||
if ([nextResponder isKindOfClass:[UIViewController class]]) {
|
||||
return (UIViewController *)nextResponder;
|
||||
}
|
||||
view = view.superview;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
static void *kUIViewLayoutMethodPropertyBottomGap = &kUIViewLayoutMethodPropertyBottomGap;
|
||||
static void *kUIViewLayoutMethodPropertyTopGap = &kUIViewLayoutMethodPropertyTopGap;
|
||||
static void *kUIViewLayoutMethodPropertyLeftGap = &kUIViewLayoutMethodPropertyLeftGap;
|
||||
static void *kUIViewLayoutMethodPropertyRightGap = &kUIViewLayoutMethodPropertyRightGap;
|
||||
|
||||
- (CGFloat)mm_safeAreaBottomGap
|
||||
{
|
||||
NSNumber *gap = objc_getAssociatedObject(self, kUIViewLayoutMethodPropertyBottomGap);
|
||||
if (gap == nil) {
|
||||
if (@available(iOS 11, *)) {
|
||||
if (self.superview.safeAreaLayoutGuide.layoutFrame.size.height > 0) {
|
||||
gap = @((self.superview.mm_h - self.superview.safeAreaLayoutGuide.layoutFrame.origin.y - self.superview.safeAreaLayoutGuide.layoutFrame.size.height));
|
||||
} else {
|
||||
gap = nil;
|
||||
}
|
||||
} else {
|
||||
gap = @(0);
|
||||
}
|
||||
objc_setAssociatedObject(self, kUIViewLayoutMethodPropertyBottomGap, gap, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
return gap.floatValue;
|
||||
}
|
||||
|
||||
- (CGFloat)mm_safeAreaTopGap
|
||||
{
|
||||
NSNumber *gap = objc_getAssociatedObject(self, kUIViewLayoutMethodPropertyTopGap);
|
||||
if (gap == nil) {
|
||||
if (@available(iOS 11, *)) {
|
||||
gap = @(self.superview.safeAreaLayoutGuide.layoutFrame.origin.y);
|
||||
} else {
|
||||
gap = @(0);
|
||||
}
|
||||
objc_setAssociatedObject(self, kUIViewLayoutMethodPropertyTopGap, gap, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
return gap.floatValue;
|
||||
}
|
||||
|
||||
- (CGFloat)mm_safeAreaLeftGap
|
||||
{
|
||||
NSNumber *gap = objc_getAssociatedObject(self, kUIViewLayoutMethodPropertyLeftGap);
|
||||
if (gap == nil) {
|
||||
if (@available(iOS 11, *)) {
|
||||
gap = @(self.superview.safeAreaLayoutGuide.layoutFrame.origin.x);
|
||||
} else {
|
||||
gap = @(0);
|
||||
}
|
||||
objc_setAssociatedObject(self, kUIViewLayoutMethodPropertyLeftGap, gap, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
return gap.floatValue;
|
||||
}
|
||||
|
||||
- (CGFloat)mm_safeAreaRightGap
|
||||
{
|
||||
NSNumber *gap = objc_getAssociatedObject(self, kUIViewLayoutMethodPropertyRightGap);
|
||||
if (gap == nil) {
|
||||
if (@available(iOS 11, *)) {
|
||||
gap = @((self.superview.mm_w - self.superview.safeAreaLayoutGuide.layoutFrame.origin.x - self.superview.safeAreaLayoutGuide.layoutFrame.size.width));
|
||||
} else {
|
||||
gap = @(0);
|
||||
}
|
||||
objc_setAssociatedObject(self, kUIViewLayoutMethodPropertyRightGap, gap, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
return gap.floatValue;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface UIViewController (SuperPlayerRotation)
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,19 @@
|
||||
#import "UIViewController+SuperPlayerRotation.h"
|
||||
|
||||
@implementation UIViewController (SuperPlayerRotation)
|
||||
|
||||
/**
|
||||
* 默认所有都不支持转屏,如需个别页面支持除竖屏外的其他方向,请在viewController重新下边这三个方法
|
||||
*/
|
||||
|
||||
// 支持哪些屏幕方向
|
||||
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
|
||||
return UIInterfaceOrientationMaskPortrait;
|
||||
}
|
||||
|
||||
// 默认的屏幕方向(当前ViewController必须是通过模态出来的UIViewController(模态带导航的无效)方式展现出来的,才会调用这个方法)
|
||||
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
|
||||
return UIInterfaceOrientationPortrait;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// AdaptiveStream.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AdaptiveStream : NSObject
|
||||
@property NSString *url;
|
||||
@property NSString *drmType;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// AdaptiveStream.m
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AdaptiveStream.h"
|
||||
|
||||
@implementation AdaptiveStream
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,69 @@
|
||||
//
|
||||
// SPPlayCGIParseResult.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
//#import "SPResolutionDefination.h"
|
||||
#import "SPSubStreamInfo.h"
|
||||
#import "AdaptiveStream.h"
|
||||
#import "SuperPlayerSprite.h"
|
||||
#import "SPVideoFrameDescription.h"
|
||||
#import "SuperPlayerUrl.h"
|
||||
|
||||
@class TXImageSprite;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(NSUInteger, SPDrmType) {
|
||||
SPDrmTypeNone,
|
||||
SPDrmTypeSimpleAES
|
||||
};
|
||||
|
||||
@interface SPPlayCGIParseResult : NSObject
|
||||
/// 视频播放url
|
||||
@property (strong, nonatomic) NSString *url;
|
||||
/// 视频名称
|
||||
@property (strong, nonatomic) NSString *name;
|
||||
/// 雪略图对象
|
||||
@property (strong, nonatomic) TXImageSprite *imageSprite;
|
||||
/// 雪略图打点帧信息
|
||||
@property (strong, nonatomic) NSArray<SPVideoFrameDescription *> *keyFrameDescList;
|
||||
/// 字流画质信息
|
||||
@property (strong, nonatomic) NSArray<SPSubStreamInfo *> *resolutionArray;
|
||||
/// 原视频时长
|
||||
@property (assign, nonatomic) NSTimeInterval originalDuration;
|
||||
|
||||
/// 预留字段,暂不使用
|
||||
@property (strong, nonatomic) NSArray<AdaptiveStream *> *adaptiveStreamArray;
|
||||
|
||||
/// V2协议的多码率URL列表
|
||||
@property (strong, nonatomic) NSArray<SuperPlayerUrl *> *multiVideoURLs;
|
||||
|
||||
/// 加密类型,用于 Drm
|
||||
@property (assign, nonatomic) SPDrmType drmType;
|
||||
|
||||
/// 加密令牌,用于 Drm
|
||||
@property (copy, nonatomic) NSString *drmToken;
|
||||
+ (SPDrmType)drmTypeFromString:(NSString *)typeString;
|
||||
/**
|
||||
* 获取画质信息
|
||||
*
|
||||
* @return 画质信息数组
|
||||
|
||||
List<TCVideoQuality> getVideoQualityList();
|
||||
|
||||
|
||||
* 获取默认画质信息
|
||||
*
|
||||
* @return 默认画质信息对象
|
||||
|
||||
TCVideoQuality getDefaultVideoQuality();
|
||||
*/
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// SPPlayCGIParseResult.m
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SPPlayCGIParseResult.h"
|
||||
#import "TXImageSprite.h"
|
||||
|
||||
@implementation SPPlayCGIParseResult
|
||||
+ (SPDrmType)drmTypeFromString:(NSString *)typeString {
|
||||
BOOL isSimpleAES = [typeString caseInsensitiveCompare:@"SimpleAES"] == NSOrderedSame;
|
||||
if (isSimpleAES) {
|
||||
return SPDrmTypeSimpleAES;
|
||||
}
|
||||
return SPDrmTypeNone;
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// SPSubStreamInfo.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by Steven Choi on 2020/2/11.
|
||||
// Copyright © 2020 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreGraphics/CoreGraphics.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 自适应码流子流信息
|
||||
@interface SPSubStreamInfo : NSObject
|
||||
@property (assign, nonatomic) CGSize size;
|
||||
@property (copy, nonatomic) NSString *resolutionName;
|
||||
@property (copy, nonatomic) NSString *type;
|
||||
+ (instancetype)infoWithDictionary:(NSDictionary *)dict;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// SPSubStreamInfo.m
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by Steven Choi on 2020/2/11.
|
||||
// Copyright © 2020 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SPSubStreamInfo.h"
|
||||
#import "J2Obj.h"
|
||||
@implementation SPSubStreamInfo
|
||||
+ (instancetype)infoWithDictionary:(NSDictionary *)dict {
|
||||
SPSubStreamInfo *info = [[SPSubStreamInfo alloc] init];
|
||||
double width = [J2Num(dict[@"width"]) doubleValue];
|
||||
double height = [J2Num(dict[@"height"]) doubleValue];
|
||||
info.size = CGSizeMake(width, height);
|
||||
info.resolutionName = J2Str(dict[@"name"]);
|
||||
info.type = J2Str(dict[@"type"]);
|
||||
return info;
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// SPVideoFrameDescription.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface SPVideoFrameDescription : NSObject
|
||||
// updates in SuperPlayerView
|
||||
@property double where;
|
||||
@property NSString *text;
|
||||
@property double time;
|
||||
+ (instancetype)instanceFromDictionary:(NSDictionary *)dict;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// SPVideoFrameDescription.m
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SPVideoFrameDescription.h"
|
||||
#import "J2Obj.h"
|
||||
|
||||
@implementation SPVideoFrameDescription
|
||||
+ (instancetype)instanceFromDictionary:(NSDictionary *)keyFrameDesc {
|
||||
if (![keyFrameDesc isKindOfClass:[NSDictionary class]]) {
|
||||
return nil;
|
||||
}
|
||||
SPVideoFrameDescription *ret = [[SPVideoFrameDescription alloc] init];
|
||||
ret.time = [J2Num([keyFrameDesc valueForKeyPath:@"timeOffset"]) intValue]/1000.0;
|
||||
ret.text = [J2Str([keyFrameDesc valueForKeyPath:@"content"]) stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
||||
return ret;
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// SuperPlayerSprite.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface SuperPlayerSprite : NSObject
|
||||
@property (strong, nonatomic) NSArray<NSString *> *imageURLs;
|
||||
@property (strong, nonatomic) NSString *webVttURL;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// SuperPlayerSprite.m
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SuperPlayerSprite.h"
|
||||
|
||||
@implementation SuperPlayerSprite
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// SuperPlayerUrl.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
/**
|
||||
* 多码率地址
|
||||
* 用于有多个播放地址的多清晰度视频的播放
|
||||
*/
|
||||
@interface SuperPlayerUrl : NSObject
|
||||
/// 播放器展示的对应标题,如“高清”、“低清”等
|
||||
@property NSString *title;
|
||||
/// 播放地址
|
||||
@property NSString *url;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// SuperPlayerUrl.m
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SuperPlayerUrl.h"
|
||||
|
||||
@implementation SuperPlayerUrl
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// SPPlayCGIParser.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/26.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SPPlayCGIParserProtocol.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface SPPlayCGIParser : NSObject
|
||||
+ (Class<SPPlayCGIParserProtocol>)parserOfVersion:(NSInteger)version;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// SPPlayCGIParser.m
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/26.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SPPlayCGIParser.h"
|
||||
#import "SPPlayCGIParser_V2.h"
|
||||
#import "SPPlayCGIParser_V4.h"
|
||||
|
||||
@implementation SPPlayCGIParser
|
||||
+ (Class<SPPlayCGIParserProtocol>)parserOfVersion:(NSInteger)version {
|
||||
if (version == 2) {
|
||||
return [SPPlayCGIParser_V2 class];
|
||||
} else if (version == 4) {
|
||||
return [SPPlayCGIParser_V4 class];
|
||||
}
|
||||
return Nil;
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// PlayCGIParserProtocol.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SPPlayCGIParseResult.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol SPPlayCGIParserProtocol <NSObject>
|
||||
+ (SPPlayCGIParseResult *)parseResponse:(NSDictionary *)jsonResp;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// SPPlayCGIParser_V2.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SPPlayCGIParserProtocol.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface SPPlayCGIParser_V2 : NSObject <SPPlayCGIParserProtocol>
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,105 @@
|
||||
//
|
||||
// SPPlayCGIParser_V2.m
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SPPlayCGIParser_V2.h"
|
||||
#import "J2Obj.h"
|
||||
#import "SuperPlayerUrl.h"
|
||||
#import "TXBitrateItemHelper.h"
|
||||
#import "TXImageSprite.h"
|
||||
|
||||
@implementation SPPlayCGIParser_V2
|
||||
+ (SPPlayCGIParseResult *)parseResponse:(NSDictionary *)responseObject {
|
||||
SPPlayCGIParseResult *ret = [[SPPlayCGIParseResult alloc] init];
|
||||
NSString *masterUrl = J2Str([responseObject valueForKeyPath:@"videoInfo.masterPlayList.url"]);
|
||||
// masterUrl = nil;
|
||||
if (masterUrl.length > 0) {
|
||||
// 1. 如果有master url,优先用这个
|
||||
ret.url = masterUrl;
|
||||
} else {
|
||||
NSString *mainDefinition = J2Str([responseObject valueForKeyPath:@"playerInfo.defaultVideoClassification"]);
|
||||
|
||||
NSArray *videoClassification = J2Array([responseObject valueForKeyPath:@"playerInfo.videoClassification"]);
|
||||
NSArray *transcodeList = J2Array([responseObject valueForKeyPath:@"videoInfo.transcodeList"]);
|
||||
|
||||
NSMutableArray<SuperPlayerUrl *> *result = [NSMutableArray new];
|
||||
|
||||
// 2. 如果有转码的清晰度,用转码流
|
||||
for (NSDictionary *transcode in transcodeList) {
|
||||
SuperPlayerUrl *subModel = [SuperPlayerUrl new];
|
||||
subModel.url = J2Str(transcode[@"url"]);
|
||||
NSNumber *theDefinition = J2Num(transcode[@"definition"]);
|
||||
|
||||
for (NSDictionary *definition in videoClassification) {
|
||||
for (NSObject *definition2 in J2Array([definition valueForKeyPath:@"definitionList"])) {
|
||||
|
||||
if ([definition2 isEqual:theDefinition]) {
|
||||
subModel.title = J2Str([definition valueForKeyPath:@"name"]);
|
||||
NSString *definitionId = J2Str([definition valueForKeyPath:@"id"]);
|
||||
// 初始播放清晰度
|
||||
if ([definitionId isEqualToString:mainDefinition]) {
|
||||
if (![ret.url containsString:@".mp4"])
|
||||
ret.url = subModel.url;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 同一个清晰度可能存在多个转码格式,这里只保留一种格式,且优先mp4类型
|
||||
for (SuperPlayerUrl *item in result) {
|
||||
if ([item.title isEqual:subModel.title]) {
|
||||
if (![item.url containsString:@".mp4"]) {
|
||||
item.url = subModel.url;
|
||||
}
|
||||
subModel = nil;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (subModel) {
|
||||
[result addObject:subModel];
|
||||
}
|
||||
}
|
||||
ret.multiVideoURLs = result;
|
||||
}
|
||||
// 3. 以上都没有,用原始地址
|
||||
if (ret.url == nil) {
|
||||
NSString *source = J2Str([responseObject valueForKeyPath:@"videoInfo.sourceVideo.url"]);
|
||||
ret.url = source;
|
||||
}
|
||||
|
||||
NSArray *imageSprites = J2Array([responseObject valueForKeyPath:@"imageSpriteInfo.imageSpriteList"]);
|
||||
if (imageSprites.count > 0) {
|
||||
// id imageSpriteObj = imageSprites[0];
|
||||
id imageSpriteObj = imageSprites.lastObject;
|
||||
NSString *vtt = J2Str([imageSpriteObj valueForKeyPath:@"webVttUrl"]);
|
||||
NSArray *imgUrls = J2Array([imageSpriteObj valueForKeyPath:@"imageUrls"]);
|
||||
NSMutableArray *imgUrlArray = @[].mutableCopy;
|
||||
for (NSString *url in imgUrls) {
|
||||
NSURL *nsurl = [NSURL URLWithString:url];
|
||||
if (nsurl) {
|
||||
[imgUrlArray addObject:nsurl];
|
||||
}
|
||||
}
|
||||
|
||||
TXImageSprite *imageSprite = [[TXImageSprite alloc] init];
|
||||
[imageSprite setVTTUrl:[NSURL URLWithString:vtt] imageUrls:imgUrlArray];
|
||||
ret.imageSprite = imageSprite;
|
||||
}
|
||||
|
||||
NSArray *keyFrameDescList = J2Array([responseObject valueForKeyPath:@"keyFrameDescInfo.keyFrameDescList"]);
|
||||
if (keyFrameDescList.count > 0) {
|
||||
NSMutableArray<SPVideoFrameDescription *> *checkPoints = [[NSMutableArray alloc] initWithCapacity:keyFrameDescList.count];
|
||||
for (NSDictionary *info in keyFrameDescList) {
|
||||
SPVideoFrameDescription *checkPoint = [SPVideoFrameDescription instanceFromDictionary:info];
|
||||
[checkPoints addObject:checkPoint];
|
||||
}
|
||||
ret.keyFrameDescList = checkPoints;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// PlayCGIV4Parser.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SPPlayCGIParserProtocol.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface SPPlayCGIParser_V4 : NSObject <SPPlayCGIParserProtocol>
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,122 @@
|
||||
//
|
||||
// PlayCGIV4Parser.m
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SPPlayCGIParser_V4.h"
|
||||
//#import "SPResolutionDefination.h"
|
||||
#import "SPSubStreamInfo.h"
|
||||
#import "AdaptiveStream.h"
|
||||
#import "TXImageSprite.h"
|
||||
#import "J2Obj.h"
|
||||
|
||||
@implementation SPPlayCGIParser_V4
|
||||
|
||||
+ (SPPlayCGIParseResult *)parseResponse:(NSDictionary *)jsonResp {
|
||||
SPPlayCGIParseResult *ret = [[SPPlayCGIParseResult alloc] init];
|
||||
|
||||
// 获取媒体信息
|
||||
NSDictionary *media = jsonResp[@"media"];
|
||||
if ([media isKindOfClass:[NSDictionary class]]) {
|
||||
do {
|
||||
//解析视频名称
|
||||
ret.name = [media valueForKeyPath:@"basicInfo.name"];
|
||||
NSDictionary *streamInfo = [media valueForKeyPath:@"streamingInfo.plainOutput"];
|
||||
if (streamInfo == nil) {
|
||||
NSArray* drmOutputs = [media valueForKeyPath:@"streamingInfo.drmOutput"];
|
||||
for (NSDictionary *drmOutput in drmOutputs) {
|
||||
SPDrmType type = [SPPlayCGIParseResult drmTypeFromString:J2Str(drmOutput[@"type"])];
|
||||
if (type == SPDrmTypeSimpleAES) {
|
||||
streamInfo = drmOutput;
|
||||
ret.drmType = SPDrmTypeSimpleAES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ret.drmToken = [media valueForKeyPath:@"streamingInfo.drmToken"];
|
||||
}
|
||||
if (streamInfo == nil) {
|
||||
return nil;
|
||||
}
|
||||
NSNumber *duration = [media valueForKeyPath:@"basicInfo.duration"];
|
||||
if ([duration isKindOfClass:[NSNumber class]]) {
|
||||
ret.originalDuration = duration.doubleValue;
|
||||
}
|
||||
// 解析分辨率名称
|
||||
NSArray *subStreamDictArray = J2Array(streamInfo[@"subStreams"]);
|
||||
NSMutableArray *subStreamInfoArray = [NSMutableArray arrayWithCapacity:subStreamDictArray.count];
|
||||
for (NSDictionary *resInfo in subStreamDictArray) {
|
||||
SuperPlayerUrl *url = [[SuperPlayerUrl alloc] init];
|
||||
url.title = J2Str(resInfo[@"resolutionName"]);
|
||||
// SPSubStreamInfo *info = [SPSubStreamInfo infoWithDictionary:resInfo];
|
||||
[subStreamInfoArray addObject:url];
|
||||
}
|
||||
ret.multiVideoURLs = subStreamInfoArray;
|
||||
|
||||
//解析视频播放url
|
||||
NSString *url = streamInfo[@"url"];
|
||||
if ([url isKindOfClass:[NSString class]] && url.length > 0) {
|
||||
//未加密直接解析出视频url
|
||||
ret.url = url;
|
||||
} else {
|
||||
//有加密,url为空,则解析drm加密的url信息
|
||||
NSArray *urlArray = streamInfo[@"drmUrls"];
|
||||
if ([urlArray isKindOfClass:[NSArray class]] &&
|
||||
urlArray.count > 0) {
|
||||
NSMutableArray *drmURLArray = [NSMutableArray arrayWithCapacity:urlArray.count];
|
||||
for (NSDictionary *dict in urlArray) {
|
||||
if ([dict isKindOfClass:[NSDictionary class]]) {
|
||||
continue;
|
||||
}
|
||||
AdaptiveStream *stream = [[AdaptiveStream alloc] init];
|
||||
stream.url = dict[@"url"];
|
||||
stream.drmType = dict[@"type"];
|
||||
[drmURLArray addObject:stream];
|
||||
}
|
||||
ret.adaptiveStreamArray = drmURLArray;
|
||||
}
|
||||
}
|
||||
|
||||
//解析略缩图信息
|
||||
NSDictionary *imageSpriteInfo = media[@"imageSpriteInfo"];
|
||||
|
||||
if ([imageSpriteInfo isKindOfClass:[NSDictionary class]]) {
|
||||
NSString *vttURLString = J2Str(imageSpriteInfo[@"webVttUrl"]);
|
||||
NSURL *vttURL = [NSURL URLWithString:vttURLString];
|
||||
NSArray *imageURLStrings = J2Array(imageSpriteInfo[@"imageUrls"]);
|
||||
NSMutableArray<NSURL *> *imageURLs = [NSMutableArray arrayWithCapacity:imageURLStrings.count];
|
||||
for (NSString *urlString in imageURLStrings) {
|
||||
NSURL *url = [NSURL URLWithString:urlString];
|
||||
if (url) {
|
||||
[imageURLs addObject:url];
|
||||
}
|
||||
}
|
||||
TXImageSprite *sprite = [[TXImageSprite alloc] init];
|
||||
[sprite setVTTUrl:vttURL imageUrls:imageURLs];
|
||||
ret.imageSprite = sprite;
|
||||
}
|
||||
|
||||
//解析关键帧信息
|
||||
NSDictionary *keyFrameDescInfo = media[@"keyFrameDescInfo"];
|
||||
if ([keyFrameDescInfo isKindOfClass:[NSDictionary class]]) {
|
||||
NSArray *keyFrameDescList = keyFrameDescInfo[@"keyFrameDescList"];
|
||||
if ([keyFrameDescList isKindOfClass:[NSArray class]] &&
|
||||
keyFrameDescList.count > 0) {
|
||||
NSMutableArray<SPVideoFrameDescription *> *videoPoints = [NSMutableArray array];
|
||||
for (NSDictionary *jsonObject in keyFrameDescList) {
|
||||
SPVideoFrameDescription *point = [SPVideoFrameDescription instanceFromDictionary:jsonObject];
|
||||
if (point) {
|
||||
[videoPoints addObject:point];
|
||||
}
|
||||
}
|
||||
ret.keyFrameDescList = videoPoints;
|
||||
}
|
||||
}
|
||||
} while (0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@end
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 361 B |
|
After Width: | Height: | Size: 539 B |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 327 B |
|
After Width: | Height: | Size: 426 B |
|
After Width: | Height: | Size: 615 B |
|
After Width: | Height: | Size: 834 B |
|
After Width: | Height: | Size: 565 B |
|
After Width: | Height: | Size: 772 B |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 173 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 587 B |
|
After Width: | Height: | Size: 833 B |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 270 B |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 577 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 124 B |
|
After Width: | Height: | Size: 125 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 907 B |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 753 B |
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// SPDefaultControlView.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by annidyfeng on 2018/9/30.
|
||||
//
|
||||
|
||||
#import "SuperPlayerControlView.h"
|
||||
|
||||
@interface SPDefaultControlView : SuperPlayerControlView
|
||||
|
||||
|
||||
/** 标题 */
|
||||
@property (nonatomic, strong) UILabel *titleLabel;
|
||||
/** 开始播放按钮 */
|
||||
@property (nonatomic, strong) UIButton *startBtn;
|
||||
/** 当前播放时长label */
|
||||
@property (nonatomic, strong) UILabel *currentTimeLabel;
|
||||
/** 视频总时长label */
|
||||
@property (nonatomic, strong) UILabel *totalTimeLabel;
|
||||
/** 全屏按钮 */
|
||||
@property (nonatomic, strong) UIButton *fullScreenBtn;
|
||||
/** 锁定屏幕方向按钮 */
|
||||
@property (nonatomic, strong) UIButton *lockBtn;
|
||||
|
||||
/** 返回按钮*/
|
||||
@property (nonatomic, strong) UIButton *backBtn;
|
||||
/// 是否禁用返回
|
||||
@property (nonatomic) BOOL disableBackBtn;
|
||||
/** bottomView*/
|
||||
@property (nonatomic, strong) UIImageView *bottomImageView;
|
||||
/** topView */
|
||||
@property (nonatomic, strong) UIImageView *topImageView;
|
||||
/** 弹幕按钮 */
|
||||
@property (nonatomic, strong) UIButton *danmakuBtn;
|
||||
/// 是否禁用弹幕
|
||||
@property (nonatomic) BOOL disableDanmakuBtn;
|
||||
/** 截图按钮 */
|
||||
@property (nonatomic, strong) UIButton *captureBtn;
|
||||
/// 是否禁用截图
|
||||
@property (nonatomic) BOOL disableCaptureBtn;
|
||||
/** 更多按钮 */
|
||||
@property (nonatomic, strong) UIButton *moreBtn;
|
||||
/// 是否禁用更多
|
||||
@property (nonatomic) BOOL disableMoreBtn;
|
||||
/** 切换分辨率按钮 */
|
||||
@property (nonatomic, strong) UIButton *resolutionBtn;
|
||||
/** 分辨率的View */
|
||||
@property (nonatomic, strong) UIView *resolutionView;
|
||||
/** 播放按钮 */
|
||||
@property (nonatomic, strong) UIButton *playeBtn;
|
||||
/** 加载失败按钮 */
|
||||
@property (nonatomic, strong) UIButton *middleBtn;
|
||||
|
||||
/** 当前选中的分辨率btn按钮 */
|
||||
@property (nonatomic, weak ) UIButton *resoultionCurrentBtn;
|
||||
|
||||
/** 分辨率的名称 */
|
||||
@property (nonatomic, strong) NSArray<NSString *> *resolutionArray;
|
||||
/** 更多设置View */
|
||||
@property (nonatomic, strong) SuperPlayerSettingsView *moreContentView;
|
||||
/** 返回直播 */
|
||||
@property (nonatomic, strong) UIButton *backLiveBtn;
|
||||
|
||||
/// 画面比例
|
||||
@property CGFloat videoRatio;
|
||||
|
||||
/** 滑杆 */
|
||||
@property (nonatomic, strong) PlayerSlider *videoSlider;
|
||||
|
||||
/** 重播按钮 */
|
||||
@property (nonatomic, strong) UIButton *repeatBtn;
|
||||
|
||||
/** 是否全屏播放 */
|
||||
@property (nonatomic, assign,getter=isFullScreen)BOOL fullScreen;
|
||||
@property (nonatomic, assign,getter=isLockScreen)BOOL isLockScreen;
|
||||
@property (nonatomic, strong) UIButton *pointJumpBtn;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,774 @@
|
||||
#import "SuperPlayerControlView.h"
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <MediaPlayer/MediaPlayer.h>
|
||||
|
||||
#import "SuperPlayerSettingsView.h"
|
||||
#import "DataReport.h"
|
||||
#import "SuperPlayerFastView.h"
|
||||
#import "PlayerSlider.h"
|
||||
#import "UIView+MMLayout.h"
|
||||
#import "SuperPlayerView+Private.h"
|
||||
#import "StrUtils.h"
|
||||
#import "SPDefaultControlView.h"
|
||||
#import "UIView+Fade.h"
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored"-Wdeprecated-declarations"
|
||||
|
||||
#define MODEL_TAG_BEGIN 20
|
||||
#define BOTTOM_IMAGE_VIEW_HEIGHT 50
|
||||
|
||||
@interface SPDefaultControlView () <UIGestureRecognizerDelegate, PlayerSliderDelegate>
|
||||
@property BOOL isLive;
|
||||
@end
|
||||
|
||||
@implementation SPDefaultControlView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
[self addSubview:self.topImageView];
|
||||
[self addSubview:self.bottomImageView];
|
||||
[self.bottomImageView addSubview:self.startBtn];
|
||||
[self.bottomImageView addSubview:self.currentTimeLabel];
|
||||
[self.bottomImageView addSubview:self.videoSlider];
|
||||
[self.bottomImageView addSubview:self.resolutionBtn];
|
||||
[self.bottomImageView addSubview:self.fullScreenBtn];
|
||||
[self.bottomImageView addSubview:self.totalTimeLabel];
|
||||
|
||||
[self.topImageView addSubview:self.captureBtn];
|
||||
[self.topImageView addSubview:self.danmakuBtn];
|
||||
[self.topImageView addSubview:self.moreBtn];
|
||||
[self addSubview:self.lockBtn];
|
||||
[self.topImageView addSubview:self.backBtn];
|
||||
|
||||
[self addSubview:self.playeBtn];
|
||||
|
||||
[self.topImageView addSubview:self.titleLabel];
|
||||
|
||||
|
||||
[self addSubview:self.backLiveBtn];
|
||||
|
||||
// 添加子控件的约束
|
||||
[self makeSubViewsConstraints];
|
||||
|
||||
self.captureBtn.hidden = YES;
|
||||
self.danmakuBtn.hidden = YES;
|
||||
self.moreBtn.hidden = YES;
|
||||
self.resolutionBtn.hidden = YES;
|
||||
self.moreContentView.hidden = YES;
|
||||
// 初始化时重置controlView
|
||||
[self playerResetControlView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)makeSubViewsConstraints {
|
||||
|
||||
[self.topImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.trailing.equalTo(self);
|
||||
make.top.equalTo(self.mas_top).offset(0);
|
||||
make.height.mas_equalTo(50);
|
||||
}];
|
||||
|
||||
[self.backBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.equalTo(self.topImageView.mas_leading).offset(5);
|
||||
make.top.equalTo(self.topImageView.mas_top).offset(3);
|
||||
make.width.height.mas_equalTo(40);
|
||||
}];
|
||||
|
||||
[self.moreBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.mas_equalTo(40);
|
||||
make.height.mas_equalTo(49);
|
||||
make.trailing.equalTo(self.topImageView.mas_trailing).offset(-10);
|
||||
make.centerY.equalTo(self.backBtn.mas_centerY);
|
||||
}];
|
||||
|
||||
[self.captureBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.mas_equalTo(40);
|
||||
make.height.mas_equalTo(49);
|
||||
make.trailing.equalTo(self.moreBtn.mas_leading).offset(-10);
|
||||
make.centerY.equalTo(self.backBtn.mas_centerY);
|
||||
}];
|
||||
|
||||
[self.danmakuBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.mas_equalTo(40);
|
||||
make.height.mas_equalTo(49);
|
||||
make.trailing.equalTo(self.captureBtn.mas_leading).offset(-10);
|
||||
make.centerY.equalTo(self.backBtn.mas_centerY);
|
||||
}];
|
||||
|
||||
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.equalTo(self.backBtn.mas_trailing).offset(5);
|
||||
make.centerY.equalTo(self.backBtn.mas_centerY);
|
||||
make.trailing.equalTo(self.captureBtn.mas_leading).offset(-10);
|
||||
}];
|
||||
|
||||
[self.bottomImageView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.trailing.bottom.mas_equalTo(0);
|
||||
make.height.mas_equalTo(BOTTOM_IMAGE_VIEW_HEIGHT);
|
||||
}];
|
||||
|
||||
[self.startBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.equalTo(self.bottomImageView.mas_leading).offset(5);
|
||||
make.top.equalTo(self.bottomImageView.mas_top).offset(10);
|
||||
make.width.height.mas_equalTo(30);
|
||||
}];
|
||||
|
||||
[self.currentTimeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.equalTo(self.startBtn.mas_trailing);
|
||||
make.centerY.equalTo(self.startBtn.mas_centerY);
|
||||
make.width.mas_equalTo(60);
|
||||
}];
|
||||
|
||||
[self.fullScreenBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.height.mas_equalTo(30);
|
||||
make.trailing.equalTo(self.bottomImageView.mas_trailing).offset(-8);
|
||||
make.centerY.equalTo(self.startBtn.mas_centerY);
|
||||
}];
|
||||
|
||||
[self.resolutionBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.height.mas_equalTo(30);
|
||||
make.width.mas_greaterThanOrEqualTo(45);
|
||||
make.trailing.equalTo(self.bottomImageView.mas_trailing).offset(-8);
|
||||
make.centerY.equalTo(self.startBtn.mas_centerY);
|
||||
}];
|
||||
|
||||
[self.totalTimeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.trailing.equalTo(self.fullScreenBtn.mas_leading);
|
||||
make.centerY.equalTo(self.startBtn.mas_centerY);
|
||||
make.width.mas_equalTo(60);
|
||||
}];
|
||||
|
||||
[self.videoSlider mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.equalTo(self.currentTimeLabel.mas_trailing);
|
||||
make.trailing.equalTo(self.totalTimeLabel.mas_leading);
|
||||
make.centerY.equalTo(self.currentTimeLabel.mas_centerY).offset(-1);
|
||||
}];
|
||||
|
||||
[self.lockBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.equalTo(self.mas_leading).offset(15);
|
||||
make.centerY.equalTo(self.mas_centerY);
|
||||
make.width.height.mas_equalTo(32);
|
||||
}];
|
||||
|
||||
|
||||
[self.playeBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.height.mas_equalTo(50);
|
||||
make.center.equalTo(self);
|
||||
}];
|
||||
|
||||
|
||||
[self.backLiveBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.bottom.mas_equalTo(self.startBtn.mas_top).mas_offset(-15);
|
||||
make.width.mas_equalTo(70);
|
||||
make.centerX.equalTo(self);
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma mark - Action
|
||||
|
||||
/**
|
||||
* 点击切换分别率按钮
|
||||
*/
|
||||
- (void)changeResolution:(UIButton *)sender {
|
||||
self.resoultionCurrentBtn.selected = NO;
|
||||
self.resoultionCurrentBtn.backgroundColor = [UIColor clearColor];
|
||||
self.resoultionCurrentBtn = sender;
|
||||
self.resoultionCurrentBtn.selected = YES;
|
||||
self.resoultionCurrentBtn.backgroundColor = RGBA(34, 30, 24, 1);
|
||||
|
||||
// topImageView上的按钮的文字
|
||||
[self.resolutionBtn setTitle:sender.titleLabel.text forState:UIControlStateNormal];
|
||||
[self.delegate controlViewSwitch:self withDefinition:sender.titleLabel.text];
|
||||
}
|
||||
|
||||
- (void)backBtnClick:(UIButton *)sender {
|
||||
if ([self.delegate respondsToSelector:@selector(controlViewBack:)]) {
|
||||
[self.delegate controlViewBack:self];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)exitFullScreen:(UIButton *)sender {
|
||||
if ([self.delegate respondsToSelector:@selector(controlViewChangeScreen:withFullScreen:)]) {
|
||||
[self.delegate controlViewChangeScreen:self withFullScreen:NO];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)lockScrrenBtnClick:(UIButton *)sender {
|
||||
sender.selected = !sender.selected;
|
||||
self.isLockScreen = sender.selected;
|
||||
self.topImageView.hidden = self.isLockScreen;
|
||||
self.bottomImageView.hidden = self.isLockScreen;
|
||||
if (self.isLive) {
|
||||
self.backLiveBtn.hidden = self.isLockScreen;
|
||||
}
|
||||
[self.delegate controlViewLockScreen:self withLock:self.isLockScreen];
|
||||
[self fadeOut:3];
|
||||
}
|
||||
|
||||
- (void)playBtnClick:(UIButton *)sender {
|
||||
sender.selected = !sender.selected;
|
||||
if (sender.selected) {
|
||||
[self.delegate controlViewPlay:self];
|
||||
} else {
|
||||
[self.delegate controlViewPause:self];
|
||||
}
|
||||
[self cancelFadeOut];
|
||||
}
|
||||
|
||||
- (void)fullScreenBtnClick:(UIButton *)sender {
|
||||
sender.selected = !sender.selected;
|
||||
self.fullScreen = !self.fullScreen;
|
||||
[self.delegate controlViewChangeScreen:self withFullScreen:YES];
|
||||
[self fadeOut:3];
|
||||
}
|
||||
|
||||
|
||||
- (void)captureBtnClick:(UIButton *)sender {
|
||||
[self.delegate controlViewSnapshot:self];
|
||||
[self fadeOut:3];
|
||||
}
|
||||
|
||||
- (void)danmakuBtnClick:(UIButton *)sender {
|
||||
sender.selected = !sender.selected;
|
||||
[self fadeOut:3];
|
||||
}
|
||||
|
||||
- (void)moreBtnClick:(UIButton *)sender {
|
||||
self.topImageView.hidden = YES;
|
||||
self.bottomImageView.hidden = YES;
|
||||
self.lockBtn.hidden = YES;
|
||||
|
||||
self.moreContentView.playerConfig = self.playerConfig;
|
||||
[self.moreContentView update];
|
||||
self.moreContentView.hidden = NO;
|
||||
|
||||
[self cancelFadeOut];
|
||||
self.isShowSecondView = YES;
|
||||
}
|
||||
|
||||
- (UIView *)resolutionView {
|
||||
if (!_resolutionView) {
|
||||
// 添加分辨率按钮和分辨率下拉列表
|
||||
|
||||
_resolutionView = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
_resolutionView.hidden = YES;
|
||||
[self addSubview:_resolutionView];
|
||||
[_resolutionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.mas_equalTo(330);
|
||||
make.height.mas_equalTo(self.mas_height);
|
||||
make.trailing.equalTo(self.mas_trailing).offset(0);
|
||||
make.top.equalTo(self.mas_top).offset(0);
|
||||
}];
|
||||
|
||||
_resolutionView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5];
|
||||
}
|
||||
return _resolutionView;
|
||||
}
|
||||
|
||||
- (void)resolutionBtnClick:(UIButton *)sender {
|
||||
self.topImageView.hidden = YES;
|
||||
self.bottomImageView.hidden = YES;
|
||||
self.lockBtn.hidden = YES;
|
||||
|
||||
// 显示隐藏分辨率View
|
||||
self.resolutionView.hidden = NO;
|
||||
[DataReport report:@"change_resolution" param:nil];
|
||||
|
||||
[self cancelFadeOut];
|
||||
self.isShowSecondView = YES;
|
||||
}
|
||||
|
||||
- (void)progressSliderTouchBegan:(UISlider *)sender {
|
||||
self.isDragging = YES;
|
||||
[self cancelFadeOut];
|
||||
}
|
||||
|
||||
- (void)progressSliderValueChanged:(UISlider *)sender {
|
||||
if (self.maxPlayableRatio > 0 && sender.value > self.maxPlayableRatio) {
|
||||
sender.value = self.maxPlayableRatio;
|
||||
}
|
||||
[self.delegate controlViewPreview:self where:sender.value];
|
||||
}
|
||||
|
||||
- (void)progressSliderTouchEnded:(UISlider *)sender {
|
||||
[self.delegate controlViewSeek:self where:sender.value];
|
||||
self.isDragging = NO;
|
||||
[self fadeOut:5];
|
||||
}
|
||||
|
||||
- (void)backLiveClick:(UIButton *)sender {
|
||||
[self.delegate controlViewReload:self];
|
||||
}
|
||||
|
||||
- (void)pointJumpClick:(UIButton *)sender {
|
||||
self.pointJumpBtn.hidden = YES;
|
||||
PlayerPoint *point = [self.videoSlider.pointArray objectAtIndex:self.pointJumpBtn.tag];
|
||||
[self.delegate controlViewSeek:self where:point.where];
|
||||
[self fadeOut:0.1];
|
||||
}
|
||||
|
||||
- (void)setDisableBackBtn:(BOOL)disableBackBtn {
|
||||
_disableBackBtn = disableBackBtn;
|
||||
self.backBtn.hidden = disableBackBtn;
|
||||
}
|
||||
|
||||
- (void)setDisableMoreBtn:(BOOL)disableMoreBtn {
|
||||
_disableMoreBtn = disableMoreBtn;
|
||||
if (self.fullScreen) {
|
||||
self.moreBtn.hidden = disableMoreBtn;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setDisableCaptureBtn:(BOOL)disableCaptureBtn {
|
||||
_disableCaptureBtn = disableCaptureBtn;
|
||||
if (self.fullScreen) {
|
||||
self.captureBtn.hidden = disableCaptureBtn;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setDisableDanmakuBtn:(BOOL)disableDanmakuBtn {
|
||||
_disableDanmakuBtn = disableDanmakuBtn;
|
||||
if (self.fullScreen) {
|
||||
self.danmakuBtn.hidden = disableDanmakuBtn;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 屏幕方向发生变化会调用这里
|
||||
*/
|
||||
- (void)setOrientationLandscapeConstraint {
|
||||
self.fullScreen = YES;
|
||||
self.lockBtn.hidden = NO;
|
||||
self.fullScreenBtn.selected = self.isLockScreen;
|
||||
self.fullScreenBtn.hidden = YES;
|
||||
self.resolutionBtn.hidden = self.resolutionArray.count == 0;
|
||||
self.moreBtn.hidden = self.disableMoreBtn;
|
||||
self.captureBtn.hidden = self.disableCaptureBtn;
|
||||
self.danmakuBtn.hidden = self.disableDanmakuBtn;
|
||||
|
||||
[self.backBtn setImage:SuperPlayerImage(@"back_full") forState:UIControlStateNormal];
|
||||
[self.totalTimeLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
if (self.resolutionArray.count > 0) {
|
||||
make.trailing.equalTo(self.resolutionBtn.mas_leading);
|
||||
} else {
|
||||
make.trailing.equalTo(self.bottomImageView.mas_trailing);
|
||||
}
|
||||
make.centerY.equalTo(self.startBtn.mas_centerY);
|
||||
make.width.mas_equalTo(self.isLive?10:60);
|
||||
}];
|
||||
|
||||
[self.bottomImageView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
CGFloat b = self.superview.mm_safeAreaBottomGap;
|
||||
make.height.mas_equalTo(BOTTOM_IMAGE_VIEW_HEIGHT+b);
|
||||
}];
|
||||
|
||||
self.videoSlider.hiddenPoints = NO;
|
||||
}
|
||||
/**
|
||||
* 设置竖屏的约束
|
||||
*/
|
||||
- (void)setOrientationPortraitConstraint {
|
||||
self.fullScreen = NO;
|
||||
self.lockBtn.hidden = YES;
|
||||
self.fullScreenBtn.selected = NO;
|
||||
self.fullScreenBtn.hidden = NO;
|
||||
self.resolutionBtn.hidden = YES;
|
||||
self.moreBtn.hidden = YES;
|
||||
self.captureBtn.hidden = YES;
|
||||
self.danmakuBtn.hidden = YES;
|
||||
self.moreContentView.hidden = YES;
|
||||
self.resolutionView.hidden = YES;
|
||||
|
||||
[self.totalTimeLabel mas_remakeConstraints:^(MASConstraintMaker *make) {
|
||||
make.trailing.equalTo(self.fullScreenBtn.mas_leading);
|
||||
make.centerY.equalTo(self.startBtn.mas_centerY);
|
||||
make.width.mas_equalTo(self.isLive?10:60);
|
||||
}];
|
||||
|
||||
[self.bottomImageView mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.height.mas_equalTo(BOTTOM_IMAGE_VIEW_HEIGHT);
|
||||
}];
|
||||
|
||||
self.videoSlider.hiddenPoints = YES;
|
||||
self.pointJumpBtn.hidden = YES;
|
||||
}
|
||||
|
||||
#pragma mark - Private Method
|
||||
|
||||
#pragma mark - setter
|
||||
|
||||
- (UILabel *)titleLabel {
|
||||
if (!_titleLabel) {
|
||||
_titleLabel = [[UILabel alloc] init];
|
||||
_titleLabel.textColor = [UIColor whiteColor];
|
||||
_titleLabel.font = [UIFont systemFontOfSize:15.0];
|
||||
}
|
||||
return _titleLabel;
|
||||
}
|
||||
|
||||
- (UIButton *)backBtn {
|
||||
if (!_backBtn) {
|
||||
_backBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_backBtn setImage:SuperPlayerImage(@"back_full") forState:UIControlStateNormal];
|
||||
[_backBtn addTarget:self action:@selector(backBtnClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _backBtn;
|
||||
}
|
||||
|
||||
- (UIImageView *)topImageView {
|
||||
if (!_topImageView) {
|
||||
_topImageView = [[UIImageView alloc] init];
|
||||
_topImageView.userInteractionEnabled = YES;
|
||||
_topImageView.image = SuperPlayerImage(@"top_shadow");
|
||||
}
|
||||
return _topImageView;
|
||||
}
|
||||
|
||||
- (UIImageView *)bottomImageView {
|
||||
if (!_bottomImageView) {
|
||||
_bottomImageView = [[UIImageView alloc] init];
|
||||
_bottomImageView.userInteractionEnabled = YES;
|
||||
_bottomImageView.image = SuperPlayerImage(@"bottom_shadow");
|
||||
}
|
||||
return _bottomImageView;
|
||||
}
|
||||
|
||||
- (UIButton *)lockBtn {
|
||||
if (!_lockBtn) {
|
||||
_lockBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
_lockBtn.exclusiveTouch = YES;
|
||||
[_lockBtn setImage:SuperPlayerImage(@"unlock-nor") forState:UIControlStateNormal];
|
||||
[_lockBtn setImage:SuperPlayerImage(@"lock-nor") forState:UIControlStateSelected];
|
||||
[_lockBtn addTarget:self action:@selector(lockScrrenBtnClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
}
|
||||
return _lockBtn;
|
||||
}
|
||||
|
||||
- (UIButton *)startBtn {
|
||||
if (!_startBtn) {
|
||||
_startBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_startBtn setImage:SuperPlayerImage(@"play") forState:UIControlStateNormal];
|
||||
[_startBtn setImage:SuperPlayerImage(@"pause") forState:UIControlStateSelected];
|
||||
[_startBtn addTarget:self action:@selector(playBtnClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _startBtn;
|
||||
}
|
||||
|
||||
- (UILabel *)currentTimeLabel {
|
||||
if (!_currentTimeLabel) {
|
||||
_currentTimeLabel = [[UILabel alloc] init];
|
||||
_currentTimeLabel.textColor = [UIColor whiteColor];
|
||||
_currentTimeLabel.font = [UIFont systemFontOfSize:12.0f];
|
||||
_currentTimeLabel.textAlignment = NSTextAlignmentCenter;
|
||||
}
|
||||
return _currentTimeLabel;
|
||||
}
|
||||
|
||||
- (PlayerSlider *)videoSlider {
|
||||
if (!_videoSlider) {
|
||||
_videoSlider = [[PlayerSlider alloc] init];
|
||||
[_videoSlider setThumbImage:SuperPlayerImage(@"slider_thumb") forState:UIControlStateNormal];
|
||||
_videoSlider.minimumTrackTintColor = TintColor;
|
||||
// slider开始滑动事件
|
||||
[_videoSlider addTarget:self action:@selector(progressSliderTouchBegan:) forControlEvents:UIControlEventTouchDown];
|
||||
// slider滑动中事件
|
||||
[_videoSlider addTarget:self action:@selector(progressSliderValueChanged:) forControlEvents:UIControlEventValueChanged];
|
||||
// slider结束滑动事件
|
||||
[_videoSlider addTarget:self action:@selector(progressSliderTouchEnded:) forControlEvents:UIControlEventTouchUpInside | UIControlEventTouchUpOutside];
|
||||
_videoSlider.delegate = self;
|
||||
}
|
||||
return _videoSlider;
|
||||
}
|
||||
|
||||
- (UILabel *)totalTimeLabel {
|
||||
if (!_totalTimeLabel) {
|
||||
_totalTimeLabel = [[UILabel alloc] init];
|
||||
_totalTimeLabel.textColor = [UIColor whiteColor];
|
||||
_totalTimeLabel.font = [UIFont systemFontOfSize:12.0f];
|
||||
_totalTimeLabel.textAlignment = NSTextAlignmentCenter;
|
||||
}
|
||||
return _totalTimeLabel;
|
||||
}
|
||||
|
||||
- (UIButton *)fullScreenBtn {
|
||||
if (!_fullScreenBtn) {
|
||||
_fullScreenBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_fullScreenBtn setImage:SuperPlayerImage(@"fullscreen") forState:UIControlStateNormal];
|
||||
[_fullScreenBtn addTarget:self action:@selector(fullScreenBtnClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _fullScreenBtn;
|
||||
}
|
||||
|
||||
- (UIButton *)captureBtn {
|
||||
if (!_captureBtn) {
|
||||
_captureBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_captureBtn setImage:SuperPlayerImage(@"capture") forState:UIControlStateNormal];
|
||||
[_captureBtn setImage:SuperPlayerImage(@"capture_pressed") forState:UIControlStateSelected];
|
||||
[_captureBtn addTarget:self action:@selector(captureBtnClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _captureBtn;
|
||||
}
|
||||
|
||||
- (UIButton *)danmakuBtn {
|
||||
if (!_danmakuBtn) {
|
||||
_danmakuBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_danmakuBtn setImage:SuperPlayerImage(@"danmu") forState:UIControlStateNormal];
|
||||
[_danmakuBtn setImage:SuperPlayerImage(@"danmu_pressed") forState:UIControlStateSelected];
|
||||
[_danmakuBtn addTarget:self action:@selector(danmakuBtnClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _danmakuBtn;
|
||||
}
|
||||
|
||||
- (UIButton *)moreBtn {
|
||||
if (!_moreBtn) {
|
||||
_moreBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_moreBtn setImage:SuperPlayerImage(@"more") forState:UIControlStateNormal];
|
||||
[_moreBtn setImage:SuperPlayerImage(@"more_pressed") forState:UIControlStateSelected];
|
||||
[_moreBtn addTarget:self action:@selector(moreBtnClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _moreBtn;
|
||||
}
|
||||
|
||||
- (UIButton *)resolutionBtn {
|
||||
if (!_resolutionBtn) {
|
||||
_resolutionBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
_resolutionBtn.titleLabel.font = [UIFont systemFontOfSize:12];
|
||||
_resolutionBtn.backgroundColor = [UIColor clearColor];
|
||||
[_resolutionBtn addTarget:self action:@selector(resolutionBtnClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _resolutionBtn;
|
||||
}
|
||||
|
||||
- (UIButton *)backLiveBtn {
|
||||
if (!_backLiveBtn) {
|
||||
_backLiveBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_backLiveBtn setTitle:@"返回直播" forState:UIControlStateNormal];
|
||||
_backLiveBtn.titleLabel.font = [UIFont systemFontOfSize:14];
|
||||
UIImage *image = SuperPlayerImage(@"qg_online_bg");
|
||||
|
||||
UIImage *resizableImage = [image resizableImageWithCapInsets:UIEdgeInsetsMake(33 * 0.5, 33 * 0.5, 33 * 0.5, 33 * 0.5)];
|
||||
[_backLiveBtn setBackgroundImage:resizableImage forState:UIControlStateNormal];
|
||||
|
||||
[_backLiveBtn addTarget:self action:@selector(backLiveClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _backLiveBtn;
|
||||
}
|
||||
|
||||
- (UIButton *)pointJumpBtn {
|
||||
if (!_pointJumpBtn) {
|
||||
_pointJumpBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
UIImage *image = SuperPlayerImage(@"copywright_bg");
|
||||
UIImage *resizableImage = [image resizableImageWithCapInsets:UIEdgeInsetsMake(0, 20, 0, 20) resizingMode:UIImageResizingModeStretch];
|
||||
[_pointJumpBtn setBackgroundImage:resizableImage forState:UIControlStateNormal];
|
||||
_pointJumpBtn.titleLabel.font = [UIFont systemFontOfSize:14];
|
||||
[_pointJumpBtn addTarget:self action:@selector(pointJumpClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self addSubview:_pointJumpBtn];
|
||||
}
|
||||
return _pointJumpBtn;
|
||||
}
|
||||
|
||||
- (SuperPlayerSettingsView *)moreContentView {
|
||||
if (!_moreContentView) {
|
||||
_moreContentView = [[SuperPlayerSettingsView alloc] initWithFrame:CGRectZero];
|
||||
_moreContentView.controlView = self;
|
||||
_moreContentView.hidden = YES;
|
||||
[self addSubview:_moreContentView];
|
||||
[_moreContentView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.mas_equalTo(330);
|
||||
make.height.mas_equalTo(self.mas_height);
|
||||
make.trailing.equalTo(self.mas_trailing).offset(0);
|
||||
make.top.equalTo(self.mas_top).offset(0);
|
||||
}];
|
||||
_moreContentView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5];
|
||||
}
|
||||
return _moreContentView;
|
||||
}
|
||||
|
||||
#pragma mark - UIGestureRecognizerDelegate
|
||||
|
||||
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
|
||||
if ([touch.view isKindOfClass:[UISlider class]]) { // 如果在滑块上点击就不响应pan手势
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - Public method
|
||||
|
||||
- (void)setHidden:(BOOL)hidden
|
||||
{
|
||||
[super setHidden:hidden];
|
||||
if (hidden) {
|
||||
self.resolutionView.hidden = YES;
|
||||
self.moreContentView.hidden = YES;
|
||||
if (!self.isLockScreen) {
|
||||
self.topImageView.hidden = NO;
|
||||
self.bottomImageView.hidden = NO;
|
||||
}
|
||||
}
|
||||
|
||||
self.lockBtn.hidden = !self.isFullScreen;
|
||||
self.isShowSecondView = NO;
|
||||
self.pointJumpBtn.hidden = YES;
|
||||
}
|
||||
|
||||
/** 重置ControlView */
|
||||
- (void)playerResetControlView {
|
||||
self.videoSlider.value = 0;
|
||||
self.videoSlider.progressView.progress = 0;
|
||||
self.currentTimeLabel.text = @"00:00";
|
||||
self.totalTimeLabel.text = @"00:00";
|
||||
self.playeBtn.hidden = YES;
|
||||
self.resolutionView.hidden = YES;
|
||||
self.backgroundColor = [UIColor clearColor];
|
||||
self.moreBtn.enabled = !self.disableMoreBtn;
|
||||
self.lockBtn.hidden = !self.isFullScreen;
|
||||
|
||||
self.danmakuBtn.enabled = YES;
|
||||
self.captureBtn.enabled = YES;
|
||||
self.backLiveBtn.hidden = YES;
|
||||
}
|
||||
|
||||
- (void)setPointArray:(NSArray *)pointArray
|
||||
{
|
||||
[super setPointArray:pointArray];
|
||||
|
||||
for (PlayerPoint *holder in self.videoSlider.pointArray) {
|
||||
[holder.holder removeFromSuperview];
|
||||
}
|
||||
[self.videoSlider.pointArray removeAllObjects];
|
||||
|
||||
for (SPVideoFrameDescription *p in pointArray) {
|
||||
PlayerPoint *point = [self.videoSlider addPoint:p.where];
|
||||
point.content = p.text;
|
||||
point.timeOffset = p.time;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
- (void)onPlayerPointSelected:(PlayerPoint *)point {
|
||||
NSString *text = [NSString stringWithFormat:@" %@ %@ ", [StrUtils timeFormat:point.timeOffset],
|
||||
point.content];
|
||||
|
||||
[self.pointJumpBtn setTitle:text forState:UIControlStateNormal];
|
||||
[self.pointJumpBtn sizeToFit];
|
||||
CGFloat x = self.videoSlider.mm_x + self.videoSlider.mm_w * point.where - self.pointJumpBtn.mm_h/2;
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
if (x + self.pointJumpBtn.mm_h/2 > ScreenWidth)
|
||||
x = ScreenWidth - self.pointJumpBtn.mm_h/2;
|
||||
self.pointJumpBtn.tag = [self.videoSlider.pointArray indexOfObject:point];
|
||||
self.pointJumpBtn.m_left(x).m_bottom(60);
|
||||
self.pointJumpBtn.hidden = NO;
|
||||
|
||||
[DataReport report:@"player_point" param:nil];
|
||||
}
|
||||
|
||||
- (void)setProgressTime:(NSInteger)currentTime
|
||||
totalTime:(NSInteger)totalTime
|
||||
progressValue:(CGFloat)progress
|
||||
playableValue:(CGFloat)playable {
|
||||
if (!self.isDragging) {
|
||||
// 更新slider
|
||||
self.videoSlider.value = progress;
|
||||
}
|
||||
// 更新当前播放时间
|
||||
self.currentTimeLabel.text = [StrUtils timeFormat:currentTime];
|
||||
// 更新总时间
|
||||
self.totalTimeLabel.text = [StrUtils timeFormat:totalTime];
|
||||
[self.videoSlider.progressView setProgress:playable animated:NO];
|
||||
}
|
||||
|
||||
- (void)resetWithResolutionNames:(NSArray<NSString *> *)resolutionNames
|
||||
currentResolutionIndex:(NSUInteger)currentResolutionIndex
|
||||
isLive:(BOOL)isLive
|
||||
isTimeShifting:(BOOL)isTimeShifting
|
||||
isPlaying:(BOOL)isPlaying
|
||||
{
|
||||
NSAssert(resolutionNames.count == 0 || currentResolutionIndex < resolutionNames.count,
|
||||
@"Invalid argument when reseeting %@", NSStringFromClass(self.class));
|
||||
|
||||
[self setPlayState:isPlaying];
|
||||
self.backLiveBtn.hidden = !isTimeShifting;
|
||||
self.moreContentView.enableSpeedAndMirrorControl = !isLive;
|
||||
|
||||
for (UIView *subview in self.resolutionView.subviews)
|
||||
[subview removeFromSuperview];
|
||||
|
||||
_resolutionArray = resolutionNames;
|
||||
if (_resolutionArray.count > 0) {
|
||||
[self.resolutionBtn setTitle:resolutionNames[currentResolutionIndex]
|
||||
forState:UIControlStateNormal];
|
||||
}
|
||||
UILabel *lable = [UILabel new];
|
||||
lable.text = @"清晰度";
|
||||
lable.textAlignment = NSTextAlignmentCenter;
|
||||
lable.textColor = [UIColor whiteColor];
|
||||
[self.resolutionView addSubview:lable];
|
||||
[lable mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.equalTo(self.resolutionView.mas_width);
|
||||
make.height.mas_equalTo(30);
|
||||
make.left.equalTo(self.resolutionView.mas_left);
|
||||
make.top.equalTo(self.resolutionView.mas_top).mas_offset(20);
|
||||
}];
|
||||
|
||||
// 分辨率View上边的Btn
|
||||
for (NSInteger i = 0 ; i < _resolutionArray.count; i++) {
|
||||
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[btn setTitle:_resolutionArray[i] forState:UIControlStateNormal];
|
||||
[btn setTitleColor:RGBA(252, 89, 81, 1) forState:UIControlStateSelected];
|
||||
[self.resolutionView addSubview:btn];
|
||||
[btn addTarget:self action:@selector(changeResolution:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[btn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.equalTo(self.resolutionView.mas_width);
|
||||
make.height.mas_equalTo(45);
|
||||
make.left.equalTo(self.resolutionView.mas_left);
|
||||
make.centerY.equalTo(self.resolutionView.mas_centerY).offset((i-self.resolutionArray.count/2.0+0.5)*45);
|
||||
}];
|
||||
btn.tag = MODEL_TAG_BEGIN+i;
|
||||
|
||||
if (i == currentResolutionIndex) {
|
||||
btn.selected = YES;
|
||||
btn.backgroundColor = RGBA(34, 30, 24, 1);
|
||||
self.resoultionCurrentBtn = btn;
|
||||
}
|
||||
}
|
||||
if (self.isLive != isLive) {
|
||||
self.isLive = isLive;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
// 时移的时候不能切清晰度
|
||||
self.resolutionBtn.userInteractionEnabled = !isTimeShifting;
|
||||
}
|
||||
|
||||
/** 播放按钮状态 */
|
||||
- (void)setPlayState:(BOOL)state {
|
||||
self.startBtn.selected = state;
|
||||
}
|
||||
|
||||
- (void)setTitle:(NSString *)title
|
||||
{
|
||||
[super setTitle:title];
|
||||
self.titleLabel.text = title;
|
||||
}
|
||||
|
||||
- (void)hideDanmu {
|
||||
[self setDisableDanmakuBtn:YES];
|
||||
}
|
||||
- (void)hideReplay {
|
||||
[self.repeatBtn setHidden:YES];
|
||||
}
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// SPWeiboControlView.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by annidyfeng on 2018/10/8.
|
||||
//
|
||||
|
||||
#import "SuperPlayerControlView.h"
|
||||
|
||||
@interface SPWeiboControlView : SuperPlayerControlView
|
||||
/** 分辨率的名称 */
|
||||
@property (nonatomic, strong) NSArray<NSString *> *resolutionArray;
|
||||
/** 开始播放按钮 */
|
||||
@property (nonatomic, strong) UIButton *startBtn;
|
||||
/** 当前播放时长label */
|
||||
@property (nonatomic, strong) UILabel *currentTimeLabel;
|
||||
/** 视频总时长label */
|
||||
@property (nonatomic, strong) UILabel *totalTimeLabel;
|
||||
/** 全屏按钮 */
|
||||
@property (nonatomic, strong) UIButton *fullScreenBtn;
|
||||
/** 滑杆 */
|
||||
@property (nonatomic, strong) PlayerSlider *videoSlider;
|
||||
|
||||
@property (nonatomic, strong) UIButton *moreBtn;
|
||||
|
||||
@property (nonatomic, strong) UIButton *backBtn;
|
||||
|
||||
@property (nonatomic, strong) UIButton *muteBtn;
|
||||
|
||||
@property (nonatomic, assign,getter=isFullScreen)BOOL fullScreen;
|
||||
|
||||
/** 切换分辨率按钮 */
|
||||
@property (nonatomic, strong) UIButton *resolutionBtn;
|
||||
@property (nonatomic, strong) UIButton *resoultionCurrentBtn;
|
||||
/** 分辨率的View */
|
||||
@property (nonatomic, strong) UIView *resolutionView;
|
||||
/** 更多设置View */
|
||||
@property (nonatomic, strong) SuperPlayerSettingsView *moreContentView;
|
||||
@property (nonatomic, strong) UIButton *pointJumpBtn;
|
||||
@end
|
||||
@@ -0,0 +1,487 @@
|
||||
//
|
||||
// SPWeiboControlView.m
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by annidyfeng on 2018/10/8.
|
||||
//
|
||||
|
||||
#import "SPWeiboControlView.h"
|
||||
#import <Masonry/Masonry.h>
|
||||
#import "UIView+Fade.h"
|
||||
#import "UIView+MMLayout.h"
|
||||
#import "StrUtils.h"
|
||||
#import "DataReport.h"
|
||||
#import "SuperPlayer.h"
|
||||
|
||||
@interface SPWeiboControlView() <PlayerSliderDelegate>
|
||||
@property BOOL isLive;
|
||||
@end
|
||||
|
||||
@implementation SPWeiboControlView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
|
||||
[self addSubview:self.startBtn];
|
||||
[self addSubview:self.currentTimeLabel];
|
||||
[self addSubview:self.totalTimeLabel];
|
||||
[self addSubview:self.videoSlider];
|
||||
[self addSubview:self.fullScreenBtn];
|
||||
[self addSubview:self.resolutionBtn];
|
||||
[self addSubview:self.muteBtn];
|
||||
[self addSubview:self.moreBtn];
|
||||
[self addSubview:self.backBtn];
|
||||
|
||||
// 添加子控件的约束
|
||||
[self makeSubViewsConstraints];
|
||||
[self resetControlView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)makeSubViewsConstraints {
|
||||
[self.startBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.center.equalTo(self);
|
||||
}];
|
||||
[self.currentTimeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.bottom.equalTo(self).offset(-8);
|
||||
make.left.mas_equalTo(@0);
|
||||
make.width.mas_equalTo(@60);
|
||||
}];
|
||||
[self.fullScreenBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerY.equalTo(self.currentTimeLabel);
|
||||
make.right.equalTo(self).offset(-12);
|
||||
}];
|
||||
[self.resolutionBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerY.equalTo(self.currentTimeLabel);
|
||||
make.right.equalTo(self.fullScreenBtn.mas_left);
|
||||
make.width.mas_equalTo(0);
|
||||
}];
|
||||
[self.totalTimeLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerY.equalTo(self.currentTimeLabel);
|
||||
make.right.equalTo(self.resolutionBtn.mas_left);
|
||||
make.width.mas_equalTo(@60);
|
||||
}];
|
||||
[self.videoSlider mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.centerY.equalTo(self.currentTimeLabel);
|
||||
make.left.equalTo(self.currentTimeLabel.mas_right);
|
||||
make.right.equalTo(self.totalTimeLabel.mas_left);
|
||||
}];
|
||||
|
||||
[self.backBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.leading.equalTo(self).offset(5);
|
||||
make.top.equalTo(self).offset(3);
|
||||
make.width.mas_equalTo(@60);
|
||||
}];
|
||||
|
||||
[self.moreBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.trailing.equalTo(self).offset(-10);
|
||||
make.centerY.equalTo(self.backBtn);
|
||||
make.width.mas_equalTo(@40);
|
||||
}];
|
||||
[self.muteBtn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.trailing.equalTo(self.moreBtn.mas_leading).offset(-10);
|
||||
make.centerY.equalTo(self.backBtn);
|
||||
make.width.mas_equalTo(@40);
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
- (UIButton *)startBtn {
|
||||
if (!_startBtn) {
|
||||
_startBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_startBtn setImage:SuperPlayerImage(@"wb_play") forState:UIControlStateNormal];
|
||||
[_startBtn setImage:SuperPlayerImage(@"wb_pause") forState:UIControlStateSelected];
|
||||
[_startBtn addTarget:self action:@selector(playBtnClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _startBtn;
|
||||
}
|
||||
|
||||
- (UILabel *)currentTimeLabel {
|
||||
if (!_currentTimeLabel) {
|
||||
_currentTimeLabel = [[UILabel alloc] init];
|
||||
_currentTimeLabel.textColor = [UIColor whiteColor];
|
||||
_currentTimeLabel.font = [UIFont systemFontOfSize:12.0f];
|
||||
_currentTimeLabel.textAlignment = NSTextAlignmentCenter;
|
||||
}
|
||||
return _currentTimeLabel;
|
||||
}
|
||||
|
||||
- (UIButton *)resolutionBtn {
|
||||
if (!_resolutionBtn) {
|
||||
_resolutionBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
_resolutionBtn.titleLabel.font = [UIFont systemFontOfSize:12];
|
||||
_resolutionBtn.backgroundColor = [UIColor clearColor];
|
||||
[_resolutionBtn addTarget:self action:@selector(resolutionBtnClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _resolutionBtn;
|
||||
}
|
||||
|
||||
- (PlayerSlider *)videoSlider {
|
||||
if (!_videoSlider) {
|
||||
_videoSlider = [[PlayerSlider alloc] init];
|
||||
[_videoSlider setThumbImage:SuperPlayerImage(@"wb_thumb") forState:UIControlStateNormal];
|
||||
_videoSlider.minimumTrackTintColor = RGBA(223, 223, 223, 1);
|
||||
// slider开始滑动事件
|
||||
[_videoSlider addTarget:self action:@selector(progressSliderTouchBegan:) forControlEvents:UIControlEventTouchDown];
|
||||
// slider滑动中事件
|
||||
[_videoSlider addTarget:self action:@selector(progressSliderValueChanged:) forControlEvents:UIControlEventValueChanged];
|
||||
// slider结束滑动事件
|
||||
[_videoSlider addTarget:self action:@selector(progressSliderTouchEnded:) forControlEvents:UIControlEventTouchUpInside | UIControlEventTouchUpOutside|UIControlEventTouchCancel];
|
||||
_videoSlider.delegate = self;
|
||||
}
|
||||
return _videoSlider;
|
||||
}
|
||||
|
||||
- (UILabel *)totalTimeLabel {
|
||||
if (!_totalTimeLabel) {
|
||||
_totalTimeLabel = [[UILabel alloc] init];
|
||||
_totalTimeLabel.textColor = [UIColor whiteColor];
|
||||
_totalTimeLabel.font = [UIFont systemFontOfSize:12.0f];
|
||||
_totalTimeLabel.textAlignment = NSTextAlignmentCenter;
|
||||
}
|
||||
return _totalTimeLabel;
|
||||
}
|
||||
|
||||
- (UIButton *)fullScreenBtn {
|
||||
if (!_fullScreenBtn) {
|
||||
_fullScreenBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_fullScreenBtn setImage:SuperPlayerImage(@"wb_fullscreen") forState:UIControlStateNormal];
|
||||
[_fullScreenBtn setImage:SuperPlayerImage(@"wb_fullscreen_back") forState:UIControlStateSelected];
|
||||
[_fullScreenBtn addTarget:self action:@selector(fullScreenBtnClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _fullScreenBtn;
|
||||
}
|
||||
|
||||
- (UIButton *)backBtn {
|
||||
if (!_backBtn) {
|
||||
_backBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_backBtn setImage:SuperPlayerImage(@"wb_back") forState:UIControlStateNormal];
|
||||
[_backBtn addTarget:self action:@selector(fullScreenBtnClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _backBtn;
|
||||
}
|
||||
- (UIButton *)moreBtn {
|
||||
if (!_moreBtn) {
|
||||
_moreBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_moreBtn setImage:SuperPlayerImage(@"wb_more") forState:UIControlStateNormal];
|
||||
[_moreBtn addTarget:self action:@selector(moreBtnClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _moreBtn;
|
||||
}
|
||||
- (UIButton *)muteBtn {
|
||||
if (!_muteBtn) {
|
||||
_muteBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_muteBtn setImage:SuperPlayerImage(@"wb_volume_on") forState:UIControlStateNormal];
|
||||
[_muteBtn setImage:SuperPlayerImage(@"wb_volume_off") forState:UIControlStateSelected];
|
||||
[_muteBtn addTarget:self action:@selector(muteBtnClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
}
|
||||
return _muteBtn;
|
||||
}
|
||||
|
||||
- (UIView *)resolutionView {
|
||||
if (!_resolutionView) {
|
||||
// 添加分辨率按钮和分辨率下拉列表
|
||||
|
||||
_resolutionView = [[UIView alloc] initWithFrame:CGRectZero];
|
||||
_resolutionView.hidden = YES;
|
||||
[self addSubview:_resolutionView];
|
||||
[_resolutionView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.mas_equalTo(330);
|
||||
make.height.mas_equalTo(self.mas_height);
|
||||
make.trailing.equalTo(self.mas_trailing).offset(0);
|
||||
make.top.equalTo(self.mas_top).offset(0);
|
||||
}];
|
||||
|
||||
_resolutionView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5];
|
||||
}
|
||||
return _resolutionView;
|
||||
}
|
||||
|
||||
- (SuperPlayerSettingsView *)moreContentView {
|
||||
if (!_moreContentView) {
|
||||
_moreContentView = [[SuperPlayerSettingsView alloc] initWithFrame:CGRectZero];
|
||||
_moreContentView.controlView = self;
|
||||
[self addSubview:_moreContentView];
|
||||
[_moreContentView mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.mas_equalTo(330);
|
||||
make.height.mas_equalTo(self.mas_height);
|
||||
make.trailing.equalTo(self.mas_trailing).offset(0);
|
||||
make.top.equalTo(self.mas_top).offset(0);
|
||||
}];
|
||||
_moreContentView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5];
|
||||
}
|
||||
return _moreContentView;
|
||||
}
|
||||
|
||||
- (void)playBtnClick:(UIButton *)sender {
|
||||
sender.selected = !sender.selected;
|
||||
if (sender.selected) {
|
||||
[self.delegate controlViewPlay:self];
|
||||
} else {
|
||||
[self.delegate controlViewPause:self];
|
||||
}
|
||||
[self cancelFadeOut];
|
||||
}
|
||||
|
||||
- (void)fullScreenBtnClick:(UIButton *)sender {
|
||||
sender.selected = !sender.selected;
|
||||
[self.delegate controlViewChangeScreen:self withFullScreen:sender.selected];
|
||||
}
|
||||
|
||||
- (void)progressSliderTouchBegan:(UISlider *)sender {
|
||||
self.isDragging = YES;
|
||||
self.startBtn.hidden = YES; // 播放按钮挡住了fastView
|
||||
[self cancelFadeOut];
|
||||
}
|
||||
|
||||
- (void)progressSliderValueChanged:(UISlider *)sender {
|
||||
if (self.maxPlayableRatio > 0 && sender.value * self.maxPlayableRatio) {
|
||||
sender.value = self.maxPlayableRatio;
|
||||
}
|
||||
[self.delegate controlViewPreview:self where:sender.value];
|
||||
}
|
||||
|
||||
- (void)progressSliderTouchEnded:(UISlider *)sender {
|
||||
[self.delegate controlViewSeek:self where:sender.value];
|
||||
self.isDragging = NO;
|
||||
self.startBtn.hidden = NO;
|
||||
[self cancelFadeOut];
|
||||
}
|
||||
|
||||
- (void)setProgressTime:(NSInteger)currentTime totalTime:(NSInteger)totalTime
|
||||
progressValue:(CGFloat)progress playableValue:(CGFloat)playable;
|
||||
{
|
||||
if (!self.isDragging) {
|
||||
// 更新slider
|
||||
self.videoSlider.value = progress;
|
||||
// 更新当前播放时间
|
||||
self.currentTimeLabel.text = [StrUtils timeFormat:currentTime];
|
||||
}
|
||||
// 更新总时间
|
||||
self.totalTimeLabel.text = [StrUtils timeFormat:totalTime];
|
||||
[self.videoSlider.progressView setProgress:playable animated:NO];
|
||||
}
|
||||
|
||||
- (void)muteBtnClick:(UIButton *)sender
|
||||
{
|
||||
sender.selected = self.playerConfig.mute = !self.playerConfig.mute;
|
||||
[self.delegate controlViewConfigUpdate:self withReload:NO];
|
||||
[self fadeOut:3];
|
||||
}
|
||||
|
||||
|
||||
/** 重置ControlView */
|
||||
- (void)resetControlView {
|
||||
self.videoSlider.value = 0;
|
||||
self.videoSlider.progressView.progress = 0;
|
||||
self.currentTimeLabel.text = @"00:00";
|
||||
self.totalTimeLabel.text = @"00:00";
|
||||
self.moreContentView.hidden = YES;
|
||||
}
|
||||
|
||||
- (void)setHidden:(BOOL)hidden
|
||||
{
|
||||
[super setHidden:hidden];
|
||||
|
||||
for (UIView *view in self.subviews) {
|
||||
if (view != self.resolutionView && view != self.moreContentView) {
|
||||
if (!self.isFullScreen && (view == self.backBtn || view == self.moreBtn || view == self.muteBtn))
|
||||
view.hidden = YES;
|
||||
else
|
||||
view.hidden = NO;
|
||||
} else {
|
||||
view.hidden = YES;
|
||||
}
|
||||
}
|
||||
self.isShowSecondView = NO;
|
||||
self.pointJumpBtn.hidden = YES;
|
||||
}
|
||||
|
||||
/** 播放按钮状态 */
|
||||
- (void)setPlayState:(BOOL)isPlay {
|
||||
self.startBtn.selected = isPlay;
|
||||
}
|
||||
|
||||
- (void)resolutionBtnClick:(UIButton *)sender {
|
||||
for (UIView *view in self.subviews) {
|
||||
view.hidden = YES;
|
||||
}
|
||||
|
||||
// 显示分辨率View
|
||||
self.resolutionView.hidden = NO;
|
||||
[DataReport report:@"change_resolution" param:nil];
|
||||
|
||||
[self cancelFadeOut];
|
||||
self.isShowSecondView = YES;
|
||||
}
|
||||
|
||||
- (void)moreBtnClick:(UIButton *)sender {
|
||||
for (UIView *view in self.subviews) {
|
||||
view.hidden = YES;
|
||||
}
|
||||
|
||||
self.moreContentView.playerConfig = self.playerConfig;
|
||||
self.moreContentView.enableSpeedAndMirrorControl = !self.isLive;
|
||||
[self.moreContentView update];
|
||||
self.moreContentView.hidden = NO;
|
||||
|
||||
[self cancelFadeOut];
|
||||
self.isShowSecondView = YES;
|
||||
}
|
||||
|
||||
- (void)resetWithResolutionNames:(NSArray<NSString *> *)resolutionNames
|
||||
currentResolutionIndex:(NSUInteger)currentResolutionIndex
|
||||
isLive:(BOOL)isLive
|
||||
isTimeShifting:(BOOL)isTimeShifting
|
||||
isPlaying:(BOOL)isPlaying
|
||||
{
|
||||
[self setPlayState:isPlaying];
|
||||
|
||||
_resolutionArray = resolutionNames;
|
||||
NSAssert(currentResolutionIndex < resolutionNames.count,
|
||||
@"Invalid argument when reseeting %@", NSStringFromClass(self.class));
|
||||
if (resolutionNames.count > 0) {
|
||||
[self.resolutionBtn setTitle:resolutionNames[currentResolutionIndex]
|
||||
forState:UIControlStateNormal];
|
||||
}
|
||||
for (UIView *subview in self.resolutionView.subviews)
|
||||
[subview removeFromSuperview];
|
||||
|
||||
UILabel *lable = [UILabel new];
|
||||
lable.text = @"清晰度";
|
||||
lable.textAlignment = NSTextAlignmentCenter;
|
||||
lable.textColor = [UIColor whiteColor];
|
||||
[self.resolutionView addSubview:lable];
|
||||
[lable mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.equalTo(self.resolutionView.mas_width);
|
||||
make.height.mas_equalTo(30);
|
||||
make.left.equalTo(self.resolutionView.mas_left);
|
||||
make.top.equalTo(self.resolutionView.mas_top).mas_offset(20);
|
||||
}];
|
||||
|
||||
// 分辨率View上边的Btn
|
||||
for (NSInteger i = 0 ; i < _resolutionArray.count; i++) {
|
||||
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[btn setTitle:_resolutionArray[i] forState:UIControlStateNormal];
|
||||
[btn setTitleColor:RGBA(252, 89, 81, 1) forState:UIControlStateSelected];
|
||||
[self.resolutionView addSubview:btn];
|
||||
[btn addTarget:self action:@selector(changeResolution:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[btn mas_makeConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.equalTo(self.resolutionView.mas_width);
|
||||
make.height.mas_equalTo(45);
|
||||
make.left.equalTo(self.resolutionView.mas_left);
|
||||
make.centerY.equalTo(self.resolutionView.mas_centerY).offset((i-self.resolutionArray.count/2.0+0.5)*45);
|
||||
}];
|
||||
|
||||
if (i == currentResolutionIndex) {
|
||||
btn.selected = YES;
|
||||
btn.backgroundColor = RGBA(34, 30, 24, 1);
|
||||
self.resoultionCurrentBtn = btn;
|
||||
}
|
||||
}
|
||||
if (self.isLive != isLive) {
|
||||
self.isLive = isLive;
|
||||
[self setNeedsLayout];
|
||||
}
|
||||
// 时移的时候不能切清晰度
|
||||
self.resolutionBtn.userInteractionEnabled = !isTimeShifting;
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击切换分别率按钮
|
||||
*/
|
||||
- (void)changeResolution:(UIButton *)sender {
|
||||
self.resoultionCurrentBtn.selected = NO;
|
||||
self.resoultionCurrentBtn.backgroundColor = [UIColor clearColor];
|
||||
self.resoultionCurrentBtn = sender;
|
||||
self.resoultionCurrentBtn.selected = YES;
|
||||
self.resoultionCurrentBtn.backgroundColor = RGBA(34, 30, 24, 1);
|
||||
|
||||
// topImageView上的按钮的文字
|
||||
[self.resolutionBtn setTitle:sender.titleLabel.text forState:UIControlStateNormal];
|
||||
[self.delegate controlViewSwitch:self withDefinition:sender.titleLabel.text];
|
||||
}
|
||||
|
||||
- (void)setOrientationLandscapeConstraint {
|
||||
self.fullScreen = YES;
|
||||
self.fullScreenBtn.selected = YES;
|
||||
self.moreBtn.hidden = NO;
|
||||
self.backBtn.hidden = NO;
|
||||
self.muteBtn.hidden = NO;
|
||||
[self.resolutionBtn mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.mas_equalTo(@60);
|
||||
}];
|
||||
|
||||
self.videoSlider.hiddenPoints = NO;
|
||||
}
|
||||
|
||||
- (void)setOrientationPortraitConstraint {
|
||||
self.fullScreen = NO;
|
||||
self.fullScreenBtn.selected = NO;
|
||||
self.moreBtn.hidden = YES;
|
||||
self.backBtn.hidden = YES;
|
||||
self.muteBtn.hidden = YES;
|
||||
[self.resolutionBtn mas_updateConstraints:^(MASConstraintMaker *make) {
|
||||
make.width.mas_equalTo(@0);
|
||||
}];
|
||||
|
||||
|
||||
self.videoSlider.hiddenPoints = YES;
|
||||
self.pointJumpBtn.hidden = YES;
|
||||
}
|
||||
|
||||
- (void)setPointArray:(NSArray *)pointArray
|
||||
{
|
||||
[super setPointArray:pointArray];
|
||||
|
||||
for (PlayerPoint *holder in self.videoSlider.pointArray) {
|
||||
[holder.holder removeFromSuperview];
|
||||
}
|
||||
[self.videoSlider.pointArray removeAllObjects];
|
||||
|
||||
for (SPVideoFrameDescription *p in pointArray) {
|
||||
PlayerPoint *point = [self.videoSlider addPoint:p.where];
|
||||
point.content = p.text;
|
||||
point.timeOffset = p.time;
|
||||
}
|
||||
}
|
||||
|
||||
- (UIButton *)pointJumpBtn {
|
||||
if (!_pointJumpBtn) {
|
||||
_pointJumpBtn = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
UIImage *image = SuperPlayerImage(@"copywright_bg");
|
||||
UIImage *resizableImage = [image resizableImageWithCapInsets:UIEdgeInsetsMake(0, 20, 0, 20) resizingMode:UIImageResizingModeStretch];
|
||||
[_pointJumpBtn setBackgroundImage:resizableImage forState:UIControlStateNormal];
|
||||
_pointJumpBtn.titleLabel.font = [UIFont systemFontOfSize:14];
|
||||
[_pointJumpBtn addTarget:self action:@selector(pointJumpClick:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[self addSubview:_pointJumpBtn];
|
||||
}
|
||||
return _pointJumpBtn;
|
||||
}
|
||||
|
||||
- (void)pointJumpClick:(UIButton *)sender {
|
||||
PlayerPoint *point = [self.videoSlider.pointArray objectAtIndex:self.pointJumpBtn.tag];
|
||||
[self.delegate controlViewSeek:self where:point.where];
|
||||
[self fadeOut:0.1];
|
||||
}
|
||||
|
||||
- (void)onPlayerPointSelected:(PlayerPoint *)point {
|
||||
NSString *text = [NSString stringWithFormat:@" %@ %@ ", [StrUtils timeFormat:point.timeOffset],
|
||||
point.content];
|
||||
|
||||
[self.pointJumpBtn setTitle:text forState:UIControlStateNormal];
|
||||
[self.pointJumpBtn sizeToFit];
|
||||
CGFloat x = self.videoSlider.mm_x + self.videoSlider.mm_w * point.where - self.pointJumpBtn.mm_w/2;
|
||||
if (x < 0)
|
||||
x = 0;
|
||||
if (x + self.pointJumpBtn.mm_w/2 > ScreenWidth)
|
||||
x = ScreenWidth - self.pointJumpBtn.mm_w/2;
|
||||
self.pointJumpBtn.tag = [self.videoSlider.pointArray indexOfObject:point];
|
||||
self.pointJumpBtn.m_left(x).m_bottom(60);
|
||||
self.pointJumpBtn.hidden = NO;
|
||||
|
||||
[DataReport report:@"player_point" param:nil];
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,12 @@
|
||||
//
|
||||
// SPWithoutControlView.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by annidyfeng on 2021/4/15.
|
||||
//
|
||||
|
||||
#import "SuperPlayerControlView.h"
|
||||
|
||||
@interface SPWithoutControlView : SuperPlayerControlView
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,39 @@
|
||||
#import "SuperPlayerControlView.h"
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <MediaPlayer/MediaPlayer.h>
|
||||
|
||||
#import "SuperPlayerSettingsView.h"
|
||||
#import "DataReport.h"
|
||||
#import "SuperPlayerFastView.h"
|
||||
#import "PlayerSlider.h"
|
||||
#import "UIView+MMLayout.h"
|
||||
#import "SuperPlayerView+Private.h"
|
||||
#import "StrUtils.h"
|
||||
#import "SPWithoutControlView.h"
|
||||
#import "UIView+Fade.h"
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored"-Wdeprecated-declarations"
|
||||
|
||||
#define MODEL_TAG_BEGIN 20
|
||||
#define BOTTOM_IMAGE_VIEW_HEIGHT 50
|
||||
|
||||
@interface SPWithoutControlView () <UIGestureRecognizerDelegate, PlayerSliderDelegate>
|
||||
@property BOOL isLive;
|
||||
@end
|
||||
|
||||
@implementation SPWithoutControlView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
if (self) {
|
||||
// skip
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
@end
|
||||