코드 상세 iOS 영상 생방송 탄막 기능

이 내용 은 절 차 를 통 해 iOS 영상 생방송 탄막 의 원리 와 코드 분석 을 상세 하 게 설명 하 였 으 며,다음은 모든 내용 입 니 다.
1.탄막 의 실현 성 분석
우선,시각 적 으로 현재 탄막 이 가지 고 있 는 기능 을 명 확 히 한다.
화면 오른쪽 에서 왼쪽으로 미끄러져 완전히 사라 질 때 까지
긴 탄막 이 든 짧 은 탄막 이 든 속도 가 일치 합 니 다.
탄막 궤도 가 있 는 것 은 무 작위 로 발생 하 는 탄막 이 아니다.
탄막 은 겹 치지 않 는 다.
다음은 무엇 을 해 야 할 지 기능 적 으로 생각 하 겠 습 니 다.
재 활용 메커니즘 은 table View 와 같은 재 활용 탱크 가 있 습 니 다.모든 탄막 은 cell 입 니 다.탄막 이 있 을 때 현재 재 활용 탱크 에 컨트롤 이 없 으 면 새로운 컨트롤 을 만 듭 니 다.재 활용 탱크 에 컨트롤 이 있 으 면 이 컨트롤 을 꺼 내 애니메이션 을 시작 합 니 다.애니메이션 이 끝 난 후에 이 컨트롤 을 다시 재 활용 탱크 로 돌아 갑 니 다.
속도 가 일치 해 야 한다 면 몇 가 지 를 고려 해 야 한다.먼저 다음 그림 에서 보 듯 이 빨간색 은 탄막 의 시작 위 치 를 대표 하고 파란색 은 탄막 의 종료 위 치 를 대표 하 며 길 이 는 그들의 실제 길 이 를 대표 한다.애니메이션 을 설정 할 때[UIView animation With Duration...]이 애니메이션 을 사용 합 니 다.duration 을 3s 로 설정 하면 스크린 1 의 속 도 는(스크린 너비+스크린 1 너비)/3 이 고,스크린 2 의 속 도 는(스크린 너비+스크린 2 너비)/3 입 니 다.스크린 2 의 길이 가 스크린 1 의 길이 보다 크기 때문에 스크린 2 의 속 도 는 스크린 1 의 속도 보다 큽 니 다.(탄막 길이 에 따라 속 도 를 조절 하 는 수요 에 있어 서 여 기 는 상대 적 으로 간단 하 다.속 도 를 전문 적 으로 계산 할 필요 가 없다.유일 하 게 번 거 로 운 것 은 속도 불일치 로 인 한 중첩 문 제 를 고려 해 야 한다)

2.준비 시작
수학 공식 에 정통 하 다 V=S/t (V 는 속 도 를 나타 내 고 S 는 거 리 를 나타 내 며 t 는 시간 을 나타 낸다)(*^ ^*) 
3.본 격 적 인 시작
BarrageView 라 는 이름 의 View 를 만 들 고 탄막 데 이 터 를 저장 하 는 대상 BarrageModel
다음은 Barrage Model.h 의 내용 으로 탄막 의 프로필 사진,닉네임,메시지 내용 을 저장 합 니 다.

@interface BarrageModel : NSObject
/**      */
@property(nonatomic,copy)NSString *userName;
/**      */
@property(nonatomic,copy)NSString *userMsg;
/**      */
@property(nonatomic,copy)NSString *userHeadImageUrl;
@end
다음은 BarrageView 내용 을 편집 하고 주석 은 가능 한 한 상세 하기 때문에 소 개 를 많이 하지 않 습 니 다.
파일

#import <UIKit/UIKit.h>
@class BarrageModel;
@interface BarrageView : UIView
/**
 *           View,    View              
 */
@property(nonatomic,retain) UIView *lastAnimateView;
/**
 *     
 *
 * @param msgModel     Model
 */
-(void)barrageSendMsg:(BarrageModel *)msgModel;
@end
파일

#import <UIKit/UIKit.h>
@class BarrageModel;
@interface BarrageView : UIView

/**
 * View, View
 */
@property(nonatomic,retain) UIView *lastAnimateView;
/**
 *
 *
 * @param msgModel Model
 */
-(void)barrageSendMsg:(BarrageModel *)msgModel;
@end
.m
#import "BarrageView.h"
#import "BarrageModel.h"
//
#define SCREEN_FRAME  [[UIScreen mainScreen] bounds]
//
#define SCREEN_HEIGHT CGRectGetHeight(SCREEN_FRAME)
//
#define SCREEN_WIDTH CGRectGetWidth(SCREEN_FRAME)

@interface BarrageView()
{
  CGFloat _minSpaceTime; /** */
}
/** */
@property (nonatomic,retain)NSMutableArray *dataArr;

/**   UI     */
@property (nonatomic,retain)NSMutableArray *resuingArr;
@end
@implementation BarrageView
- (instancetype)initWithFrame:(CGRect)frame
{
  self = [super initWithFrame:frame];
  if (self) {
    [self setInterface];
  }
  return self;
}
-(void)setInterface
{
  // ,
  self.dataArr = [NSMutableArray array];
  self.resuingArr = [NSMutableArray array];
  //
  UIView *view = [self createUI];
  [self.resuingArr addObject:view];
  //
  _minSpaceTime = 1;
  //
  [self checkStartAnimatiom];
}
-(void)checkStartAnimatiom
{
  //
  if (self.dataArr.count>0) {
    if (self.resuingArr.count>0) { // UI
     
      // , UI
      UIView *view = [self.resuingArr firstObject];
      [self.resuingArr removeObject:view];
      // UI
      [self startAnimationWithView:view];
     
    }else{ // UI
     
      // UI
      UIView *view = [self createUI];
      // UI
      [self startAnimationWithView:view];
    }
  }
  // , sleep()
  // , ,
  dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(_minSpaceTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    [self checkStartAnimatiom];
  });
}
-(void)startAnimationWithView:(UIView *)view
{
  //
  BarrageModel *barrageModel = [self.dataArr firstObject];
  //
  CGSize nameSize = [barrageModel.userName boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, 14) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:@{                                                                         } context:nil].size;
  //
  CGSize msgSize = [barrageModel.userMsg boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, 14) options:NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading attributes:@{                                                               NSFontAttributeName:[UIFont systemFontOfSize:14]
} context:nil].size;
  UIImageView *headImageView; //
  UILabel *userNameLabel;   //
  UILabel *userMsgLabel;   //
  // ,
  for (UIView *subView in view.subviews) {
    if (subView.tag == 1000) {
      headImageView = (UIImageView *)subView;
      headImageView.image = [UIImage imageNamed:@""];
     
    }else if (subView.tag == 1001){
      userNameLabel = (UILabel *)subView;
      userNameLabel.text = barrageModel.userName;
      // Label
      CGRect nameRect = userNameLabel.frame;
      nameRect.size.width = nameSize.width;
      userNameLabel.frame = nameRect;
    }else{
      userMsgLabel = (UILabel *)subView;
      userMsgLabel.text = barrageModel.userMsg;
      // Label
      CGRect msgRect = userMsgLabel.frame;
      msgRect.size.width = msgSize.width;
      userMsgLabel.frame = msgRect;
    }
  }
  // = + + ( , , , )
  view.frame = CGRectMake(SCREEN_WIDTH, 0, CGRectGetWidth(headImageView.frame) + 4 + (CGRectGetWidth(userNameLabel.frame)>CGRectGetWidth(userMsgLabel.frame)?CGRectGetWidth(userNameLabel.frame):CGRectGetWidth(userMsgLabel.frame)), CGRectGetHeight(self.frame));
  // , 。 V( ) = 100( )
  // S = + V = 100( )
  // V( ) = S( )/t( ) -------> t( ) = S( )/V( );
  CGFloat duration = (view.frame.size.width+SCREEN_WIDTH)/100;
  // : +
  _minSpaceTime = (view.frame.size.width + 30)/100;
  // view
  _lastAnimateView = view; 
  // UI
  [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
    //
    CGRect frame = view.frame;
    view.frame = CGRectMake(-frame.size.width, 0, frame.size.width, frame.size.height);
  } completion:^(BOOL finished) {
    //
    view.frame = CGRectMake(SCREEN_WIDTH, 0, 0, CGRectGetHeight(self.frame));
    //
    [self.resuingArr addObject:view];
  }]; 
  //
  [self.dataArr removeObject:barrageModel];
}
#pragma mark public method
-(void)barrageSendMsg:(BarrageModel *)msgModel{
  //
  [self.dataArr addObject:msgModel];
}
#pragma mark
-(UIView *)createUI
{
  UIView *view = [[UIView alloc] initWithFrame:CGRectMake(SCREEN_WIDTH, 0, 0, CGRectGetHeight(self.frame))];
  view.backgroundColor = [UIColor colorWithWhite:0 alpha:0.3];
  UIImageView *headImageView = [[UIImageView alloc] initWithFrame:CGRectMake(2, 2, CGRectGetHeight(self.frame)-4, CGRectGetHeight(self.frame)-4)];
  headImageView.layer.cornerRadius = headImageView.frame.size.width/2;
  headImageView.layer.masksToBounds = YES;
  headImageView.tag = 1000;
  headImageView.backgroundColor = [UIColor redColor];
  [view addSubview:headImageView];
  UILabel *userNameLabel = [[UILabel alloc] initWithFrame:CGRectMake(CGRectGetMaxX(headImageView.frame) + 2, 0, 0,14)];
  userNameLabel.font = [UIFont systemFontOfSize:14];
  userNameLabel.tag = 1001;
  [view addSubview:userNameLabel];
  UILabel *userMsgLabel = [[UILabel alloc] initWithFrame:CGRectMake(CGRectGetMaxX(headImageView.frame)+2, CGRectGetMaxY(userNameLabel.frame), 0, 14)];
  userMsgLabel.font = [UIFont systemFontOfSize:14];
  userMsgLabel.tag = 1002;
  [view addSubview:userMsgLabel];
  [self addSubview:view];
  return view;
}
마지막 으로 vc 에서.

#import "ViewController.h"
#import "BarrageView.h"
#import "BarrageModel.h"
//     
#define SCREEN_FRAME [[UIScreen mainScreen] bounds]
//     
#define SCREEN_HEIGHT CGRectGetHeight(SCREEN_FRAME)
//     
#define SCREEN_WIDTH CGRectGetWidth(SCREEN_FRAME)
@interface ViewController ()
/**         */
@property (nonatomic,retain)BarrageView *barrageViewOne;
/**         */
@property (nonatomic,retain)BarrageView *barrageViewTwo;
@end
@implementation ViewController
- (void)viewDidLoad {
 [super viewDidLoad];
 //         
 _barrageViewOne = [[BarrageView alloc]initWithFrame:CGRectMake(0,200, SCREEN_WIDTH, 34)];
 [self.view addSubview:_barrageViewOne];
 //         
 _barrageViewTwo = [[BarrageView alloc]initWithFrame:CGRectMake(0,300, SCREEN_WIDTH, 34)];
 [self.view addSubview:_barrageViewTwo];
}
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
 NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(sendMessage) userInfo:nil repeats:YES];
 [timer fire];
}
-(void)sendMessage
{
 BarrageModel *model = [[BarrageModel alloc]init];
 model.userName = @[@"  ",@"  ",@"  ",@"  ",@"  ",@"  ",@"  ",@"  ",@"  ",@"  ",@"  ",@"  "][arc4random()%12];
 model.userMsg = @[@"    ",@"  vsqe12qwe",@"        ",@"      ",@"12312",@"     ",@"     ",@"OK  ",@"     ",@"      ",@"    "][arc4random()%11];
 //          UI   
 CGFloat onePositon = _barrageViewOne.lastAnimateView.layer.presentationLayer.frame.size.width + _barrageViewOne.lastAnimateView.layer.presentationLayer.frame.origin.x;
 //          UI   
 CGFloat twoPositon = _barrageViewTwo.lastAnimateView.layer.presentationLayer.frame.size.width + _barrageViewTwo.lastAnimateView.layer.presentationLayer.frame.origin.x;
 if ( onePositon < twoPositon ) {
 [_barrageViewOne barrageSendMsg:model];
 }else{
 [_barrageViewTwo barrageSendMsg:model];
 }
}
@end
4.테스트 결론
한 시간의 타이머 테스트 를 통 해 메모리 가 증가 하지 않 았 다.

좋은 웹페이지 즐겨찾기