Dynamic支持CollectionView布局 、 MotionEffects特效 、 BlurImage效果 、 TextKit

1 使用UIDynamicAnimator对集合视图进行布局

1.1 问题

UIKit Dynamic动力模型一个非常有趣的用途就是影响集合视图的布局,可以给集合视图的布局添加各种动力行为,使其产生丰富多彩的效果,本案例使用UIDynamicAnimator对集合视图进行布局,实现一个弹性列表,如图-1所示:

图-1

1.2 方案

首先创建一个SingleViewApplication项目,给UIColor类创建一个分类UIColor+RandomColor,提供一个产生随机颜色的静态方法randomColor。

其次创建一个自定义布局类TRCollectionViewSpringCellLayout继承至UICollectionViewFlowLayout,该类有一个UIDynamicAnimator类型的属性animator。重写prepareLayout方法(该方法在布局开始前自动调用),在该方法中使用initWithCollectionViewLayout:创建animator对象,然后给每个items都添加UIAttachmentBehavior行为。

然后实现layoutAttributesForElementsInRect: 和 layoutAttributesForItemAtIndexPath: 这两个方法,程序运行的时候会通过调用它们来询问 collectionView每一个 item 的布局信息。

再实现shouldInvalidateLayoutForBoundsChange:,该方法会在集合视图的 bounds发生改变的时候被调用,根据最新的contentOffset 调整animator中behaviors 的参数,在重新调整之后该方法返回NO。

最后在TRViewController的viewDidLoad方法中使用TRCollectionViewSpringCellLayout对象创建集合视图collectionView,并且实现集合视图的协议方法给集合视图加载数据。

1.3 步骤

实现此案例需要按照如下步骤进行。

步骤一:创建UIColor分类

首先创建一个SingleViewApplication项目,给UIColor类创建一个分类UIColor+RandomColor,提供一个产生随机颜色的静态方法randomColor,代码如下所示:

 
  1. + (UIColor *)randomColor
  2. {
  3. CGFloat red = arc4random() % 256 / 256.0;
  4. CGFloat green = arc4random() % 256 / 256.0;
  5. CGFloat blue = arc4random() % 256 / 256.0;
  6. return [UIColor colorWithRed:red green:green blue:blue alpha:1.0];
  7. }

步骤二:创建自定义布局类TRCollectionViewSpringCellLayout

首先创建一个自定义布局类TRCollectionViewSpringCellLayout继承至UICollectionViewFlowLayout,该类有一个UIDynamicAnimator类型的属性animator,代码如下所示:

  1. @interface TRCollectionViewSpringCellLayout ()
  2. @property (strong, nonatomic) UIDynamicAnimator *animator;
  3. @end

其次重写prepareLayout方法(该方法在布局开始前自动调用),在该方法中使用initWithCollectionViewLayout:创建animator对象,然后给每个items都添加UIAttachmentBehavior行为,代码如下所示:

 
  1. //布局前的准备,布局开始前自动调用
  2. - (void)prepareLayout
  3. {
  4. if(!self.animator){
  5. //通过集合视图布局创建animator对象
  6. self.animator = [[UIDynamicAnimator alloc]initWithCollectionViewLayout:self];
  7. CGSize contentSize = self.collectionViewContentSize;
  8. //获取所有的items
  9. NSArray *items = [super layoutAttributesForElementsInRect:CGRectMake(0, 0, contentSize.width, contentSize.height)];
  10. //给每个一Cell创建UIAttachmentBehavior
  11. for (UICollectionViewLayoutAttributes *attributes in items) {
  12. UIAttachmentBehavior *spring = [[UIAttachmentBehavior alloc]initWithItem:attributes attachedToAnchor:attributes.center];
  13. spring.damping = 0.6;
  14. spring.frequency = 0.8;
  15. [self.animator addBehavior:spring];
  16. }
  17. }
  18. }

然后实现layoutAttributesForElementsInRect: 和 layoutAttributesForItemAtIndexPath: 这两个方法,程序运行的时候会通过调用它们来询问 collectionView每一个 item 的布局信息,代码如下所示:

 
  1. //在集合视图滚动时会自动调用,返回所有cell的属性,并传递可见的矩形区域
  2. - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
  3. {
  4. //当collectionView需要layout信息时由animator提供
  5. return [self.animator itemsInRect:rect];
  6. }
  7. - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
  8. {
  9. return [self.animator layoutAttributesForCellAtIndexPath:indexPath];
  10. }

最后实现shouldInvalidateLayoutForBoundsChange:,该方法会在集合视图的 bounds发生改变的时候被调用,根据最新的contentOffset 调整animator中behaviors 的参数,在重新调整之后该方法返回NO,代码如下所示:

 
  1. //当bounds发生变化时,调用方法,为不同的Cell改变不同的锚点
  2. - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
  3. {
  4. UIScrollView *scrollView = self.collectionView;
  5. //获取滚动的距离
  6. CGFloat scrollDelta = newBounds.origin.y - scrollView.bounds.origin.y;
  7. //手指所在的位置
  8. CGPoint touchLocation = [scrollView.panGestureRecognizer locationInView:scrollView];
  9. //计算和改动每一个Cell的锚点
  10. for (UIAttachmentBehavior *spring in self.animator.behaviors) {
  11. UICollectionViewLayoutAttributes *item = [spring.items firstObject];
  12. CGPoint center = item.center;
  13. CGPoint anchorPoint = spring.anchorPoint;
  14. CGFloat distance = fabsf(touchLocation.y - anchorPoint.y);
  15. CGFloat scrollResistance = distance / 600;
  16. center.y += (scrollDelta>0)?MIN(scrollDelta, scrollDelta * scrollResistance):MAX(scrollDelta, scrollDelta * scrollResistance);
  17. item.center = center;
  18. //当item处于动画中时,如果对象主动修改了位置信息,需要更新动画
  19. [self.animator updateItemUsingCurrentState:item];
  20. }
  21. return NO;
  22. }

步骤四:遵守委托协议,实现协议方法

首先在TRViewController的viewDidLoad方法中创建TRCollectionViewSpringCellLayout对象layout,并设置相关属性,代码如下所示:

 
  1. - (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4.     TRCollectionViewSpringCellLayout *layout = [[TRCollectionViewSpringCellLayout alloc]init];
  5. layout.itemSize = CGSizeMake(300, 40);
  6. layout.sectionInset = UIEdgeInsetsMake(0, 10, 0, 10);
  7. }

然后通过layout创建collectionView,并注册Cell,代码如下所示:

 
  1. static NSString *cellIdentifier = @"MyCell";
  2. - (void)viewDidLoad
  3. {
  4. [super viewDidLoad];
  5.     TRCollectionViewSpringCellLayout *layout = [[TRCollectionViewSpringCellLayout alloc]init];
  6. layout.itemSize = CGSizeMake(300, 40);
  7. layout.sectionInset = UIEdgeInsetsMake(0, 10, 0, 10);
  8. UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:self.view.frame collectionViewLayout:layout];
  9. collectionView.showsVerticalScrollIndicator = NO;
  10. collectionView.showsHorizontalScrollIndicator = NO;
  11. collectionView.dataSource = self;
  12. [collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:cellIdentifier];
  13. [self.view addSubview:collectionView];
  14. }

最后实现集合视图的协议方法给集合视图加载数据,代码如下所示:

 
  1. - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
  2. {
  3. return 50;
  4. }
  5. - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
  6. {
  7. UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
  8. cell.backgroundColor = [UIColor randomColor];
  9. return cell;
  10. }

1.4 完整代码

本案例中,TRViewController.m文件中的完整代码如下所示:

 
  1. #import "TRViewController.h"
  2. #import "TRCollectionViewSpringCellLayout.h"
  3. #import "UIColor+RandomColor.h"
  4. @implementation TRViewController
  5. static NSString *cellIdentifier = @"MyCell";
  6. - (void)viewDidLoad
  7. {
  8. [super viewDidLoad];
  9.     TRCollectionViewSpringCellLayout *layout = [[TRCollectionViewSpringCellLayout alloc]init];
  10. layout.itemSize = CGSizeMake(300, 40);
  11. layout.sectionInset = UIEdgeInsetsMake(0, 10, 0, 10);
  12. UICollectionView *collectionView = [[UICollectionView alloc]initWithFrame:self.view.frame collectionViewLayout:layout];
  13. collectionView.showsVerticalScrollIndicator = NO;
  14. collectionView.showsHorizontalScrollIndicator = NO;
  15. collectionView.dataSource = self;
  16. [collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:cellIdentifier];
  17. [self.view addSubview:collectionView];
  18. }
  19. - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
  20. {
  21. return 50;
  22. }
  23. - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
  24. {
  25. UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
  26. cell.backgroundColor = [UIColor randomColor];
  27. return cell;
  28. }
  29. @end
 

本案例中,TRCollectionViewSpringCellLayout.m文件中的完整代码如下所示:

 
  1. #import "TRCollectionViewSpringCellLayout.h"
  2. @interface TRCollectionViewSpringCellLayout ()
  3. @property (strong, nonatomic) UIDynamicAnimator *animator;
  4. @end
  5. @implementation TRCollectionViewSpringCellLayout
  6. //布局前的准备,布局开始前自动调用
  7. - (void)prepareLayout
  8. {
  9. //给每个一Cell创建UIAttachmentBehavior
  10. if(!self.animator){
  11. //通过集合视图布局创建animator对象
  12. self.animator = [[UIDynamicAnimator alloc]initWithCollectionViewLayout:self];
  13. CGSize contentSize = self.collectionViewContentSize;
  14. //获取所有的items
  15. NSArray *items = [super layoutAttributesForElementsInRect:CGRectMake(0, 0, contentSize.width, contentSize.height)];
  16. for (UICollectionViewLayoutAttributes *attributes in items) {
  17. UIAttachmentBehavior *spring = [[UIAttachmentBehavior alloc]initWithItem:attributes attachedToAnchor:attributes.center];
  18. spring.damping = 0.6;
  19. spring.frequency = 0.8;
  20. [self.animator addBehavior:spring];
  21. }
  22. }
  23. }
  24. //在集合视图滚动时会自动调用,返回所有cell的属性,并传递可见的矩形区域
  25. - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
  26. {
  27. //当collectionView需要layout信息时由animator提供
  28. return [self.animator itemsInRect:rect];
  29. }
  30. - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
  31. {
  32. return [self.animator layoutAttributesForCellAtIndexPath:indexPath];
  33. }
  34. //当bounds发生变化时,调用方法,为不同的Cell改变不同的锚点
  35. - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
  36. {
  37. UIScrollView *scrollView = self.collectionView;
  38. //获取滚动的距离
  39. CGFloat scrollDelta = newBounds.origin.y - scrollView.bounds.origin.y;
  40. //手指所在的位置
  41. CGPoint touchLocation = [scrollView.panGestureRecognizer locationInView:scrollView];
  42. //计算和改动每一个Cell的锚点
  43. for (UIAttachmentBehavior *spring in self.animator.behaviors) {
  44. UICollectionViewLayoutAttributes *item = [spring.items firstObject];
  45. CGPoint center = item.center;
  46. CGPoint anchorPoint = spring.anchorPoint;
  47. CGFloat distance = fabsf(touchLocation.y - anchorPoint.y);
  48. CGFloat scrollResistance = distance / 600;
  49. center.y += (scrollDelta>0)?MIN(scrollDelta, scrollDelta * scrollResistance):MAX(scrollDelta, scrollDelta * scrollResistance);
  50. item.center = center;
  51. //当item处于动画中时,如果对象主动修改了位置信息, 需要更新动画
  52. [self.animator updateItemUsingCurrentState:item];
  53. }
  54. return NO;
  55. }
  56. @end
 

本案例中,UIColor+RandomColor.h文件中的完整代码如下所示:

 
  1. #import <UIKit/UIKit.h>
  2. @interface UIColor (RandomColor)
  3. + (UIColor *)randomColor;
  4. @end
 

本案例中,UIColor+RandomColor.m文件中的完整代码如下所示:

 
  1. #import "UIColor+RandomColor.h"
  2. @implementation UIColor (RandomColor)
  3. + (UIColor *)randomColor
  4. {
  5. CGFloat red = arc4random() % 256 / 256.0;
  6. CGFloat green = arc4random() % 256 / 256.0;
  7. CGFloat blue = arc4random() % 256 / 256.0;
  8. return [UIColor colorWithRed:red green:green blue:blue alpha:1.0];
  9. }
  10. @end
 

2 给视图添加MotionEffect特效

2.1 问题

UIMotionEffect是iOS7中新增加一个类,它能帮助开发者为用户界面加上运动拟真效果,本案例使用UIMotionEffect给视图添加MotionEffect特效,如图-2所示:

图-2

2.2 方案

首先在Storyboard中搭建界面,在View中拖放一个ImageView控件作为backgroundView,在右边栏的检查器中设置好ImageView的显示图片。然后再拖放一个View控件覆盖在ImageView上面作为foregroundView,大小比ImageView略小,View控件里面是一个TextView控件,给TextView控件添加一些显示内容。

其次将ImageView控件和View关联成ViewController的属性backgroundView和foregroundView。

然后在viewDidLoad方法中给backgroundView和foregroundView添加MotionEffect效果。

最后需要在真机里面运行才能看到backgroundView和foregroundView根据设备的移动而产生偏移。

2.3 步骤

实现此案例需要按照如下步骤进行。

步骤一:搭建Storyboard界面

首先在Storyboard中搭建界面,在View中拖放一个和View同等大小的ImageView控件作为backgroundView,这里需要注意为了保证视图偏移的时候不会有空白,所以ImageView的大小要设置的比屏幕大,这里ImageView的frame设置为-100,-100,520,760。

然后在右边栏的检查器中设置好ImageView的显示图片。然后再拖放一个View控件覆盖在ImageView上面作为foregroundView,大小比ImageView略小,View控件里面是一个TextView控件,给TextView控件添加一些显示内容,Storyboard界面效果如图-3所示:

图-3

步骤二:创建添加MotionEffect效果

首先将ImageView控件和View关联成ViewController的属性backgroundView和foregroundView,代码如下所示:

 
  1. @interface ViewController ()
  2. @property (weak, nonatomic) IBOutlet UIImageView *backgroundView;
  3. @property (weak, nonatomic) IBOutlet UIView *foregroundView;
  4. @end

然后在viewDidLoad方法中给backgroundView和foregroundView添加MotionEffect效果,代码如下所示:

 
  1. - (void)viewDidLoad {
  2. [super viewDidLoad];
  3. self.foregroundView.layer.cornerRadius = 6.0f;
  4. self.foregroundView.layer.masksToBounds = YES;
  5. //给foregroundView添加MotionEffect
  6. UIInterpolatingMotionEffect *xAxis = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
  7. //设置x轴的最大和最小偏移值
  8. xAxis.minimumRelativeValue = @(-15.0);
  9. xAxis.maximumRelativeValue = @(15.0);
  10. UIInterpolatingMotionEffect *yAxis = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y" type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
  11. yAxis.minimumRelativeValue = @(-15.0);
  12. yAxis.maximumRelativeValue = @(15.0);
  13. //创建UIMotionEffectGroup对象
  14. UIMotionEffectGroup *foregroundMotionEffect = [[UIMotionEffectGroup alloc] init];
  15. foregroundMotionEffect.motionEffects = @[xAxis, yAxis];
  16. //添加MotionEffect
  17. [self.foregroundView addMotionEffect:foregroundMotionEffect];
  18. //给backgroundView添加MotionEffect
  19. UIInterpolatingMotionEffect *xAxis2 = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
  20. //设置y轴的最大和最小偏移值
  21. xAxis2.minimumRelativeValue = @(25.0);
  22. xAxis2.maximumRelativeValue = @(-25.0);
  23. UIInterpolatingMotionEffect *yAxis2 = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y" type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
  24. yAxis2.minimumRelativeValue = @(32.0);
  25. yAxis2.maximumRelativeValue = @(-32.0);
  26. UIMotionEffectGroup *backgroundMotionEffect = [[UIMotionEffectGroup alloc] init];
  27. backgroundMotionEffect.motionEffects = @[xAxis2, yAxis2];
  28. [self.backgroundView addMotionEffect:backgroundMotionEffect];
  29. }

步骤三:真机上运行程序

由于MotionEffect是根据设备的运动而产生的,所以需要在真机里面运行才能看到backgroundView和foregroundView根据设备的移动而产生偏移,真机上运行效果如图-4、图-5、图-6、图-7所示:

图-4

图-5

图-6

图-7

2.4 完整代码

本案例中,ViewController.m文件中的完整代码如下所示:

 
  1. #import "ViewController.h"
  2. @interface ViewController ()
  3. @property (weak, nonatomic) IBOutlet UIImageView *backgroundView;
  4. @property (weak, nonatomic) IBOutlet UIView *foregroundView;
  5. @end
  6. @implementation ViewController
  7. - (void)viewDidLoad {
  8. [super viewDidLoad];
  9. self.foregroundView.layer.cornerRadius = 6.0f;
  10. self.foregroundView.layer.masksToBounds = YES;
  11. //给foregroundView添加MotionEffect
  12. UIInterpolatingMotionEffect *xAxis = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
  13. //设置最大和最小偏移值
  14. xAxis.minimumRelativeValue = @(-15.0);
  15. xAxis.maximumRelativeValue = @(15.0);
  16. UIInterpolatingMotionEffect *yAxis = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y" type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
  17. yAxis.minimumRelativeValue = @(-15.0);
  18. yAxis.maximumRelativeValue = @(15.0);
  19. UIMotionEffectGroup *foregroundMotionEffect = [[UIMotionEffectGroup alloc] init];
  20. foregroundMotionEffect.motionEffects = @[xAxis, yAxis];
  21. [self.foregroundView addMotionEffect:foregroundMotionEffect];
  22. //给backgroundView添加MotionEffect
  23. UIInterpolatingMotionEffect *xAxis2 = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.x" type:UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
  24. xAxis2.minimumRelativeValue = @(25.0);
  25. xAxis2.maximumRelativeValue = @(-25.0);
  26. UIInterpolatingMotionEffect *yAxis2 = [[UIInterpolatingMotionEffect alloc] initWithKeyPath:@"center.y" type:UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
  27. yAxis2.minimumRelativeValue = @(32.0);
  28. yAxis2.maximumRelativeValue = @(-32.0);
  29. UIMotionEffectGroup *backgroundMotionEffect = [[UIMotionEffectGroup alloc] init];
  30. backgroundMotionEffect.motionEffects = @[xAxis2, yAxis2];
  31. [self.backgroundView addMotionEffect:backgroundMotionEffect];
  32. }
  33. @end
 

3 给图片添加模糊效果

3.1 问题

IOS7在视觉方面有许多改变,其中非常吸引人的功能之一就是在整个系统中巧妙的使用了模糊效果,本案例使用UIImage+ImageBlur分类给图片添加各种模糊效果,如图-8所示:

图-8

3.2 方案

首先在Storyboard中搭建界面,场景中拖放一个ImageView控件和五个Button控件,在右边栏设置好ImageView的显示图片,然后分别将Button的tag设置为0、1、2、3、4,别分代表不同的图片模糊效果。

其次将ImageView关联成ViewController的属性imageView,将五个Button关联同一个方法changeEffect:。

然后导入UIImage+ImageBlur文件,该分类提供的几种图片模糊效果的方法。

最后实现changeEffect:方法,该方法根据用户的选择,通过image的图片模糊方法实现不同的图片的模糊效果。

3.3 步骤

实现此案例需要按照如下步骤进行。

步骤一:搭建Stroyboard界面

首先在Storyboard中搭建界面,场景中拖放一个ImageView控件和五个Button控件,在右边栏设置好ImageView的显示图片,然后分别将Button的tag设置为0、1、2、3、4,别分代表不同的图片模糊效果,搭建好的界面如图-9所示:

图-9

然后将ImageView关联成ViewController的属性imageView,将五个Button关联同一个方法changeEffect:,代码如下所示:

 
  1. @interface ViewController ()
  2. @property (weak, nonatomic) IBOutlet UIImageView *imageView;
  3. @end

步骤二:实现图片模糊效果

首先导入UIImage+ImageBlur文件,该分类提供的几种图片模糊效果的方法。

然后实现changeEffect:方法,该方法根据用户的选择,通过image的图片模糊方法实现不同的图片的模糊效果,代码如下所示:

 
  1. - (IBAction)changeEffect:(UIButton *)sender {
  2. UIImage *effectImage;
  3. switch (sender.tag) {
  4. case 0:
  5. effectImage = [self.imageView.image applyLightEffect];
  6. break;
  7. case 1:
  8. effectImage = [self.imageView.image applyExtraLightEffect];
  9. break;
  10. case 2:
  11. effectImage = [self.imageView.image applyDarkEffect];
  12. break;
  13. case 3:
  14. effectImage = [self.imageView.image applyTintEffectWithColor:[UIColor lightGrayColor]];
  15. break;
  16. case 4:
  17. effectImage = [UIImage imageNamed:@"xiaoqingxin07.jpg"];
  18. break;
  19. }
  20. self.imageView.image = effectImage;
  21. }

运行程序可以看到LightEffect、ExtraLightEffect、DarkEffect、TintEffectWithColor等图片模糊效果分别如图-10、图-11、图-12及图-13所示:

图-10

图-11

图-12

图-13

3.4 完整代码

本案例中,ViewController.m文件中的完整代码如下所示:

 
  1. #import "ViewController.h"
  2. #import "UIImage+ImageEffects.h"
  3. @interface ViewController ()
  4. @property (weak, nonatomic) IBOutlet UIImageView *imageView;
  5. @end
  6. @implementation ViewController
  7. - (IBAction)changeEffect:(UIButton *)sender {
  8. UIImage *effectImage;
  9. switch (sender.tag) {
  10. case 0:
  11. effectImage = [self.imageView.image applyLightEffect];
  12. break;
  13. case 1:
  14. effectImage = [self.imageView.image applyExtraLightEffect];
  15. break;
  16. case 2:
  17. effectImage = [self.imageView.image applyDarkEffect];
  18. break;
  19. case 3:
  20. effectImage = [self.imageView.image applyTintEffectWithColor:[UIColor lightGrayColor]];
  21. break;
  22. case 4:
  23. effectImage = [UIImage imageNamed:@"xiaoqingxin07.jpg"];
  24. break;
  25. }
  26. self.imageView.image = effectImage;
  27. }
  28. @end
 

4 演示属性字符串的用法

4.1 问题

NSAtrributeString属性字符串是基于TextKit来构建的字符串对象,将字符串和样式信息组合在一起。本案例演示属性字符串的用法,如图-14所示:

图-14

4.2 方案

首先在viewDidLoad方法中创建一个NSDictionary类型的对象attributes,以键值对的方式管理字符串的样式信息。

其次创建一个NSAttributedString类型的字符串attrString,使用initWithString:attributes:方法进行初始化,string参数是字符串的内容,attributes参数就是上一步创建的attributes对象,即字符串的样式信息。

然后再创建一个NSMutableAttributedString类型的字符串mAttrString,与NSAttributedString类型不同的是NSMutableAttributedString类型是可变的属性字符串。

可以使用addAttribute:value:range:方法,或者addAttributes:range:方法给mAttrString添加样式,两个方法的区别就是前者只能添加一个键值对表示的样式,后者可以添加多个键值对表示的样式。

最后将mAttrString设置为self.label.attributedText属性,即可在界面看见带有属性样式的字符串。

4.3 步骤

实现此案例需要按照如下步骤进行。

步骤一:搭建Storyboard界面

首先Storyboard的场景中拖放一个Label控件,并将Label控件关联成TRViewController的属性label,代码如下所示:

 
  1. @interface TRViewController ()
  2. @property (weak, nonatomic) IBOutlet UILabel *label;
  3. @end

步骤二:创建属性字符串

首先在viewDidLoad方法中创建一个NSDictionary类型的对象attributes,以键值对的方式管理字符串的样式信息,NSForegroundColorAttributeName是key表示前景色即字符串的颜色,对应的value是一个UIColor类型的对象。NSFontAttributeName也是key表示字体名称,对应的value是一个UIFont类型的对象,代码如下所示:

 
  1. - (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4. NSDictionary *attributes = @{NSForegroundColorAttributeName : [UIColor redColor], NSFontAttributeName : [UIFont systemFontOfSize:26]};
  5. }

其次创建一个NSAttributedString类型的字符串attrString,使用initWithString:attributes:方法进行初始化,string参数是字符串的内容,attributes参数就是上一步创建的attributes对象,即字符串的样式信息,代码如下所示:

 
  1. - (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4. NSDictionary *attributes = @{NSForegroundColorAttributeName : [UIColor redColor], NSFontAttributeName : [UIFont systemFontOfSize:26]};
  5. NSAttributedString *attrString = [[NSAttributedString alloc]initWithString:@"Hello World." attributes:attributes];
  6. }

然后再创建一个NSMutableAttributedString类型的字符串mAttrString,与NSAttributedString类型不同的是NSMutableAttributedString类型是可变的属性字符串,代码如下所示:

 
  1. - (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4. NSDictionary *attributes = @{NSForegroundColorAttributeName : [UIColor redColor], NSFontAttributeName : [UIFont systemFontOfSize:26]};
  5. NSAttributedString *attrString = [[NSAttributedString alloc]initWithString:@"Hello World." attributes:attributes];
  6. NSMutableAttributedString *mAttrString = [attrString mutableCopy];
  7. }

再使用addAttribute:value:range:方法,或者addAttributes:range:方法给mAttrString添加样式,两个方法的区别就是前者只能添加一个键值对表示的样式,后者可以添加多个键值对表示的样式,代码如下所示:

 
  1. - (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4. NSDictionary *attributes = @{NSForegroundColorAttributeName : [UIColor redColor], NSFontAttributeName : [UIFont systemFontOfSize:26]};
  5. NSAttributedString *attrString = [[NSAttributedString alloc]initWithString:@"Hello World." attributes:attributes];
  6. NSMutableAttributedString *mAttrString = [attrString mutableCopy];
  7. [mAttrString addAttribute:NSFontAttributeName value:[UIFont italicSystemFontOfSize:35] range:NSMakeRange(3, 2)];
  8. [mAttrString addAttributes:@{NSBackgroundColorAttributeName : [UIColor lightGrayColor], NSTextEffectAttributeName : NSTextEffectLetterpressStyle} range:NSMakeRange(6, 3)];
  9. }

最后将mAttrString设置为self.label.attributedText属性,即可在界面看见带有属性样式的字符串,代码如下所示:

 
  1. - (void)viewDidLoad
  2. {
  3. [super viewDidLoad];
  4. NSDictionary *attributes = @{NSForegroundColorAttributeName : [UIColor redColor], NSFontAttributeName : [UIFont systemFontOfSize:26]};
  5. NSAttributedString *attrString = [[NSAttributedString alloc]initWithString:@"Hello World." attributes:attributes];
  6. NSMutableAttributedString *mAttrString = [attrString mutableCopy];
  7. [mAttrString addAttribute:NSFontAttributeName value:[UIFont italicSystemFontOfSize:35] range:NSMakeRange(3, 2)];
  8. [mAttrString addAttributes:@{NSBackgroundColorAttributeName : [UIColor lightGrayColor], NSTextEffectAttributeName : NSTextEffectLetterpressStyle} range:NSMakeRange(6, 3)];
  9.     self.label.attributedText = mAttrString;
  10. }

4.4 完整代码

本案例中,TRViewController.m文件中的完整代码如下所示:

 
  1. #import "TRViewController.h"
  2. @interface TRViewController ()
  3. @property (weak, nonatomic) IBOutlet UILabel *label;
  4. @end
  5. @implementation TRViewController
  6. - (void)viewDidLoad
  7. {
  8. [super viewDidLoad];
  9. NSDictionary *attributes = @{NSForegroundColorAttributeName : [UIColor redColor], NSFontAttributeName : [UIFont systemFontOfSize:26]};
  10. NSAttributedString *attrString = [[NSAttributedString alloc]initWithString:@"Hello World." attributes:attributes];
  11. NSMutableAttributedString *mAttrString = [attrString mutableCopy];
  12. [mAttrString addAttribute:NSFontAttributeName value:[UIFont italicSystemFontOfSize:35] range:NSMakeRange(3, 2)];
  13. [mAttrString addAttributes:@{NSBackgroundColorAttributeName : [UIColor lightGrayColor], NSTextEffectAttributeName : NSTextEffectLetterpressStyle} range:NSMakeRange(6, 3)];
  14.     self.label.attributedText = mAttrString;
  15. }
  16. @end
原文地址:https://www.cnblogs.com/52190112cn/p/5049488.html