咱們都知道在京東,淘寶這些App,在節假日,好比雙11,春節之類的,都會顯示不一樣的底部菜單欄,那這種是怎麼實現的呢?
我有2個思路:php
這邊使用的是第二種方法。java
總體的佈局大概爲:android
<RadioGroup
android:id="@+id/rdoG_main_menu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<RadioButton
android:id="@+id/rdoBtn_main_index"
style="@style/base_radio_button"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawableTop="@drawable/sl_main_index"
android:text="@string/text_index"/>
<RadioButton
android:id="@+id/rdoBtn_main_game"
style="@style/base_radio_button"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawableTop="@drawable/sl_main_game"
android:text="@string/text_game"/>
<RadioButton
android:id="@+id/rdoBtn_main_trad"
style="@style/base_radio_button"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawableTop="@drawable/sl_main_trad"
android:text="@string/text_trad"/>
<RadioButton
android:id="@+id/rdoBtn_main_center"
style="@style/base_radio_button"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:drawableTop="@drawable/sl_main_personal"
android:text="@string/text_person"/>
</RadioGroup>複製代碼
以前的菜單圖標是用靜態的資源文件,也就是R.mipmap.xxxx圖片資源,再經過Selector來控制圖標切換:sql
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="false" android:drawable="@mipmap/personal_normal"/>
<item android:state_checked="true" android:drawable="@mipmap/personal_selected"/>
</selector>複製代碼
那問題來了,圖標是從網上下載的,selector是xml寫的,那咱們要怎麼辦呢?
若是selector能夠用java來寫
若是網絡圖片能夠存爲本地圖片(下次使用)
那就天下太平,一見生財了!緩存
經過java代碼動態生成selector網絡
/** * 建立Selector背景資源文件 * * @param context * @param checked 確認時候的資源文件 * @param unchecked 非確認時候的資源文件 * @return */
private StateListDrawable createDrawableSelector(Context context, Drawable unchecked, Drawable checked) {
StateListDrawable stateList = new StateListDrawable();
int statePressed = android.R.attr.state_pressed;
int stateChecked = android.R.attr.state_checked;
int stateFocused = android.R.attr.state_focused;
stateList.addState(new int[]{stateChecked}, checked);
stateList.addState(new int[]{statePressed}, checked);
stateList.addState(new int[]{stateFocused}, checked);
stateList.addState(new int[]{}, unchecked);
return stateList;
}複製代碼
根據生成的Selector給radioButton設置drawableTopapp
/** * 根據bitmap位圖文件生成selector * * @param bitmapDefault * @param bitmapChecked */
private void createButtonSelector(Bitmap bitmapDefault, Bitmap bitmapChecked, RadioButton radioButton) {
BitmapDrawable drawableDefault = new BitmapDrawable(bitmapDefault);
BitmapDrawable drawableChecked = new BitmapDrawable(bitmapChecked);
Drawable drawable = createDrawableSelector(this, drawableDefault, drawableChecked);
drawable.setBounds(0, 0, ICON_WIDTH,
ICON_WIDTH);
radioButton.setCompoundDrawables(null, drawable, null, null);
}複製代碼
查看如何使用ide
createButtonSelector(BitmapFactory.decodeResource(getResources(), R.mipmap.trad_normal),
BitmapFactory.decodeResource(getResources(), R.mipmap.trad_selected), mRdoBtnMainTrad);複製代碼
其中 trad_normal以及trad_selected爲mipmap中的圖片資源;mRdoBtnMainTrad爲所要設置的RadioButton。佈局
Ok,到這裏爲止,java代碼生成selector而且設置已經完成了。ui
若是咱們只是須要單單獲取bitmap,那麼咱們能夠調用Drawable的方法:
/** * 從網絡獲取圖片 * * @param clazz 調用方法的類 * @param netUrl 獲取圖片的連接 * @return 返回一個 drawable 類型的圖片 */
private static Drawable loadImageFromNet(Class clazz, String netUrl) {
Drawable drawable = null;
try {
drawable = Drawable.createFromStream(new URL(netUrl).openStream(), "netUrl.jpg");
} catch (IOException e) {
XLog.e(clazz.getName() + e.getMessage());
}
return drawable;
}複製代碼
可是!!這樣是很差的,若是單單這樣作的話,那咱們每次都須要從網絡獲取資源,再從新生成selector,再設置上去,這樣的消耗太大了,至少,圖片咱們須要緩存起來!
這裏咱們使用了Glide來作圖片下載,固然,其餘的畢卡索或者imageloader也都是有相似的方法的:
/** * 保存圖片到手機 * * @param url */
public static void download(final String url) {
new AsyncTask<Void, Integer, File>() {
@Override
protected File doInBackground(Void... params) {
File file = null;
try {
FutureTarget<File> future = Glide
.with(CatApplication.getInstance())
.load(url)
.downloadOnly(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
file = future.get();
// 首先保存圖片
File pictureFolder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsoluteFile();
File appDir = new File(pictureFolder, AppConf.DownLoadConf.DOWNLOAD_DIR);
if (!appDir.exists()) {
appDir.mkdirs();
}
String fileName = System.currentTimeMillis() + ".jpg";
File destFile = new File(appDir, fileName);
Kits.File.copyFile(file.getPath(), destFile.getPath());
XLog.e(destFile.getAbsolutePath());
} catch (Exception e) {
e.printStackTrace();
}
return file;
}
@Override
protected void onPostExecute(File file) {
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
}.execute();
}複製代碼
其中copyFile的方法爲:
/** * copy file * * @param sourceFilePath * @param destFilePath * @return * @throws RuntimeException if an error occurs while operator FileOutputStream */
public static boolean copyFile(String sourceFilePath, String destFilePath) {
InputStream inputStream = null;
try {
inputStream = new FileInputStream(sourceFilePath);
} catch (FileNotFoundException e) {
throw new RuntimeException("FileNotFoundException occurred. ", e);
}
return writeFile(destFilePath, inputStream);
}複製代碼
/** * write file, the bytes will be written to the begin of the file * * @param filePath * @param stream * @return * @see {@link #writeFile(String, InputStream, boolean)} */
public static boolean writeFile(String filePath, InputStream stream) {
return writeFile(filePath, stream, false);
}複製代碼
/** * write file * * @param stream the input stream * @param append if <code>true</code>, then bytes will be written to the end of the file rather than the beginning * @return return true * @throws RuntimeException if an error occurs while operator FileOutputStream */
public static boolean writeFile(String filePath, InputStream stream, boolean append) {
return writeFile(filePath != null ? new java.io.File(filePath) : null, stream, append);
}複製代碼
/** * write file * * @param file the file to be opened for writing. * @param stream the input stream * @param append if <code>true</code>, then bytes will be written to the end of the file rather than the beginning * @return return true * @throws RuntimeException if an error occurs while operator FileOutputStream */
public static boolean writeFile(java.io.File file, InputStream stream, boolean append) {
OutputStream o = null;
try {
makeDirs(file.getAbsolutePath());
o = new FileOutputStream(file, append);
byte data[] = new byte[1024];
int length = -1;
while ((length = stream.read(data)) != -1) {
o.write(data, 0, length);
}
o.flush();
return true;
} catch (FileNotFoundException e) {
throw new RuntimeException("FileNotFoundException occurred. ", e);
} catch (IOException e) {
throw new RuntimeException("IOException occurred. ", e);
} finally {
IO.close(o);
IO.close(stream);
}
}複製代碼
/** * Creates the directory named by the trailing filename of this file, including the complete directory path required * to create this directory. <br/> * <br/> * <ul> * <strong>Attentions:</strong> * <li>makeDirs("C:\\Users\\Trinea") can only create users folder</li> * <li>makeFolder("C:\\Users\\Trinea\\") can create Trinea folder</li> * </ul> * * @param filePath * @return true if the necessary directories have been created or the target directory already exists, false one of * the directories can not be created. * <ul> * <li>if {@link File#getFolderName(String)} return null, return false</li> * <li>if target directory already exists, return true</li> * </ul> */
public static boolean makeDirs(String filePath) {
String folderName = getFolderName(filePath);
if (TextUtils.isEmpty(folderName)) {
return false;
}
java.io.File folder = new java.io.File(folderName);
return (folder.exists() && folder.isDirectory()) || folder.mkdirs();
}複製代碼
固然,眼尖的同窗會發現:
這裏有問題啊---->
String fileName = System.currentTimeMillis() + ".jpg";複製代碼
圖片的命名是沒規則的,那咱們怎麼從獲取的圖片中找到本身要的,而後對應生成selector呢?
這裏博主的思路是創建一個sql,創建一個映射,不過如今後臺還沒開發出接口,等接好後,博主會放出一個demo。
以上是博主本身的思路想法,若是各位大佬有更好的方法,歡迎私信以及留言。