>

让排版引擎支持对于图片的排版澳门博发娱乐官

- 编辑:澳门博发娱乐官网 -

让排版引擎支持对于图片的排版澳门博发娱乐官

</code></pre>

- (CAShapeLayer *)realWaveLayer{

import <UIKit/UIKit.h>

@interface UIView(LYExtension)

// 在分类中声明@property,只会生成方法的声明,不会生成方法的实现。

@property(nonatomic, assign)CGSize size;

@property(nonatomic, assign) CGFloat width;

@property(nonatomic, assign) CGFloat height;

@property(nonatomic, assign) CGFloat x;

@property(nonatomic, assign) CGFloat y;

@end
</pre></code>

<pre><code>

// UIView + LYExtension.m

// Created by YoungLee on //**

// Copyright (c) **** YoungLee.All rights reserved.

    "name" : "coretext-image-2.jpg"

IOS 类似于网易新闻首页新闻轮播的组件

、需求分析

 

 1、可横向循环滚动新闻图片

 

 2、滚动到对应图片时显示新闻标题 

 

 3、每张新闻图片可点击

 

 4、有pageControl提示

 

 5、具有控件的扩展能力

 

 

 

二、设计实现

 

 1、显示图片使用SDWebImage第三方库,可缓存图片、通过url异步加载图片

 

 2、使用一个横向滚动的UITableView实现循环滚动

 

 3、使用一个黑色半透明的背景、白色文字的UILabel显示标题

 

 4、定义每个新闻的数据结构:

 

   

 

/** @brief 默认使用本地地址,如果本地没有的话,使用网络图片 */

 

@interface PhotoNewsModel : NSObject

 

/** @brief 加载时展示的图片*/

@property (nonatomic, strong) UIImage *loadingImage;

 

/** @brief 图片本地的地址 */

@property (nonatomic, strong) NSString *localPath;

 

/** @brief 新闻图片的地址 */

@property (nonatomic, strong) NSString *photoUrl;

 

/** @brief 新闻标题 */

@property (nonatomic, strong) NSString *title;

 

 

@end

5、代理协议:

 

 

@protocol UIPhotoNewsViewDelegate <NSObject>

 

/**

 *  取得多少条图片新闻

 *

 *  @param photoNews 控件自身

 *

 *  @return 图片新闻的个数

 */

- (NSUInteger)photoNewsCount:(UIPhotoNewsView *)photoNews;

 

 

 

/**

 *  返回第几个图片新闻的model

 *

 *  @param photoNews 控件自身

 *  @param index

 *

 *  @return 返回描述图片新闻的model

 */

- (PhotoNewsModel *)photoNews:(UIPhotoNewsView *)photoNews

            photoModelAtIndex:(NSUInteger)index;

 

 

 

/**

 *  图片新闻点击的回调

 *

 *  @param photoNews 控件自身

 *  @param model     点击新闻对应的model

 */

- (void)photoNews:(UIPhotoNewsView *)photoNews

    photoDidClick:(PhotoNewsModel *)model;

 

 

 

 

@end

6、循环滚动如何实现

 

  a)将要展示的数据复制一份相当于 1、2、3、4|1、2、3、4

 

  b)数据初始化时,定位到第二份的1这里

 

  c)滚动到前面的1或者2时,设置跳转到第二份的1和2

 

  d)关键代码:

 

- (void)makeCycleScroll

{

    if(self.realCount >= 2)

    {

        CGFloat currentOffsetX = self.contentTableView.contentOffset.x;

        CGFloat currentOffSetY = self.contentTableView.contentOffset.y;

        CGFloat contentHeight  = self.contentTableView.contentSize.height;

         

        if (currentOffSetY < (contentHeight / 8.0)) {

            self.contentTableView.contentOffset = CGPointMake(currentOffsetX,(currentOffSetY + (contentHeight/2)));

        }

        if (currentOffSetY >= ((contentHeight * 6)/ 8.0)) {

            self.contentTableView.contentOffset = CGPointMake(currentOffsetX,(currentOffSetY - (contentHeight/2)));

        }

    }

}

类似于网易新闻首页新闻轮播的组件 、需求分析 1、可横向循环滚动新闻图片 2、滚动到对应图片时显示新闻标题 3、每张新闻图片可点...

/*!

if (!_waveSpeed) {
    _waveSpeed = 1.5;
}
return _waveSpeed;

<pre><code>
// UIView + LYExtension.h

    transform = CGAffineTransformScale(transform, 1.f, -1.f);

@property (nonatomic, assign) CGFloat offset;

import "UIView + LYExtenson.h"

  • (void)setSize:(CGSize)size {

    CGSize size = self.frame;

    frame.size = size;

    self.frame = frame;

}

  • (CGSize)size {

    return self.frame.size;

}

  • (void)setWidth:(CGFloat)width {

    CGRect frame = self.frame;

    frame.size.width = width;

    self.frame = frame;

}

  • (CGFloat)width {

    return self.frame.size.width;

}

  • (void)setHeight:(CGFloat)height {

    CGRect frame = self.frame;

    frame.size.height = height;

    self.frame = frame;

}

  • (CGFloat)height {

    return self.frame.size.height;

}

  • (void)setX:(CGFloat)x {

    CGRect frame = self.frame;

    frame.origin.x = x;

    self.frame = frame;

}

  • (CGFloat)x {

return self.frame.origin.x;

}

  • (void)setY:(CGFloat)y {

    CGRect frame = self.frame;

    frame.origin.y = y;

    self.frame = frame;

}

  • (CGFloat)y {

return self.frame.origin.y;

}

</pre></code>


如有不当、错误之处,欢迎指正!

static CGFloat descentCallback(void *ref){

相信很多人见过app个人中心的波浪动画效果吧,是不是觉得很酷?
接下来,我会给大家分享一个实现的思路。
先上图,看看效果。

// Copyright (c) **** YoungLee.All rights reserved.

            CTRunDelegateRef delegate = (__bridge CTRunDelegateRef)[runAttributes valueForKey:(id)kCTRunDelegateAttributeName];

/*!

}

// Created by YoungLee on //**

12345678910111213141516

/*!

@property (nonatomic, strong) CAShapeLayer *maskWaveLayer;//遮罩浪

                } else if ([type isEqualToString:@"img"]) {

废话不多说 直接上头文件 自己去Git下载吧 Git Link, press here to download

@property (nonatomic, strong) UIColor *realWaveColor;//实浪颜色

            for (NSDictionary *dict in array) {

if ([NSThread isMainThread]) {block();} else {dispatch_async(dispatch_get_main_queue;}

if (!_maskWaveColor) {
    _maskWaveColor = [[UIColor whiteColor]colorWithAlphaComponent:0.3];
}
return _maskWaveColor;

}

  • @brief Frame ParserConfig Attributes*/@interface XViewHandle : NSObject

- (CGFloat)waveSpeed {

+ (NSAttributedString *)parseImageDataFromNSDictionary:(NSDictionary *)dict

@interface XFrameParser : NSObject

@property (nonatomic, strong) CADisplayLink *timer;//刷屏器

    CFArrayRef lines = CTFrameGetLines(textFrame);

@end

@end
</pre></code>
<pre><code>
@interface ZSWave ()

        }

/*!

简单原理,CAShapeLayer 结合CGPath绘制图形。
动画操作的是CAShapeLayer(CALayer的子类)层,而非直接操作UIView。
CAShapeLayer在渲染速度,显示效果,内存占用,资源消耗上均有不小优势。对于CALayer和UIView的区别以及CAShapeLayer不是很了解的读者,可以阅读我在文章结尾附上的相关知识链接。

我们将上一节的content.json文件修改为如下内容,增加了 2 个type值为img的配置项。由于是图片的配置项,所以我们不需要设置颜色,字号这些图片不具有的属性,但是,我们另外增加了 3 个图片的配置属性:

  • (XCoreLinkData *)touchLinkInView: view atPoint: point data: (XCoreTextData *)data;

}

            CGPoint relativePoint = CGPointMake(point.x-CGRectGetMinX(rect),

/*!

<pre><code>

  }

  • (__class *)sharedInstance;

}

    CGFloat leading = 0.0f;

  • @brief 解析的内容 仅限文字内容的多样化
    • @param content 内容
  • @param config 配置 就是上边说的基本配置嘿嘿
    • @return 返回这个东西喽 一个TextData模型*/

@property (nonatomic, strong) CAShapeLayer *realWaveLayer;//真实浪

        // 翻转坐标系,因为 imageData 中的坐标是 CoreText 的坐标系

/*!

- (UIColor *)realWaveColor {

        // 获得每一行的 CGRect 信息

  • @brief 颜色的定义呦*/

@end

                if ([type isEqualToString:@"txt"]) {

  • x;

  • y;

  • width;

  • height;

  • setX: x;

  • setY: y;

  • setWidth: width;

  • setHeight: height;

jswave.gif

            CTRunRef run = (__bridge CTRunRef)runObj;

/*!

}

        CGRect rect = CGRectApplyAffineTransform(flippedRect, transform);

  • @brief 主线程呦*/

}

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556

// 这是链接的模型@property (strong, nonatomic) NSString * title;@property (strong, nonatomic) NSString * url;@property (assign, nonatomic) NSRange range;

[self.timer invalidate];
self.timer = nil;

            CGFloat xOffset = CTLineGetOffsetForStringIndex(line, CTRunGetStringRange(run).location, NULL);

先看一下JSON 格式<pre><code>[{"width": 200,"height": 100,"url": "": "img"},{"color": "blue","content": "this is first part and you can set your txt here. remember set default config","size": 30,"type": "txt"},{"color": "orange","content": "this is second part","size": 14,"type": "txt"},{"width": 100,"height": 200,"url": "": "img"},{"color": "red","content": "this is third part","size": 20,"type": "txt"},{"color": "blue","content": "press here to jump","size": 40,"url": "": "link"}]</code></pre>

- (void)initData{

澳门博发娱乐官网 1

/*!

澳门博发娱乐官网 2

    self = [super initWithCoder:aDecoder];

/*!

}

                          - imageRect.size.height;

// 包含的链接数组@property (strong, nonatomic) NSMutableArray * linkArray;

- (void)stopWaveAnimation;

    CGFloat width = (CGFloat)CTLineGetTypographicBounds(line, &ascent, &descent, &leading);

  • @brief Build CTFrameRef.*/@class XCoreTextData;

- (UIColor *)maskWaveColor {

                                                              config:config];

@end

- (CAShapeLayer *)maskWaveLayer{

    NSMutableArray *imageArray = [NSMutableArray array];

@end

核心代码

12345678910

@end

if (!_maskWaveLayer) {
    _maskWaveLayer = [CAShapeLayer layer];
    _maskWaveLayer.frame =  self.bounds;
    _maskWaveLayer.fillColor = self.maskWaveColor.CGColor;
}
return _maskWaveLayer;

[ {

/*!

if (!_waveHeight) {
    _waveHeight = 5;
}
return _waveHeight;

    "content" : " 内容、颜色、字体 ",

  • @brief 两个关于颜色的类方法 根据名称得到颜色 根据JSON得到颜色*/
if (!_speed) {
    _speed = 0.7;
}
return _speed;

            NSLog(@"bingo");

  • (UIColor *)colorWithRGBArray: (NSArray *)array;

</pre></code>
最后一定记得重写dealloc,把定时器注销。
<pre><code>

            CFIndex idx = CTLineGetStringIndexForPosition(line, relativePoint);

  • @brief imageDataModel*/@interface XCoreImageData : NSObject

}

            NSDictionary *runAttributes = (NSDictionary *)CTRunGetAttributes(run);

/*!

@property (nonatomic, assign) CGFloat speed;//浪速

            // 判断这个偏移是否在我们的链接列表中

  • @brief 其实绘制 就是要ctFrame*/@property (assign, nonatomic) CTFrameRef ctFrame;@property (assign, nonatomic) CGFloat height;
  • (void)wave{

    [self layoutIfNeeded];

    self.offset += self.speed;

    CGFloat width = CGRectGetWidth(self.frame); CGFloat height = CGRectGetHeight(self.frame);

    //真实浪 CGMutablePathRef path = CGPathCreateMutable(); CGPathMoveToPoint(path, NULL, 0, height ); CGFloat y = 0.f; for (CGFloat x = 0.f; x <= width ; x++) {

      y = height * sinf(0.01 * self.waveSpeed * x + self.offset * 0.045);
      CGPathAddLineToPoint(path, NULL, x, y);
    

    }

    CGFloat centX = self.center.x; CGFloat CentY = height sinf(0.01 self.waveSpeed centX + self.offset 0.045); CGRect iconFrame = [self.headerImageWallView frame]; iconFrame.origin.y = CentY - iconFrame.size.height; self.headerImageWallView.frame =iconFrame; //调整头像位置,随波浪运动 CGPathAddLineToPoint(path, NULL, width, height); CGPathAddLineToPoint(path, NULL, 0, height); CGPathCloseSubpath(path); self.realWaveLayer.path = path; self.realWaveLayer.fillColor = self.realWaveColor.CGColor; CGPathRelease(path); //遮罩浪 CGMutablePathRef maskpath = CGPathCreateMutable(); CGPathMoveToPoint(maskpath, NULL, 0, height); CGFloat maskY = 0.f; for (CGFloat x = 0.f; x <= width ; x++) {

      maskY = height * cosf(0.01 * self.waveSpeed * x + self.offset * 0.045);
      CGPathAddLineToPoint(maskpath, NULL, x, maskY);
    

    } CGPathAddLineToPoint(maskpath, NULL, width, height); CGPathAddLineToPoint(maskpath, NULL, 0, height); CGPathCloseSubpath(maskpath); self.maskWaveLayer.path = maskpath; self.maskWaveLayer.fillColor = self.maskWaveColor.CGColor; CGPathRelease(maskpath);

                continue;

XViewHandle * config = [[XViewHandle alloc] init];config.width = showView.width;NSString * path = [[NSBundle mainBundle] pathForResource:@"content" ofType:@"json"];XCoreTextData * data = [XFrameParser parseTemplateFile:path config:config];showView.data = data;showView.height = data.height;showView.backgroundColor = [UIColor whiteColor];[self.view addSubview:showView];

@property (nonatomic, assign) CGFloat waveHeight;//浪高

            runBounds.size.height = ascent + descent;

  • @brief Save CTFrameRef and Frame.*/@interface XCoreTextData : NSObject

}

@property (strong, nonatomic) NSString * title;

// JSON: [12, 22, 33]

if (!_headerImageWallView) {
    _headerImageWallView = [[UIView alloc]initWithFrame:CGRectMake(self.center.x - 30, -60, 60, 60)];
    _headerImageWallView.layer.borderColor = [UIColor whiteColor].CGColor;
    _headerImageWallView.layer.borderWidth = 2;
    _headerImageWallView.layer.cornerRadius = 20;
}
return _headerImageWallView;

            if (imgIndex == self.imageArray.count) {

/*!

- (CGFloat)speed {

123456789101112131415

  • (UIColor *)colorWithName: (NSString *)string;

@property (nonatomic, strong) UIColor *maskWaveColor;//遮罩浪颜色

    [self fillImagePosition];

  • @brief linkDataModel*/@interface XCoreLinkData : NSObject

}

    NSMutableAttributedString *result = [[NSMutableAttributedString alloc] init];

/*!

</pre></code>

                    linkData.title = dict[@"content"];

忽略掉这个晃眼的红色(毕竟只是用来做示例),这个波浪效果很带感吧。

        if (imageData == nil) {

  • @brief 解析AttributeString喽、
    • @param content 内容 就是一个AttributeString
  • @param config 配置
    • @return 返回TextData模型*/

- (void)startWaveAnimation{

                    // 创建 CoreTextLinkData

/*!

#pragma mark - lazy loading

    if (self.imageArray.count == 0) {

/*!

[self.layer addSublayer:self.realWaveLayer];
[self.layer addSublayer:self.maskWaveLayer];
[self addSubview:self.headerImageWallView];

[self startWaveAnimation];

    NSMutableAttributedString * space =

if (!_realWaveColor) {
    _realWaveColor = [UIColor whiteColor];
}
return _realWaveColor;

改造CTFrameParser的parseTemplateFile:(NSString *)path config:(CTFrameParserConfig*)config;方法,使其支持对type为img的节点解析。并且对type为img的节点,设置其CTRunDelegate信息,使其在绘制时,为图片预留相应的空白位置。

  • @brief 一些基本的配置属性 Model*/@property (assign, nonatomic) CGFloat width;@property (assign, nonatomic) CGFloat fontSize;@property (assign, nonatomic) CGFloat lineSpace;@property (strong, nonatomic) UIColor * textColor;
self.timer = [CADisplayLink displayLinkWithTarget:self selector:@selector(wave)];
[self.timer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];

    // 此处省略上一节中介绍的,对图片点击检测的逻辑

static NSMutableAttributedString * result;

- (void)stopWaveAnimation{

}

@end

- (CGFloat)waveHeight {

            if (![metaDic isKindOfClass:[NSDictionary class]]) {

  • @brief 这里是DebugLog 大家都很常用吧 所以不啰嗦了*/

@property (nonatomic, assign) CGFloat waveSpeed;//浪弯曲度

    CGPoint lineOrigins[lineCount];

注释很明确、 h文件中文注释 m文件英文注释、 懒得切输入法、 祝大家观影愉快。 - - - Dylan.

}

                              linkArray:(NSMutableArray *)linkArray {

X_SINGLETON_DEC(XViewHandle)

}

                    [result appendAttributedString:as];

然后看一下实现的头文件<pre><code>//// XViewHandle.h// XCoreText//// Created by Dylan on 15/1/17.// Copyright 2015年 Dylan. All rights reserved.//

- (void)startWaveAnimation;

    // 获得每一行的 origin 坐标

}

            CGRect colRect = CGPathGetBoundingBox(pathRef);

/*!

</pre></code>
<pre><code>

我们先为CTDisplayView类增加UITapGestureRecognizer:

// 这是image的模型呦、@property (strong, nonatomic) NSString * url;@property (assign, nonatomic) CGFloat position;@property (assign, nonatomic) CGRect imagePosition;

}
</pre></code>
参考资料CADisplayLink, CALayer和UIView的区别

        return;

@interface XTouch : NSObject

  • (void)dealloc{

    [self stopWaveAnimation];

                } else if ([type isEqualToString:@"img"]) {

  • (XCoreTextData *)parseContent: (NSString *)content config: (XViewHandle *)config;

看代码实现部分
<pre><code>
@interface ZSWave : UIView

        }

/*! JSON Format Example[{"color": "blue", // or you can change this with Array contains R G B"content": "With More Text", // content"size": 16 // font size"type": "txt" // type mains your content.},{"width": 12., // image size"height": 12.,"url": "image url", // image url"type": "img"},{"color": "blue", // link color"content": "Press Here", // link tip"url": "" // href"type": "link"}]*/</code></pre>

- (UIView *)headerImageWallView {

                                        options:NSJSONReadingAllowFragments

// 包含的图片数组@property (strong, nonatomic) NSMutableArray * imageArray;

@property (nonatomic, strong) UIView *headerImageWallView;//头像父视图

在 Demo 中,我们在最外层的 View Controller 中监听图片点击的通知,当收到通知后,进入到一个新的界面来显示图片点击内容。

@end

  • (instancetype)initWithFrame:(CGRect)frame
    {
    if ([super initWithFrame:frame]) {
    [self initData];
    }
    return self;
    }

    "name" : "coretext-image-1.jpg"

  • @brief 这个是最重要的方法 解析JSON文件
    • @param filePath JSON文件的路径 也可以自己去更改方法 改为JSON内容 都是可以的呦
  • @param config 这里的配置就用来配置一下width 别的属性的值 你当然写到JSON文档中了、 JSON格式可以参考下边的content.JSON 文件呦
    • @return 返回TextData这个玩意*/
if (!_realWaveLayer) {
    _realWaveLayer = [CAShapeLayer layer];
    _realWaveLayer.frame =  self.bounds;
    _realWaveLayer.fillColor = self.realWaveColor.CGColor;

}
return _realWaveLayer;

                imageData = nil;

然后看一下使用方法<pre><code>XDisplayView * showView = [[XDisplayView alloc] initWithFrame:CGRectMake(0, 64, CGRectGetWidth([UIScreen mainScreen].bounds), 100)];

</pre></code>
默认属性设置及初始化
<pre><code>
#pragma mark - Initialize parameter

    for (CoreTextLinkData *data in linkArray) {

  • @brief 关于UIView的一些扩展喽 很方便的 开发中也可以使用呦*/

        NSArray *array = [NSJSONSerialization JSONObjectWithData:data

  • @brief UIView ex*/@interface UIView (frameHandle)

                                  config:(CTFrameParserConfig*)config

  • (XCoreTextData *)parseAttributesContent: (NSMutableAttributedString *)content config: (XViewHandle *)config;

                    imageData.position = [result length];

  • (__class *)sharedInstance { static dispatch_once_t once; static __class * singleton; dispatch_once( &once, ^{ singleton = [[__class alloc] init]; } ); return singleton; }

            CGRect runBounds;

  • (XCoreTextData *)parseTemplateFile: (NSString *)filePath config: (XViewHandle *)config;

- (void)fillImagePosition {

@end

@property (assign, nonatomic) CTFrameRef ctFrame;

  • @brief 快速单例呦*/

}

Demo 工程的 Gif 效果图如下,读者可以将示例工程用git checkout image_support切换到当前章节状态,查看相关代码逻辑。

                    [result appendAttributedString:as];

/*!

  },

// 这是检测连接点击的方法 直接在tap手势的回掉方法里边 调用这个类方法就可以了。

    }

        imagePosition.y = self.bounds.size.height - imageRect.origin.y

本文由胜博发-编程发布,转载请注明来源:让排版引擎支持对于图片的排版澳门博发娱乐官