Android内存优化之封装九宫格
Android内存优化之封装九宫格
拉偶有所依 发表于3年前
Android内存优化之封装九宫格
  • 发表于 3年前
  • 阅读 408
  • 收藏 6
  • 点赞 0
  • 评论 1

移动开发云端新模式探索实践 >>>   

随着市场上越来越多的APP上线,好多软件对手机的内存要求也是很大,所以我们在开发的时候一定要掌握如何去优化内存,将自己的APP尽可能优化。今天我们就一起看一下九宫格的优化。下面是软件的截图

内存优化之封装九宫格

1、为了达到更好的效果我们不用UITableView,首先我们要通过XIB自定义一个图片和文字如图:

内存优化之封装九宫格

2、自定义主视图JRMainScrollView,通过协议代理来实现功能,做法和UITableView类似,大家可以参考一下UITableView

首先:我们要定义数据源协议

<span style="font-family:Arial;font-size:14px;">//数据源协议
@protocol JRMainScrollDataSource <NSObject>
//获取总的数量
- (NSInteger) numberOfItems;

//获取列的数量
- (NSInteger) numberOfColumsOfRow;
//获取item
- (UIView *) mainScrollView:(JRMainScrollView *)mainScrollView itemAtIndex:(NSInteger) index;
@end</span>

其次:我们要定义属性协议

<span style="font-family:Arial;font-size:14px;">//属性协议
@protocol JRMainScrollDelegate <NSObject>
@optional
//获取高度
- (CGFloat)  heightForItemAtView:(JRMainScrollView *) mainScrollView;

//获取宽度
- (CGFloat)  widthForItemAtView:(JRMainScrollView *) mainScrollView;

//获取间距
- (CGFloat) mainScrollView:(JRMainScrollView *)mainScrollView spaceForItemWithType:(kJRMainScrollItemSpace)type;
@end</span>

注意获取间距包括到左右的间距和上下的间距通过定义一个枚举实现

<span style="font-family:Arial;font-size:14px;">typedef enum{
    kJRMainScrollItemLeftSpace,
    kJRMainScrollItemTopSpace
} kJRMainScrollItemSpace;</span>

 

3、内部布局实现,计算出当前所有的frame,并且放入数组在此期间,用的的属性参数都需要从代理来获取,代码如下

<span style="font-family:Arial;font-size:14px;">//加载子视图
- (void)_loadSubViews{
    //获取总个数和列数
    NSInteger totalItems=[self.jrDataSource numberOfItems];
    NSInteger colum=[self.jrDataSource numberOfColumsOfRow];

    //获取宽度和高度
    CGFloat itemWidth=[self.jrDelegate widthForItemAtView:self];
    CGFloat itemHeigt=[self.jrDelegate heightForItemAtView:self];

    //获取上下间距
    CGFloat leftSpace=[self.jrDelegate mainScrollView:self spaceForItemWithType:kJRMainScrollItemLeftSpace];
    CGFloat topSpace=[self.jrDelegate mainScrollView:self spaceForItemWithType:kJRMainScrollItemTopSpace];

    CGFloat space=(kWidth-2*leftSpace-colum*itemWidth)/(colum-1)+itemWidth;

    for (int i=0;i<totalItems;i++) {
        int clo=i%colum;
        int row=i/colum;
        CGRect frame=CGRectMake(leftSpace+clo*space, 20+row*(itemHeigt+topSpace), itemWidth, itemHeigt);
        [self.array addObject:[NSValue valueWithCGRect:frame]];    
    }
self.contentSize=CGSizeMake(0, CGRectGetMaxY([[self.array lastObject] CGRectValue]));
    self.showsVerticalScrollIndicator=NO;

}</span>


4、判断当前的frame是不是在当前的屏幕可视范围之内,如果要是在的进行视图的渲染,如果不在不予理睬。


<span style="font-family:Arial;font-size:14px;">-(void)layoutSubviews{
    [super layoutSubviews];

    //循环便利获取在屏幕中的frame
    for (int i=0;i<self.array.count;i++) {

        UIView * tempView=(UIView *)self.current[@(i)];

        CGRect rect=[self.array[i] CGRectValue];
        if ([self isInScreenWith:rect]) {
            if(!tempView){//字典里没有的才需要重重新加载
                UIView *view=[self.jrDataSource mainScrollView:self itemAtIndex:i];
                view.frame=rect;
                [self.current setObject:view forKey:@(i)];
                [self addSubview:view];
            }

        }else if(tempView){//如果存在字典而且不在视线内部的则移除
            [self.current removeObjectForKey:@(i)];
            [tempView removeFromSuperview];
            [self.pool addObject:tempView];
        }  
    }

//判断是不是在视野内部,其中有两种情况,Y值在屏幕内部,或者MAXY值在屏幕内部
- (BOOL) isInScreenWith:(CGRect) frame{
    CGFloat setMiny=self.contentOffset.y;
    CGFloat setMaxy=self.contentOffset.y+kHeight;    
    BOOL condition1=frame.origin.y>=setMiny&&frame.origin.y<=setMaxy;
    BOOL condition2=CGRectGetMaxY(frame)>=setMiny&&CGRectGetMaxY(frame)<=setMaxy;

    if(condition1||condition2){
        return YES;
    }

    return NO;
        }</span>

 

5、操作缓冲池重复利用对象

<span style="font-family:Arial;font-size:14px;">/** 存放frame*/
@property(nonatomic,strong) NSMutableArray * array;
/** 存放当前显示的对象*/
@property(nonatomic,strong) NSMutableDictionary * current;
/** 存放缓冲池对象*/
@property(nonatomic,strong) NSMutableSet * pool;
/**
 *  获取重复利用的对象
 *
 *  @param identy <#identy description#>
 *
 *  @return <#return value description#>
 */
- (JRRectView *) dequeueReusedItemWithIdenty:(NSString *) identy{
    JRRectView * view=[self.pool anyObject];
    if (view!=nil) {
        [self.pool removeObject:view];
    }
    return view;
}</span>

6、在主控制器加载视图并实现代理方法即可

<span style="font-family:Arial;font-size:14px;"> //加载所有数据
- (void) _loadSubviews{

    //1 增加滚动视图
    JRMainScrollView * mainScroll=[[JRMainScrollView alloc] initWithFrame:self.view.bounds];
    mainScroll.jrDataSource=self;
    mainScroll.jrDelegate=self;
    [mainScroll reloadViews];
    [self.view addSubview:mainScroll];

}
#pragma mark - 数据源方法
-(NSInteger)numberOfItems{
    return 132;
}

-(NSInteger) numberOfColumsOfRow{
    return 3;
}

-(UIView *) mainScrollView:(JRMainScrollView *)mainScrollView itemAtIndex:(NSInteger)index{

    JRRectView *cell=[mainScrollView dequeueReusedItemWithIdenty:@"test"];
    if (cell==nil) {
        cell=[[[NSBundle mainBundle] loadNibNamed:@"rect" owner:nil options:nil] lastObject];
    }

    cell.titleLabel.text=[NSString stringWithFormat:@"下载"];
    NSString * imageName=[NSString stringWithFormat:@"%d",arc4random_uniform(20)+256];
    UIImage *image=[UIImage imageNamed:imageName];
    cell.image.image=image;

    return cell;
}

#pragma mark - 代理方法

//获取高度
- (CGFloat)  heightForItemAtView:(JRMainScrollView *) mainScrollView{
   return 100;
}

//获取宽度
- (CGFloat)  widthForItemAtView:(JRMainScrollView *) mainScrollView{
    return 90;
}

//获取间距
- (CGFloat) mainScrollView:(JRMainScrollView *)mainScrollView spaceForItemWithType:(kJRMainScrollItemSpace)type{

    if (type==kJRMainScrollItemLeftSpace) {
        return 20;
    }else if (type==kJRMainScrollItemTopSpace){
        return 20;
    }
    return 20;

}</span>


7、内存优化,除了上面6点,还要懂得源码的优化,一键清除Log(开发日志)信息,一键优化减少加密后原包大小


  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 26
博文 81
码字总数 138944
评论 (1)
郁林
安卓??!!
×
拉偶有所依
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: