Android底部导航栏的动态替换方案
android底部导航栏的动态替换方案,供大家参考,具体内容如下
1、通常来说,一般情况下,我们的app的bottomtab会有下面几种实现方式。
1)、自定义view,然后自己写逻辑去实现互斥。
2)、使用radiogroup+radiobutton去实现底部的tab。
*度比极高,如果想实现搞复杂度的话可以重写 radiobutton。
3)、使用google design包里面的 tablayout去实现。
可上、可下、可以滑动
偷懒的话可以根据已有api来设置一些资源,也可以 setcustomview()
4)、使用google design包里面的bottomnavigationview去实现。
(1)使用menu设置资源
(2)有默认的动画效果
2.本篇介绍的是日常见到的京东,淘宝类似的根据后台下发实现动态替换底部导航资源图片的方法(基于tablayout实现)
既然提到了动态替换肯定意味着要下载资源,所以先讲一下intentservice
- intentservice也是一个service,只不过google帮我们在里面封装并维护了一个handlerthread,里面的操作都是异步的。
- 当任务执行完后,intentservice 会自动停止,不需要我们去手动结束。
- 如果启动 intentservice 多次,那么每一个耗时操作会以工作队列的方式在 intentservice 的 onhandleintent 回调方法中执行,依次去执行,使用串行的方式,执行完自动结束。
onhandlerintent(intent intent) 是最重要的一个方法
@override protected void onhandleintent(intent intent) { if (intent != null) { final string action = intent.getaction(); if (action_foo.equals(action)) { // 在这里面处理耗时任务,当所有的耗时任务都结束以后,intentservice会自动的finish掉,不需要开发者关心。 } } }
选择intentservice的原因是因为下面的这几个操作都是耗时操作,所以我们干脆都封装到这service里面,我们只需要在合适的时机去启动这个service就ok了
- 需要下载资源压缩包
- 因为是动态替换,所以必然涉及到预下载,所以数据格式要先定好(下面是数据格式)。
{ "currentinfo":{//当前样式 "id":"111", "imagezipurl":你的下载地址, "tabnameslist":[ "首页1","附近1","发现1","我的1" ], "tabcolornormal":"b0c4de", "tabcolorhighlight":"f7b62d", "starttime":开始时间, "deadlinetime":结束时间 }, "nextinfo":{//下一次要展示的样式 "id":"111", "imagezipurl":你的下载地址, "tabnameslist":[ "首页2","附近2","发现2","我的2" ], "tabcolornormal":"b0c4de", "tabcolorhighlight":"fe6246", "starttime":开始时间, "deadlinetime":结束时间 } }
- 需要存放资源压缩包
下载和存放文件的代码(这里使用的是retrofit进行下载的)
// 下载文件 response<responsebody> zipfile = servicegenerator.createservice(homeservice.class) .downloadfileretrofit(getfiledownloadurl(hometabimageinfobean, type)) .execute(); // 得到文件流 responsebody zipbody = zipfile.body(); logutils.d("download", "下载完成"); // 创建一个文件 file zipdirectory = new file(filepathutil.gethuashenghometabzipdirectory(getapplicationcontext()) + createzipfilename(hometabimageinfobean, type)); // 如果文件不存在,则创建文件夹 if (!zipdirectory.exists()) { zipdirectory.createnewfile(); } // 保存文件 fileutils.writefile2disk(zipbody, zipdirectory);
- 解压资源并删除文件(解压方法由于过长所以写在了文中底部)
// 解压文件 并删除文件 if (ziputils.unzipfile(zipdirectory.getabsolutepath(), current.equals(type) ? filepathutil.gethuashenghometabimgcurrentdirectory(getapplicationcontext()) : filepathutil.gethuashenghometabimgnextdirectory(getapplicationcontext()))) { // 保存文件解压地址 savefiledirpath(hometabimageinfobean, type, current.equals(type) ? filepathutil.gethuashenghometabimgcurrentdirectory(getapplicationcontext()) : filepathutil.gethuashenghometabimgnextdirectory(getapplicationcontext())); logutils.d("hometabimagedownloadint", "解压完成---"); }
其实最关键的就是如何创建并获取我们的文件资源
重要的就是资源的两种状态切换(选中 or 不选中),通常我们都是使用drawable来写的
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@mipmap/home_tab_financing_selected" android:state_selected="true" /> <item android:drawable="@mipmap/home_tab_financing_normal" /> </selector>
现在我们要根据下载下来的图片(存放在sdcard中)去动态创建drawable这样我们便能里面系统控件的互斥特性
下面的三个方法代码很重要
// 构建drawable选择器 private statelistdrawable createdrawableselector(drawable checked, drawable unchecked) { statelistdrawable statelist = new statelistdrawable(); int state_selected = android.r.attr.state_selected; statelist.addstate(new int[]{state_selected}, checked); statelist.addstate(new int[]{-state_selected}, unchecked); return statelist; }
// 构建颜色选择器 private colorstatelist createcolorselector(int checkedcolor, int uncheckedcolor) { return new colorstatelist( new int[][]{new int[]{android.r.attr.state_selected}, new int[]{-android.r.attr.state_selected}}, new int[]{checkedcolor, uncheckedcolor});
// 将文件转换成drawable // pathname就是图片存放的绝对路径 private drawable getdrawablebyfile(string pathname) { return drawable.createfrompath(pathname); }
最后就是在tablayout的tab上设置资源
取出tablayout的所有的tab,遍历,然后根据特定条件去设置相应的drawable就可以了
最后在本文结尾附上上文的压缩相关工具类
import com.blankj.utilcode.util.closeutils; import com.blankj.utilcode.util.stringutils; import java.io.bufferedinputstream; import java.io.bufferedoutputstream; import java.io.file; import java.io.fileinputstream; import java.io.fileoutputstream; import java.io.ioexception; import java.io.inputstream; import java.io.outputstream; import java.util.arraylist; import java.util.collection; import java.util.enumeration; import java.util.list; import java.util.zip.zipentry; import java.util.zip.zipfile; import java.util.zip.zipoutputstream; /** * <pre> * author: 程龙 * time : 2018/12/14 * desc : 压缩相关工具类 * </pre> */ public final class ziputils { private static final int kb = 1024; private ziputils() { throw new unsupportedoperationexception("u can't instantiate me..."); } /** * 批量压缩文件 * * @param resfiles 待压缩文件集合 * @param zipfilepath 压缩文件路径 * @return {@code true}: 压缩成功<br>{@code false}: 压缩失败 * @throws ioexception io错误时抛出 */ public static boolean zipfiles(collection<file> resfiles, string zipfilepath) throws ioexception { return zipfiles(resfiles, zipfilepath, null); } /** * 批量压缩文件 * * @param resfiles 待压缩文件集合 * @param zipfilepath 压缩文件路径 * @param comment 压缩文件的注释 * @return {@code true}: 压缩成功<br>{@code false}: 压缩失败 * @throws ioexception io错误时抛出 */ public static boolean zipfiles(collection<file> resfiles, string zipfilepath, string comment) throws ioexception { return zipfiles(resfiles, fileutils.getfilebypath(zipfilepath), comment); } /** * 批量压缩文件 * * @param resfiles 待压缩文件集合 * @param zipfile 压缩文件 * @return {@code true}: 压缩成功<br>{@code false}: 压缩失败 * @throws ioexception io错误时抛出 */ public static boolean zipfiles(collection<file> resfiles, file zipfile) throws ioexception { return zipfiles(resfiles, zipfile, null); } /** * 批量压缩文件 * * @param resfiles 待压缩文件集合 * @param zipfile 压缩文件 * @param comment 压缩文件的注释 * @return {@code true}: 压缩成功<br>{@code false}: 压缩失败 * @throws ioexception io错误时抛出 */ public static boolean zipfiles(collection<file> resfiles, file zipfile, string comment) throws ioexception { if (resfiles == null || zipfile == null) return false; zipoutputstream zos = null; try { zos = new zipoutputstream(new fileoutputstream(zipfile)); for (file resfile : resfiles) { if (!zipfile(resfile, "", zos, comment)) return false; } return true; } finally { if (zos != null) { zos.finish(); closeutils.closeio(zos); } } } /** * 压缩文件 * * @param resfilepath 待压缩文件路径 * @param zipfilepath 压缩文件路径 * @return {@code true}: 压缩成功<br>{@code false}: 压缩失败 * @throws ioexception io错误时抛出 */ public static boolean zipfile(string resfilepath, string zipfilepath) throws ioexception { return zipfile(resfilepath, zipfilepath, null); } /** * 压缩文件 * * @param resfilepath 待压缩文件路径 * @param zipfilepath 压缩文件路径 * @param comment 压缩文件的注释 * @return {@code true}: 压缩成功<br>{@code false}: 压缩失败 * @throws ioexception io错误时抛出 */ public static boolean zipfile(string resfilepath, string zipfilepath, string comment) throws ioexception { return zipfile(fileutils.getfilebypath(resfilepath), fileutils.getfilebypath(zipfilepath), comment); } /** * 压缩文件 * * @param resfile 待压缩文件 * @param zipfile 压缩文件 * @return {@code true}: 压缩成功<br>{@code false}: 压缩失败 * @throws ioexception io错误时抛出 */ public static boolean zipfile(file resfile, file zipfile) throws ioexception { return zipfile(resfile, zipfile, null); } /** * 压缩文件 * * @param resfile 待压缩文件 * @param zipfile 压缩文件 * @param comment 压缩文件的注释 * @return {@code true}: 压缩成功<br>{@code false}: 压缩失败 * @throws ioexception io错误时抛出 */ public static boolean zipfile(file resfile, file zipfile, string comment) throws ioexception { if (resfile == null || zipfile == null) return false; zipoutputstream zos = null; try { zos = new zipoutputstream(new fileoutputstream(zipfile)); return zipfile(resfile, "", zos, comment); } finally { if (zos != null) { closeutils.closeio(zos); } } } /** * 压缩文件 * * @param resfile 待压缩文件 * @param rootpath 相对于压缩文件的路径 * @param zos 压缩文件输出流 * @param comment 压缩文件的注释 * @return {@code true}: 压缩成功<br>{@code false}: 压缩失败 * @throws ioexception io错误时抛出 */ private static boolean zipfile(file resfile, string rootpath, zipoutputstream zos, string comment) throws ioexception { rootpath = rootpath + (isspace(rootpath) ? "" : file.separator) + resfile.getname(); if (resfile.isdirectory()) { file[] filelist = resfile.listfiles(); // 如果是空文件夹那么创建它,我把'/'换为file.separator测试就不成功,eggpain if (filelist == null || filelist.length <= 0) { zipentry entry = new zipentry(rootpath + '/'); if (!stringutils.isempty(comment)) entry.setcomment(comment); zos.putnextentry(entry); zos.closeentry(); } else { for (file file : filelist) { // 如果递归返回false则返回false if (!zipfile(file, rootpath, zos, comment)) return false; } } } else { inputstream is = null; try { is = new bufferedinputstream(new fileinputstream(resfile)); zipentry entry = new zipentry(rootpath); if (!stringutils.isempty(comment)) entry.setcomment(comment); zos.putnextentry(entry); byte buffer[] = new byte[kb]; int len; while ((len = is.read(buffer, 0, kb)) != -1) { zos.write(buffer, 0, len); } zos.closeentry(); } finally { closeutils.closeio(is); } } return true; } /** * 批量解压文件 * * @param zipfiles 压缩文件集合 * @param destdirpath 目标目录路径 * @return {@code true}: 解压成功<br>{@code false}: 解压失败 * @throws ioexception io错误时抛出 */ public static boolean unzipfiles(collection<file> zipfiles, string destdirpath) throws ioexception { return unzipfiles(zipfiles, fileutils.getfilebypath(destdirpath)); } /** * 批量解压文件 * * @param zipfiles 压缩文件集合 * @param destdir 目标目录 * @return {@code true}: 解压成功<br>{@code false}: 解压失败 * @throws ioexception io错误时抛出 */ public static boolean unzipfiles(collection<file> zipfiles, file destdir) throws ioexception { if (zipfiles == null || destdir == null) return false; for (file zipfile : zipfiles) { if (!unzipfile(zipfile, destdir)) return false; } return true; } /** * 解压文件 * * @param zipfilepath 待解压文件路径 * @param destdirpath 目标目录路径 * @return {@code true}: 解压成功<br>{@code false}: 解压失败 * @throws ioexception io错误时抛出 */ public static boolean unzipfile(string zipfilepath, string destdirpath) throws ioexception { // 判断是否存在这个路径,没有的话就创建这个路径 file tempdir = new file(destdirpath); if (!tempdir.exists()) { tempdir.mkdirs(); } return unzipfile(fileutils.getfilebypath(zipfilepath), fileutils.getfilebypath(destdirpath)); } /** * 解压文件 * * @param zipfile 待解压文件 * @param destdir 目标目录 * @return {@code true}: 解压成功<br>{@code false}: 解压失败 * @throws ioexception io错误时抛出 */ public static boolean unzipfile(file zipfile, file destdir) throws ioexception { return unzipfilebykeyword(zipfile, destdir, null) != null; } /** * 解压带有关键字的文件 * * @param zipfilepath 待解压文件路径 * @param destdirpath 目标目录路径 * @param keyword 关键字 * @return 返回带有关键字的文件链表 * @throws ioexception io错误时抛出 */ public static list<file> unzipfilebykeyword(string zipfilepath, string destdirpath, string keyword) throws ioexception { return unzipfilebykeyword(fileutils.getfilebypath(zipfilepath), fileutils.getfilebypath(destdirpath), keyword); } /** * 解压带有关键字的文件 * * @param zipfile 待解压文件 * @param destdir 目标目录 * @param keyword 关键字 * @return 返回带有关键字的文件链表 * @throws ioexception io错误时抛出 */ public static list<file> unzipfilebykeyword(file zipfile, file destdir, string keyword) throws ioexception { if (zipfile == null || destdir == null) return null; list<file> files = new arraylist<>(); zipfile zf = new zipfile(zipfile); enumeration<?> entries = zf.entries(); while (entries.hasmoreelements()) { zipentry entry = ((zipentry) entries.nextelement()); string entryname = entry.getname(); if (stringutils.isempty(keyword) || fileutils.getfilename(entryname).tolowercase().contains(keyword.tolowercase())) { string filepath = destdir + file.separator + entryname; file file = new file(filepath); files.add(file); if (entry.isdirectory()) { if (!fileutils.createorexistsdir(file)) return null; } else { if (!fileutils.createorexistsfile(file)) return null; inputstream in = null; outputstream out = null; try { in = new bufferedinputstream(zf.getinputstream(entry)); out = new bufferedoutputstream(new fileoutputstream(file)); byte buffer[] = new byte[kb]; int len; while ((len = in.read(buffer)) != -1) { out.write(buffer, 0, len); } } finally { closeutils.closeio(in, out); } } } } return files; } /** * 获取压缩文件中的文件路径链表 * * @param zipfilepath 压缩文件路径 * @return 压缩文件中的文件路径链表 * @throws ioexception io错误时抛出 */ public static list<string> getfilespath(string zipfilepath) throws ioexception { return getfilespath(fileutils.getfilebypath(zipfilepath)); } /** * 获取压缩文件中的文件路径链表 * * @param zipfile 压缩文件 * @return 压缩文件中的文件路径链表 * @throws ioexception io错误时抛出 */ public static list<string> getfilespath(file zipfile) throws ioexception { if (zipfile == null) return null; list<string> paths = new arraylist<>(); enumeration<?> entries = getentries(zipfile); while (entries.hasmoreelements()) { paths.add(((zipentry) entries.nextelement()).getname()); } return paths; } /** * 获取压缩文件中的注释链表 * * @param zipfilepath 压缩文件路径 * @return 压缩文件中的注释链表 * @throws ioexception io错误时抛出 */ public static list<string> getcomments(string zipfilepath) throws ioexception { return getcomments(fileutils.getfilebypath(zipfilepath)); } /** * 获取压缩文件中的注释链表 * * @param zipfile 压缩文件 * @return 压缩文件中的注释链表 * @throws ioexception io错误时抛出 */ public static list<string> getcomments(file zipfile) throws ioexception { if (zipfile == null) return null; list<string> comments = new arraylist<>(); enumeration<?> entries = getentries(zipfile); while (entries.hasmoreelements()) { zipentry entry = ((zipentry) entries.nextelement()); comments.add(entry.getcomment()); } return comments; } /** * 获取压缩文件中的文件对象 * * @param zipfilepath 压缩文件路径 * @return 压缩文件中的文件对象 * @throws ioexception io错误时抛出 */ public static enumeration<?> getentries(string zipfilepath) throws ioexception { return getentries(fileutils.getfilebypath(zipfilepath)); } /** * 获取压缩文件中的文件对象 * * @param zipfile 压缩文件 * @return 压缩文件中的文件对象 * @throws ioexception io错误时抛出 */ public static enumeration<?> getentries(file zipfile) throws ioexception { if (zipfile == null) return null; return new zipfile(zipfile).entries(); } private static boolean isspace(string s) { if (s == null) return true; for (int i = 0, len = s.length(); i < len; ++i) { if (!character.iswhitespace(s.charat(i))) { return false; } } return true; } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: MVPXlistView展示上拉下拉效果
下一篇: Android实现头像上传功能
推荐阅读
-
Android用Scroller实现一个可向上滑动的底部导航栏
-
Android 弹出Dialog时隐藏状态栏和底部导航栏的方法
-
Android底部导航栏的动态替换方案
-
Android底部导航栏的三种风格实现
-
Android选中突出背景效果的底部导航栏功能
-
实现Android 简单的 底部导航栏【EasyNavigationBar】
-
Android应用开发--底部导航栏效果的一种实现方式(ViewPager 、Fragment)
-
Android用Scroller实现一个可向上滑动的底部导航栏
-
Android 弹出Dialog时隐藏状态栏和底部导航栏的方法
-
Android应用开发--底部导航栏效果的一种实现方式(ViewPager&Fragment)