项目中有个需求,需要以跑马灯的形势滚动展示用户的实时数据,跑马灯需要有用户头像,内容的长度不固定,并且可以点击,滚动效果还要足够流畅,本着不重复造轮子的心理,在网上各种搜索,发现都没法找到满足需求的demo,没办法,本来(ˇˍˇ) 想~偷个懒来着,现在只有自己动手造轮子了。

整体思路大概就是在scrollView中添加多个view,让这几个view依次排列在在scrollView中,动态计算scrollView的frame,让其宽度刚好是所有view的总宽度和,然后把scrollView的x初始值设置在屏幕以外,通过一个定时器,让scrollView每隔一段时间就移动一定的距离,这个时间可以微调,确保不会出现滚动的时候抖动的问题,当scrollView滚出可见区域了,再把scrollView的frame恢复到初始值即可

先看下效果图吧,由于博客园好像不支持gif图片上传,所有整了几张静态图,如果想要完整效果和代码的话,可以前往我的github https://github.com/qqcc1388/MarqueeViewDemo 查看demo源码和动态效果

我的这个demo中分为3个部分

  • HXQMarqueeView 用来显示跑马灯的显示区域,接受滚动的数据源,并且手动控制动画的开启。
  • HXQBoardView 跑马灯中每组数据的显示区域,这个视图的长度是根据传入文字的多少,动态计算的,如果文字或者头像被点击了,可以通过block将点击的model传递到上一层
  • HXQMarqueeModel 跑马灯数据model 主要参数是文字内容和头像参数(头像是网络图片),设置完文字后,在setTitle这个方法中会动态的把文字的总宽度计算一遍,并赋值为titleWith,width的宽度为文字+头像的总宽度

部分实现代码

//
//  HXQMarqueeView.m
//  hxquan
//
//  Created by Tiny on 2018/3/2.
//  Copyright © 2018年 Tiny. All rights reserved.
//#import "HXQMarqueeView.h"
#import "HXQMarqueeModel.h"
#import "HXQBoardView.h"
#import "UIView+Extionsiton.h"@interface HXQMarqueeView ()@property (nonatomic, strong) NSTimer *timer;
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) NSMutableArray *viewList;
@property (nonatomic, strong) NSArray *models;
@property (nonatomic, copy) void (^itelClick)(HXQMarqueeModel *);@end@implementation HXQMarqueeView-(void)dealloc{[self.timer  invalidate];self.timer = nil;
}-(NSMutableArray *)viewList{if (!_viewList) {_viewList = [NSMutableArray array];}return _viewList;
}-(NSTimer *)timer{if (!_timer) {_timer = [NSTimer timerWithTimeInterval:0.008f target:self selector:@selector(refreshProgress) userInfo:nil repeats:YES];[[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];}return _timer;
}-(instancetype)initWithFrame:(CGRect)frame{if (self = [super initWithFrame:frame]) {[self setupUI];}return self;
}-(void)setupUI{self.scrollView = [[UIScrollView alloc] initWithFrame:self.bounds];self.scrollView.scrollEnabled = NO;self.scrollView.showsVerticalScrollIndicator = NO;self.scrollView.showsHorizontalScrollIndicator = NO;[self addSubview:self.scrollView];
}-(void)setItems:(NSArray *)items{_models = items;//移除动画[self.scrollView.layer removeAllAnimations];//先移除之前的itemfor (UIView *v in self.scrollView.subviews) {if ([v isKindOfClass:[HXQBoardView class]]) {[v removeFromSuperview];}}[self.viewList removeAllObjects];//创建新的itemHXQBoardView *last = nil;CGFloat margin = 20;for (int i = 0; i < items.count; i++) {HXQMarqueeModel *model = items[i];HXQBoardView * lb = [[HXQBoardView alloc] initWithFrame:CGRectMake(last.frame.origin.x + last.bounds.size.width + margin, 0, model.width, 44) Model:model];__weak typeof(self) weakself = self;lb.boardItemClick = ^(HXQMarqueeModel *xModel) {if (weakself.itelClick) {weakself.itelClick(xModel);}};lb.tag = i;[self.scrollView addSubview:lb];[self.viewList addObject:lb];last = lb;}//设置scrollView的contentSizeself.scrollView.contentSize = CGSizeMake(last.frame.origin.x+last.bounds.size.width, 0);CGSize contetnsize = self.scrollView.contentSize;self.scrollView.frame = CGRectMake(self.bounds.size.width,0,contetnsize.width+self.bounds.size.width, 44);self.clipsToBounds = YES;
}-(void)refreshProgress{self.scrollView.x -=0.5 ;if (self.scrollView.x <= -self.scrollView.contentSize.width) {self.scrollView.x = self.bounds.size.width;}}- (void)startAnimation {if (!self.timer.isValid) {[self.timer fire];}
}-(void) stopAnimation{  //结束动画if (self.timer.isValid) {[self.timer invalidate];self.timer = nil;}
}#pragma mark - Private
-(void)addMarueeViewItemClickBlock:(void (^)(HXQMarqueeModel *))block{self.itelClick = block;
}

//demo使用起来也很简单 只需要3行代码即可(前提是数据源要准备好哦?)

    //创建跑马灯HXQMarqueeView *marqueeView = [[HXQMarqueeView alloc] initWithFrame:CGRectMake(0 100,self.view.bounds.size.width, 44)];[self.view addSubview:marqueeView];//初始化数据源[marqueeView setItems:modelList];//开始动画[marqueeView startAnimation];//如果需要监听点击回调,请实现这个方法[marqueeView addMarueeViewItemClickBlock:^(HXQMarqueeModel *model) {NSLog(@"%@",model.title);}];

swift版本(snapKit布局),更加简洁完善

//
//  HXQMarqueeView.swift
//  hxquan-swift
//
//  Created by Tiny on 2018/11/20.
//  Copyright © 2018年 hxq. All rights reserved.
//  跑马灯import UIKitclass MarqueeModel: Equatable{var title: String?  //内容var img: String?  //头像图片 urlvar textColor: UIColor = .black   //字体默认颜色var font: UIFont = .systemFont(ofSize: 14)  //字体大小var imageHolder: UIImage = HXQDefaultUserImage    //头像默认图片static func == (lhs: MarqueeModel, rhs: MarqueeModel) -> Bool {return  lhs.title == rhs.title &&lhs.img == rhs.img &&lhs.textColor == rhs.textColor &&lhs.font == rhs.font &&lhs.imageHolder == rhs.imageHolder}
}class MarqueeItem: UIView {private var textLb: UILabel!  //文字labelprivate var imgView: UIImageView!  //图片/// 重写setModel并赋值fileprivate var model: MarqueeModel?{didSet{if model != nil {textLb.text = model?.titletextLb.textColor = model!.textColortextLb.font = model!.fontimgView.sd_setImage(with: URL(string: model!.img ?? ""), placeholderImage: model!.imageHolder)}}}override init(frame: CGRect) {super.init(frame: frame)setupUI()}required init?(coder aDecoder: NSCoder) {super.init(coder: aDecoder)}private func setupUI(){let gesture = UITapGestureRecognizer(target: self, action: #selector(itemClick))addGestureRecognizer(gesture)textLb = UILabel()textLb.font = UIFont.systemFont(ofSize: 14)textLb.textColor = UIColor.blackaddSubview(textLb)imgView = UIImageView()imgView.layer.masksToBounds = trueaddSubview(imgView)imgView.snp.makeConstraints { (make) inmake.left.equalTo(5)make.top.equalTo(5)make.bottom.equalTo(-5)make.width.equalTo(imgView.snp.height)}textLb.snp.makeConstraints { (make) inmake.centerY.equalToSuperview()make.left.equalTo(imgView.snp.right).offset(5)make.right.equalTo(-5)}}/// item被点击事件回调fileprivate var itemDidTap:(() -> Void)?@objc private func itemClick(){//将事件传递出去itemDidTap?()}override func layoutSubviews() {super.layoutSubviews()imgView.layer.cornerRadius = imgView.bounds.size.width*0.5}
}class HXQMarqueeView: UIView {/// 初始化scrollViewprivate lazy var scrollView: UIScrollView = {let scrollView = UIScrollView(frame: .zero)scrollView.scrollsToTop = falsescrollView.showsVerticalScrollIndicator = falsescrollView.showsHorizontalScrollIndicator = falsereturn scrollView}()/// 初始化定时器private lazy var timer: Timer = {[unowned self] inlet timer = Timer(timeInterval: 0.008, target: self, selector: #selector(startToMove), userInfo: nil, repeats: true)RunLoop.current.add(timer, forMode: .common)return timer}()override init(frame: CGRect) {super.init(frame: frame)setupUI()}required init?(coder aDecoder: NSCoder) {super.init(coder: aDecoder)}private func setupUI(){layer.masksToBounds = trueaddSubview(scrollView)scrollView.snp.makeConstraints { (make) inmake.top.left.bottom.equalToSuperview()make.width.equalToSuperview()}}var marqueeHolder: String?var marqueeFontSize: CGFloat = 14var marqueeTextColor = UIColor.blackpublic var items = [MarqueeModel](){didSet{//判断2次数据是否相同if oldValue == items {return}//关闭定时器if timer.isValid {timer.fireDate = Date.distantFuture}//移除scrollView中所有控件for v in scrollView.subviews{v.removeFromSuperview()}//显示默认if items.isEmpty{//如果需要显示默认值的话if marqueeHolder != nil{let lb = UILabel()lb.textAlignment = .centerlb.text = marqueeHolderlb.font = UIFont.systemFont(ofSize: marqueeFontSize)lb.textColor = marqueeTextColorscrollView.addSubview(lb)lb.snp.makeConstraints { (make) inmake.height.equalToSuperview()make.left.equalTo(20)}//更新scrollView的ContentSizescrollView.snp.makeConstraints { (make) inmake.right.equalTo(lb.snp.right)}layoutIfNeeded()scrollView.x = 0;}}else{let margin: CGFloat = 10let gap: CGFloat = 20var last: MarqueeItem?for (i,model) in items.enumerated(){let item = MarqueeItem()item.model = modelitem.itemDidTap = { [unowned self] inself.selectionBlock?(model,i)}scrollView.addSubview(item)item.snp.makeConstraints { (make) inif last == nil{make.left.equalTo(margin)}else{make.left.equalTo(last!.snp.right).offset(gap)}make.height.equalToSuperview()}last = item}//更新scrollView的ContentSizescrollView.snp.makeConstraints { (make) inmake.right.equalTo(last!.snp.right).offset(margin)}layoutIfNeeded()//拿到contentSize重新更新scrollView约束scrollView.snp.remakeConstraints { (make) inmake.width.equalTo(scrollView.contentSize.width)make.top.bottom.equalToSuperview()make.right.equalTo(last!.snp.right).offset(margin)make.left.equalTo(self.snp.right)}//开始启动定时器if last != nil{timer.fireDate = Date(timeIntervalSinceNow: 0)}}}}private var selectionBlock: ((MarqueeModel,Int) -> Void)?public func queeSelection(_ callBack: ((MarqueeModel,Int) -> Void)?){selectionBlock = callBack}@objc private func startToMove(){scrollView.x = scrollView.x - 0.5 ;if scrollView.x <= -scrollView.contentSize.width {scrollView.x = self.bounds.size.width;}}deinit {if timer.isValid {timer.invalidate()}}
}/// swift版本跑马灯使用方法//创建let marquee = HXQMarqueeView()view.addSubview(marquee)//设置约束marquee.snp.makeConstraints { (make) inmake.left.equalTo(20)make.right.equalTo(-20)make.top.equalTo(100)make.height.equalTo(30)}//初始化数据源var array = [MarqueeModel]()for i in 0..<5 {let item = MarqueeModel()item.title = "我完事了,你们呢\(i)"item.img = ""item.textColor = COLOR_RANDOM()item.font = HFont(12)array.append(item)}//赋值marquee.items = array//监听点击marquee.queeSelection { (model, index) inprint("\(model.title ?? "") + \(index)")}

更多详情请参考demo: https://github.com/qqcc1388/MarqueeViewDemo

转载请标注来源:http://www.cnblogs.com/qqcc1388/p/8664280.html

转载于:https://www.cnblogs.com/qqcc1388/p/8664280.html

iOS 跑马灯带图片可点击相关推荐

  1. html垂直居中走马灯,史上最全解析:4种方法制作-PPT跑马灯/走马灯图片轮播动画...

    本期要点:全面解析不同场景下的跑马灯PPT图片动画 技巧概要:动画精准衔接 路径起点终点位置 插件提高效率 图文编辑:幻云PPT设计 大雄董军 比如我们今天要讲的跑马灯动画 跑马灯动画其实是根据咱们传 ...

  2. iOS 跑马灯封装(带点击事件)

    1.WAdvertScrollView.h #import <UIKit/UIKit.h> @class WAdvertScrollView; typedef enum : NSUInte ...

  3. C#跑马灯,图片滚动,后台获取图片地址。动态绑定图片,imag显示文字

    下面附下载地址. http://download.csdn.net/download/njxiaogui/10002058 1.跑马灯效果,图片连续循环滚动,图片下面并可附文字描述,图片是从数据库中获 ...

  4. 1、跑马灯之图片循环滚动

    最近,公司做了好几个项目,第一个项目首页跑马灯的效果是我们亲爱滴组长同学写的,后面跑马灯的需求改变了而组长同学又搞别的路去了,于是把我叫了过去,组长很亲切滴对我讲,I am very busy,  R ...

  5. iOS 跑马灯之 TXScrollLabelView

    前言 前段时间在开发一个广播的功能,网上也自己找了一些库,没有发现非常好用的,于是自己抽时间写了一个,在 Github 上发布一天收获六十多个 star,这里首先感谢大家在微博上的转发,使得 TXSc ...

  6. 只需一个DOM,纯CSS实现线性跑马灯特效

    只需一个DOM,纯CSS实现跑马灯线性特效 引言 跑马灯效果图&Demo 跑马灯代码 样式分析解释 引言 之前看到一个效果,一条小细线,围绕着边框一直绕圈,不过它的实现方式使用了JavaScr ...

  7. PHP怎么设置字体走马灯效果,html跑马灯/走马灯效果

    实现跑马灯的方法很多,其中最简单的是采用一句Html代码来实现,我们在需要出现跑马灯效果的地方插入"滚动的文字"语句,它的效果如下所示: 滚动的文字 适当的运用标签的参数,可以表现 ...

  8. 这是一个有关于点击按钮选图片然后有跑马灯的界面????

    任务要求实现一个图片选择器和一个很6的跑马灯 嗯,反正看到就一脸懵B了 图片选择器怪麻烦的,就先跑马灯(滚动字幕)吧=- = 效果图如下: 无奈机子很卡= = 嗯截图很费劲 那么就来讲一下怎么弄的吧= ...

  9. iOS 封装跑马灯和轮播效果

    代码地址如下: http://www.demodashi.com/demo/14075.html 功能概述和预览 功能描述:WSL_RollView 是基于UICollectionView实现的支持水 ...

  10. 原生JS实现图片跑马灯特效

    今天给大家分享一个用原生JS实现的图片跑马灯特效,效果如下: 实现的代码如下,欢迎大家复制粘贴. <!DOCTYPE html> <html><head><m ...

最新文章

  1. Can't get source for site-packages\torchvision\ops\poolers.py. TorchScript requires source access in
  2. C++成员变量的初始化顺序问题
  3. 《疯狂动物城》电脑壁纸
  4. 启明云端分享|ESP32摄像头应用方案常遇到的问题
  5. 学习underscore源码整体架构,打造属于自己的函数式编程类库
  6. Linux入门笔记——文件操作命令2
  7. 【数据库系统】文件处理系统的弊端
  8. 苹果手机提醒事项怎么设置农历生日提醒?
  9. Spring 处理请求和响应相关的注解
  10. python logging模块详解_python logging模块使用总结
  11. MSCRM 报表显示 rsprocessingaborted 错误
  12. java 正则表达式 img src_腰酸推荐Java-Jsoup爬取妹子图
  13. sata接口 图解 定义_SATA定义及接口
  14. 闪耀光栅 (DMD) 的衍射效应
  15. 量化研究 | 策略在指数与主连复权的差异化分析(最终篇)
  16. php监听input,js实时监听input中值变化
  17. 如何把浏览器中知乎文章导出成PDF
  18. python爬取微信制作照片墙
  19. Helm安装Harbor
  20. js字母大小写转换方法

热门文章

  1. FDTD PDMS光学参数txt文档
  2. c语言实型变量允许存放整型数,实型变量允许存放整形数吗
  3. 设置iSCSI的发起程序(客户端)(三)
  4. 富爸爸穷爸爸读书感言
  5. 计算机更改后怎么找不到桌面文件,电脑桌面的文件不见了怎么找回
  6. 案例|工业物联网解决方案•生产数据可视化
  7. mysql如何备份数据库_MySQL如何备份数据库
  8. 程序和算法之间,主要有什么关系?
  9. python open file失败_python open打开文件失败原因及解决办法
  10. 服务器上删掉的数据如何找回,在服务器数据丢失情况下如何恢复数据