欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android底部导航栏的动态替换方案

程序员文章站 2022-08-20 16:39:19
android底部导航栏的动态替换方案,供大家参考,具体内容如下 1、通常来说,一般情况下,我们的app的bottomtab会有下面几种实现方式。 1)、自定义vi...

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;
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。