Luban(鲁班)--图片压缩使用以及源码解析

Android图片压缩原理(二)—— 鲁班压缩算法解析 前面几篇文章,我们了解了一些关于。 阅读详情
AI摘要

本文详细介绍了Luban图片压缩库的工作原理及其在Android应用中的使用方法。通过对比压缩前后图片的质量和大小,展示了Luban的有效性和灵活性。同时,文章也深入剖析了Luban的源码实现,并指出了其在多图片压缩和支持方面的不足。

###1.Android图片显示遇到的问题
在Android应用中加载图片,是一个需要消耗内存的一个动作。也是Android开发者在项目优化中比较头疼的一个问题。

先了解下加载图片如何消耗内存的

图片质量1px所占空间(1byte=8位)1024*1024图片大小
ALPHA_8只有透明度,没有颜色,那么一个像素点占8位。1byte1M
RGB_565 即R=5,G=6,B=5,没有透明度,那么一个像素点占5+6+5=16位2byte2M
ARGB_8888由4个8位组成,即A=8,R=8,G=8,B=8,那么一个像素点占8+8+8+8=32位4byte4M
ARGB_4444由4个4位组成,即A=4,R=4,G=4,B=4,那么一个像素点占4+4+4+4=16位2byte2M



而Android系统分配给单个应用的内存空间还是很有限的大致有16M,64M,128M等。如果一个应用加载大量高质量的图片的话就会导致一种情况出现——OOM(内存溢出)。

所以为了避免这种情况出现,就要对图片进行压缩处理显示。

对图片压缩处理就是进行裁切以及压缩,但是为了保证处理后的图片尽量达到跟原图效果一致,对图片裁切,压缩的一个度是如何控制呢。

这里介绍下一个第三方开源库——Luabn(最接近微信朋友圈压缩图片算法)

2.使用Luban压缩图片效果

 

上面两图中的上部分图片是原图,下面部分是经过Luban压缩过后的图片

效果:

第一张原图4.55m 尺寸3456x4608。 压缩过后53k 尺寸1152x1536

第二张原图1.16m 尺寸1080x1920。 压缩过后150k 尺寸360x640

我们可以发现压缩后的图片在不放大的情况下,图片效果和原图一致,Luban的处理效果特别好。

如何使用Luban压缩图片

1.在项目中的build.gradle添加依赖(需要用到RxJava1.0)
这里写图片描述

2.在代码中使用Luban压缩方法

1)Listerner方式。传入图片File,调用设置压缩监听setCompressListerner方法,处理压缩结果。
这里写图片描述

2)Rxjava方式,传入图片File,调用asObservable方法返回一个Observable观察者对象,使用RxJava方式来处理压缩结果。
这里写图片描述

项目地址

3.Luban源码分析

源码中最主要的方法就是thirdCompress(File file),即如何计算得出理想的压缩后宽高,以及图片大小。

Luban压缩算法思路
  1. 判断图片比例值,是否处于以下区间内;
    • [1, 0.5625) 即图片处于 [1:1 ~ 9:16) 比例范围内
    • [0.5625, 0.5) 即图片处于 [9:16 ~ 1:2) 比例范围内
    • [0.5, 0) 即图片处于 [1:2 ~ 1:∞) 比例范围内
  2. 判断图片最长边是否过边界值;
    • [1, 0.5625) 边界值为:1664 * n(n=1), 4990 * n(n=2), 1280 * pow(2, n-1)(n≥3)
    • [0.5625, 0.5) 边界值为:1280 * pow(2, n-1)(n≥1)
    • [0.5, 0) 边界值为:1280 * pow(2, n-1)(n≥1)
  3. 计算压缩图片实际边长值,以第2步计算结果为准,超过某个边界值则:width / pow(2, n-1),height/pow(2, n-1)
  4. 计算压缩图片的实际文件大小,以第2、3步结果为准,图片比例越大则文件越大。
    size = (newW * newH) / (width * height) * m;
    • [1, 0.5625) 则 width & height 对应 1664,4990,1280 * n(n≥3),m 对应 150,300,300;
    • [0.5625, 0.5) 则 width = 1440,height = 2560, m = 200;
    • [0.5, 0) 则 width = 1280,height = 1280 / scale,m = 500;注:scale为比例值
  5. 判断第4步的size是否过小
    • [1, 0.5625) 则最小 size 对应 60,60,100
    • [0.5625, 0.5) 则最小 size 都为 100
    • [0.5, 0) 则最小 size 都为 100
  6. 将前面求到的值压缩图片 width, height, size 传入压缩流程,压缩图片直到满足以上数值
源码:

根据算法计算压缩后的宽高以及图片文件大小,在调用压缩方法compress,传入计算后的宽高以及图片大小

开始进行压缩,这里分别执行了压缩图片大小compress方法,以及压缩图片质量saveImage方法
这里写图片描述

压缩图片至预期大小,配置BitmapFactory.Options中inSampleSize的值来压缩图片的宽高

图片质量压缩
这里写图片描述

4.主要代码分析

清楚了第三档压缩的实现之后,再了解使用Luban压缩时用到几个方法:

get()、load(file)、putGear() 、setFileName()、setCompressListener()、launch()、asObservable()。

get(Context context)

这里写图片描述

这里写图片描述

首先调用的是get(this),传入的是一个Context对象,调用私有的构造方法传入一个File对象创建一个Luban对象;File对象生成调用的是getPhotoCacheDir方法,来指定缓存目录。

路径为:app包名/cache/luban_disk_cache/文件名

这里写图片描述

load(File file)
public Luban load(File file) {
    mFile = file;
    return this;
}

这个方法比较容易理解,传入的是我们图片文件。

putGear(int gear)
public Luban putGear(int gear) {
        this.gear = gear;
        return this;
}

设置压缩等级,源码中只有两种等级:FIRST_GEAR 和 THIRD_GEAR,传入其他值无效。

    private static final int FIRST_GEAR = 1;
    public static final int THIRD_GEAR = 3;
setFileName(String fileName)

设置压缩后的图片名称

    public Luban setFilename(String filename) {
        this.filename = filename;
        return this;
    }
setCompressListener(OnCompressListener listener)

设置压缩监听 OnCompressListener是一个接口,里面有三个方法,对应三种状态

public Luban setCompressListener(OnCompressListener listener) {
        compressListener = listener;
        return this;
}
public interface OnCompressListener {

    /**
     * Fired when the compression is started, override to handle in your own code
     * 压缩开始
     */
    void onStart();

    /**
     * Fired when a compression returns successfully, override to handle in your own code
     * 压缩成功
     */
    void onSuccess(File file);

    /**
     * Fired when a compression fails to complete, override to handle in your own code
     * 压缩失败
     */
    void onError(Throwable e);
}
lanuch()

开始压缩,方法中使用的RxJava,根据设置的压缩等级来压缩图片


asObservable()

使用这个方法的话,采用的Rxjava方式返回一个观察者Observable。

    public Observable<File> asObservable() {
        if (gear == FIRST_GEAR)//判断压缩等级 
            return Observable.just(mFile).map(new Func1<File, File>() {
                @Override
                public File call(File file) {
                    return firstCompress(file); //调用第一档压缩方法
                }
            });
        else if (gear == THIRD_GEAR)
            return Observable.just(mFile).map(new Func1<File, File>() {
                @Override
                public File call(File file) {
                    return thirdCompress(file);// 调用第三档压缩方法
                }
            });
        else return Observable.empty();
    }

Luban存在的不足

1.不能很好的支持多图片压缩。(出现问题:多图压缩出现OOM)

2.项目使用中必须添加RxJava依赖。(已在测试项目中剔除掉RxJava依赖 「链接」)



最后感谢作者 郑梓斌

Android进阶之路 - Luban 压缩图片 我记得在2017年写项目的时候图片压缩工具就是用的Luban,时隔多年后在近期的俩个项目中依旧发现了Luban的身影,所以觉得有必要好好记录一下老朋友想学习一款新技术最好的方式就是去看,因为除了会介绍基本的使用之外,如果你有兴趣的话也可以学一下源码;而我记录Blog更多的是我的一个学习、反思的过程,希望也可以帮到你。 阅读详情

相关推荐

鲁班Luban压缩图片(仿微信朋友圈压缩图片)

鲁班压缩图片Android Studio开发版,需要java1.8

可能是最详细的Android图片压缩原理分析(二)—— 鲁班压缩算法解析

第一步进行采样率压缩; 第二步进行宽高的等比例压缩(微信对原图和缩略图限制了最大长宽或者最小长宽); 第三步就是对图片的质量进行压缩(一般75或者70); 第四部就是采用webP的格式。 经过这四部的处理,基本上和微信朋友圈的效果一致,包括文件大小和显示效果 ...

weixin_44005563的博客 6486

Android图片压缩工具Luban(鲁班).zip

Luban(鲁班)——Android图片压缩工具,仿微信朋友圈压缩策略。项目描述目前做app开发总绕不开图片这个元素。但是随着手机拍照分辨率的提升,图片的压缩成为一个很重要的问题。单纯对图片进行裁切,压缩已经有很多文章介绍。但是裁切成多少,压缩成多少却很难控制好,裁切过头图片太小,质量压缩过头则显示效果太差。于是自然想到app巨头“微信”会是怎么处理,Luban(鲁班)就是通过在微信朋友圈发送近100张不同分辨率图片,对比原图与微信压缩后的图片逆向推算出来的压缩算法。因为有其他语言也想要实现 Luban,所以描述了一遍算法步骤 因为是逆向推算,效果还没法跟微信一模一样,但是已经很接近微信朋友圈压缩后的效果,具体看以下对比!效果与对比内容原图LubanWechat截屏 720P720*1280,390k720*1280,87k720*1280,56k截屏 1080P1080*1920,2.21M1080*1920,104k1080*1920,112k拍照 13M(4:3)3096*4128,3.12M1548*2064,141k1548*2064,147k拍照 9.6M(16:9)4128*2322,4.64M1032*581,97k1032*581,74k滚动截屏1080*6433,1.56M1080*6433,351k1080*6433,482k导入compile 'io.reactivex:rxandroid:1.2.1' compile 'io.reactivex:rxjava:1.1.6' compile 'top.zibin:Luban:1.0.5'使用Listener方式Luban内部采用io线程进行图片压缩,外部调用只需设置好结果监听即可Luban.get(this)     .load(File)                     //传人要压缩的图片     .putGear(Luban.THIRD_GEAR)      //设定压缩档次,默认三挡     .setCompressListener(new OnCompressListener() { //设置回调         @Override         public void onStart() {             //TODO 压缩开始前调用,可以在方法内启动 loading UI         }         @Override         public void onSuccess(File file) {             //TODO 压缩成功后调用,返回压缩后的图片文件         }         @Override         public void onError(Throwable e) {             //TODO 当压缩过去出现问题时调用         }     }).launch();    //启动压缩RxJava方式RxJava 调用方式请自行随意控制线程Luban.get(this)         .load(file)         .putGear(Luban.THIRD_GEAR)         .asObservable()         .subscribeOn(Schedulers.io())         .observeOn(AndroidSchedulers.mainThread())         .doOnError(new Action1() {             @Override             public void call(Throwable throwable) {                 throwable.printStackTrace();             }         })         .onErrorResumeNext(new Func1>() {             @Override             public Observable<? extends File> call(Throwable throwable) {                 return Observable.empty();             }         })         .subscribe(new Action1() {             @Override             public void call(File file) {                 //TODO 压缩成功后调用,返回压缩后的图片文件             }         }); 标签:Luban(鲁班)

Android开发中的图片压缩——luban压缩使用介绍和源码初步梳理(1)

问题背景 安卓日常开发和学习过程中,涉及图片压缩的场景很多,比如图片上传过程等。很多时候加载的图片过多不进行图片压缩的话也是很容易出现OOM内存溢出的,本文将对安卓开发的图片压缩操作以及鲁班压缩框架进行初步的介绍,以及对鲁班压缩的源码进行初步的梳理。 问题分析 首先,介绍下安卓开发中常见的几种压缩方式: 1.质量压缩 质量...

baorant24的博客 1792

Linux下科大讯飞离线语音识别SDK从下载到实战(附常见问题解决)

本文详细介绍了在Linux系统下,如何从科大讯飞开放平台获取离线语音识别SDK,完成环境准备、编译部署到实战开发的完整流程。文章重点解析了SDK目录结构、语法词典定制、示例代码修改,并针对开发中常见的“词典加载失败”、音频格式、交叉编译及性能优化等问题提供了深度解决方案,助力嵌入式与IoT开发者快速实现稳定可靠的离线命令识别功能。

honey的博客 1241

TCGA数据下载保姆级教程:用GDC-client从零搞定,附配置文件避坑指南

本文提供TCGA数据下载的完整教程,详细讲解如何使用GDC-client工具从零开始配置到高效获取基因组数据。涵盖环境准备、认证配置、数据检索、高效下载及故障处理等关键步骤,并附配置文件避坑指南,帮助生物医学研究者快速掌握TCGA数据下载技巧。

weixin_30892037的博客 262

Luban的使用和源码解析

###Luban的使用和源码解析: 目前做App开发总绕不开图片这个元素。但是随着手机拍照分辨率的提升,图片的压缩成为一个很重要的问题。单纯对图片进行裁切,压缩已经有很多文章介绍。但是裁切成多少,压缩成多少却很难控制好,裁切过头图片太小,质量压缩过头则显示效果太差. Luban(鲁班)就是通过在微信朋友圈发送近100张不同分辨率图片,对比原图与微信压缩后的图片逆向推算出来的压缩算法. 异步调用: ...

MyselfGang的博客 3037

WRF-CHEM 新手向实践(四):化学初始/边界场及namelist设置

这是这个系列的最后一节了,这些经验是自己作为一个半路出家的外行一步步摸索出来的,其中不免有很多理解不到位的地方,但也正是如此,我相信这是目前新手入门wrf-chem最友好的教程之一,希望能对大家有实质性的帮助。本节继续未完成的内容。在mozbc生成化学初始和边界条件之前,还需要先在wrfinput文件中开启化学部分。

qq_42335815的博客 4638

Luban—— Android图片压缩工具

Luban Android图片压缩工具

QG 2207

在VS2019里把JSBSim飞行模型集成到你的C++项目里(附完整配置流程和常见错误解决)

本文详细介绍了如何在Visual Studio 2019中将JSBSim飞行模型集成到C++项目中,包括环境准备、源码编译、项目配置和常见错误解决方案。通过实战技巧和优化建议,帮助开发者高效实现高精度飞行仿真功能,提升开发效率。

weixin_42620202的博客 413

海康威视iVMS-4200在银河麒麟系统部署全攻略与疑难排解

在信创国产化进程中,软件兼容性是关键挑战之一。以安防监控领域广泛使用的海康威视iVMS-4200客户端为例,其从Windows环境迁移到银河麒麟等国产操作系统时,面临架构适配、依赖库匹配等核心兼容性问题。这涉及到跨平台软件部署的通用原理:不同CPU架构(如ARM的飞腾、x86的兆芯)和操作系统底层API的差异,要求软件必须进行针对性编译和优化。解决这类问题的技术价值在于保障专业软件在国产化环境中的稳定运行,是信创产业落地的重要环节。具体到应用场景,如在基于银河麒麟V10的安防监控项目中,通过获取对应架构的.

weixin_33423874的博客 1456

最接近微信的图片压缩方案:10分钟上手Luban算法

你是否还在为App中的图片加载缓慢而烦恼?用户抱怨相册上传卡顿、流量消耗过大?Luban(鲁班)图片压缩工具或许能解决这些问题。作为一款接近微信朋友圈压缩效果的Android图片处理库,Luban通过智能算法将13M的拍照原图压缩至140k左右,同时保持视觉质量几乎无损。本文将带你从参数调优到可视化调试,全面掌握这一高效压缩方案。 ## 为什么选择Luban? Luban的核心优势在于其算法设...

gitblog_00907的博客 1211

6、探索音乐结构中的统一性:贝多芬《英雄交响曲》第一乐章的深度剖析

本文深入剖析了贝多芬《英雄交响曲》第一乐章的音乐结构,探讨其统一性的来源及表现形式。通过主题与动机、和声与调性、旋律与节奏、织体与动态等多方面的分析,揭示了这部作品在技术层面和情感表达上的卓越成就。

b9c0d的博客 518

告别繁琐配置:Luban Gradle插件实现图片压缩参数自动化

你是否还在为Android项目中的图片压缩参数配置而烦恼?手动调整压缩阈值、格式和尺寸比例不仅耗时,还难以保证效果一致性。本文将介绍如何通过Luban(鲁班)的Gradle插件实现图片压缩参数的自动化管理,让你彻底摆脱重复劳动,专注于业务开发。读完本文后,你将掌握: - Luban压缩算法的核心优势 - Gradle插件的自动化配置技巧 - 多场景下的参数优化方案 - 完整的集成与调试流程 #...

gitblog_00857的博客 489

作物生长模型Oryza V3实战2:下载、安装与使用

摘要:ORYZA 现在的应用范围已从单一水稻作物模拟扩展到多个水稻作物模拟。我在csdn站内也上传了“作物生长模型oryza v3大全(含所有参数模板和4个校准程序1个分析工具)”,可以说是全网最全的吧。网上搜索一般下载的v3只有一个a3主程序,不适合作全面与深入的研究,本版本从国外下载回来,一开始少了一个“SoilHydrau.exe”文件,说是有病毒被隔离了,后经历各种技术手段,并向国际水道研究所发送邮件,才得以补全所有的参数化及校准程序、分析工具,来之不易,有缘人得之。

503

AI编码规则:从提示工程到自动化,提升大模型生成代码质量

在软件工程领域,代码质量是保障软件可维护性、安全性和团队协作效率的核心。其背后遵循着从基础语法规范到架构设计原则的一系列工程实践。随着大语言模型(LLM)在代码生成任务中的广泛应用,如何确保AI生成的代码符合这些工程标准,成为一个关键的技术挑战。这涉及到将人类工程师积累的最佳实践,转化为机器可理解、可执行的明确约束。通过系统化的**编码规则**定义与集成,例如构建涵盖安全、风格、架构的多层次规则集,并将其融入**提示工程**或自动化工作流,可以显著引导AI产出更健壮、规范的代码。这种方法的价值在于,它能将模

weixin_42525189的博客 643

Luban

Luban前言一、Luban是什么?二、使用步骤1.引入库2.使用3.API三、算法作者地址 前言 自己写的bitmap压缩不够优秀,找了个优秀的图片压缩框架 一、Luban是什么? Luban(鲁班) —— Android图片压缩工具,仿微信朋友圈压缩策略。 二、使用步骤 1.引入库 implementation 'top.zibin:Luban:1.1.8' 2.使用 一张一张压缩 Observable.fromIterable(images ==

嗯... 2512

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

OpenCore Legacy Patcher 完整教程:让老款 Mac 免费用上最新 macOS

Apple 早已停止给老机型推送系统更新,可它们的硬件明明还能再战。OpenCore Legacy Patcher(OCLP)就是在引导阶段注入兼容补丁,让旧款 Intel Mac 装上新版 macOS 的免费工具。全程涉及格式化操作,**先把重要数据备份好**。 ## 原理速览:OCLP 如何绕过系统限制 OCLP 并不改动磁盘里的系统本体。开机时,OpenCore 引导加载器会提前把补丁载

gitblog_00232的博客 731

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

实测超越微信?Luban 1.1.8让图片压缩效率再突破

如果觉得这个压缩工具对你有帮助,记得点赞收藏关注三连!下期我们将带来Luban与其他压缩库的性能横评,敬请期待。

gitblog_00055的博客 1067

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

终极指南:Luban压缩算法如何实现微信朋友圈级别的图片优化

Luban(鲁班)是一款高效的图片压缩工具,其压缩效果非常接近微信朋友圈的图片压缩算法。本文将深入解析Luban的核心压缩技术,带您了解如何通过比例区间决策树实现高质量图片压缩,帮助开发者轻松集成到自己的项目中。 ## 📊 为什么选择Luban压缩算法? 在移动应用开发中,图片压缩是提升用户体验的关键环节。过大的图片会导致加载缓慢、流量消耗增加,而过低的压缩质量又会影响视觉效果。Luban压

gitblog_00996的博客 389

Luban 2(鲁班 2)Android 图片压缩库完全指南:微信朋友圈压缩策略的像素级还原与 Kotlin/TurboJPEG 深度优化

Luban 2(鲁班 2)是一款面向 Android 的高效图片压缩工具库,其核心思路是通过逆向推算微信朋友圈的压缩策略,在图片体积与显示画质之间找到最优平衡点。本文以 [README.md](https://link.gitcode.com/i/3f19b08b8d5dac5373b7c5c47b6d5e0f) 为主线,结合仓库中的算法实现、协程 API、TurboJPEG 原生层、单元测试与示

gitblog_00365的博客 253

实测!Luban同步异步压缩速度深度对比:谁才是移动端图片处理之王?

你还在为图片压缩太慢导致APP卡顿烦恼吗?还在纠结同步压缩阻塞UI线程还是异步压缩延迟高的问题吗?本文将通过实测对比Luban(鲁班)图片压缩算法的同步与异步模式性能差异,让你3分钟搞懂两种模式的适用场景,轻松解决移动端图片处理难题。 读完本文你将获得: - 同步/异步压缩的核心差异解析 - 3组真实设备性能测试数据对比 - 基于场景的最佳压缩模式选择指南 - 完整的代码集成示例与优化建议 #...

gitblog_00367的博客 478

彻底解决Luban图片压缩残留:Android应用卸载后缓存清理全方案

你是否遇到过这样的困扰:明明卸载了使用Luban(鲁班)图片压缩算法的Android应用,手机存储空间却没有明显释放?这很可能是因为Luban生成的压缩图片缓存文件没有被彻底清理。本文将从技术原理到实战操作,全面解决这一问题,让你的应用在用户卸载后不留痕迹。 读完本文你将获得: - 了解Luban缓存文件的存储机制 - 掌握3种彻底清理缓存的实现方案 - 学会在应用开发中预防缓存残留问题 - 获...

gitblog_00512的博客 489

告别无效压缩!Luban ignoreBy参数的黄金阈值设置指南

你是否遇到过这样的困境:使用Luban压缩图片时,小图被过度压缩导致模糊,大图却因未触发压缩而体积超标?作为最接近微信朋友圈压缩算法的图片处理库,Luban的ignoreBy参数正是解决这一矛盾的关键。本文将通过源码解析和场景测试,帮你找到不同业务场景下的最优阈值,让每张图片都获得恰到好处的压缩处理。 ## 参数原理:为什么100KB成为默认阈值? Luban的压缩触发机制由双重条件控制:文件...

gitblog_00276的博客 1006

Luban错误处理全解析:常见异常与解决方案

你是否遇到过图片压缩时的神秘崩溃?是否因压缩失败导致用户投诉?Luban(鲁班)作为接近微信朋友圈压缩效果的Android图片压缩库,在实际开发中仍会遇到各类异常。本文将系统梳理Luban的7类核心异常,提供12种解决方案及6个最佳实践,帮你构建健壮的图片压缩模块。 读完本文你将掌握: - 快速定位Luban压缩失败的根本原因 - 实现零崩溃的异常处理机制 - 优化压缩成功率的实战技巧 - 构建...

gitblog_00273的博客 529

Apache License 2.0完整指南:Luban开源协议使用规范详解

Apache License 2.0是目前最受欢迎的开源协议之一,Luban项目正是采用这一协议来保护开发者的权益。作为可能是最接近微信朋友圈的图片压缩算法,Luban在Apache 2.0协议下为用户提供了自由使用、修改和分发的权利。😊 ## 📋 Apache 2.0协议核心要点 Apache License 2.0协议为使用者提供了极大的自由度,同时确保了原作者的权益得到保护。 ##

gitblog_00740的博客 552
上一篇: RxJava 系列学习
下一篇: vlayout使用解析
疯狂小凯哥
博客等级 码龄10年 79粉丝 17原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值