開發環境:macOS 10.12 + Android Studio 2.2,MinSDK Android 5.1java
先看看整體效果android
本示例是基於Fragment進行的,直接上代碼:緩存
【界面結構】網絡
在 Fragment 中,採用 ScrollView + LinearLayout 實現。app
1 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:scrollbars="vertical" 6 tools:context=".Fragment.HomeFrg"> 7 <LinearLayout 8 android:id="@+id/frg_home" 9 android:layout_width="match_parent" 10 android:layout_height="match_parent" 11 android:orientation="vertical" 12 android:divider="@drawable/sep_home" 13 android:showDividers="middle" /> 14 </ScrollView>
順便說一句,顯示列表中的分割線,採用自身的divider來實現,實現方式見上述代碼中的第十二、13行。異步
分割線採用 drawable 的 shape,注意:shape 中必定要添加 solid 和 size,而且 solid 的顏色必須定義,哪怕是透明的也要定義。ide
項目結構以下:佈局
背景顏色的定義,在 values/colors 中實現,以下所示:post
1 <color name="colorBG">#EEEEEE</color>
整個 divider 的代碼以下:測試
1 <?xml version="1.0" encoding="utf-8"?> 2 <shape xmlns:android="http://schemas.android.com/apk/res/android"> 3 <solid android:color="@color/colorBG" /> 4 <size android:height="10dp" /> 5 </shape>
【代碼結構】
新建 java 的類庫,名爲:TestImage.java,主要是結合緩存實現圖片的異步加載(線程池方式),代碼以下:
1 import android.graphics.drawable.Drawable; 2 import android.os.Handler; 3 4 import java.lang.ref.SoftReference; 5 import java.net.URL; 6 import java.util.HashMap; 7 import java.util.Map; 8 import java.util.concurrent.ExecutorService; 9 import java.util.concurrent.Executors; 10 11 public class TestImage { 12 // 爲了加快速度,在內存中開啓緩存 13 // 主要應用於重複圖片較多時,或者同一個圖片要屢次被訪問,好比在ListView時來回滾動 14 public Map<String, SoftReference<Drawable>> imageCache = new HashMap<String, SoftReference<Drawable>>(); 15 16 // 固定 10 個線程來執行任務 17 private ExecutorService _exeService = Executors.newFixedThreadPool(10); 18 private final Handler _handler = new Handler(); 19 20 public Drawable getImage(final String url, final Callback callback) { 21 22 // 緩存中存在就用緩存中的圖片 23 if (imageCache.containsKey(url)) { 24 SoftReference<Drawable> softReference = imageCache.get(url); 25 26 if (softReference.get() != null) { 27 return softReference.get(); 28 } 29 } 30 31 // 緩存中沒有圖片,就從網絡中獲取圖片,同時,存入緩存 32 _exeService.submit(new Runnable() { 33 34 @Override 35 public void run() { 36 final Drawable drawable = getImage(url); 37 imageCache.put(url, new SoftReference<Drawable>(drawable)); 38 39 _handler.post(new Runnable() { 40 41 @Override 42 public void run() { 43 callback.imageLoaded(drawable); 44 } 45 }); 46 } 47 }); 48 49 return null; 50 } 51 52 // 從網絡中獲取圖片 53 protected Drawable getImage(String url) { 54 Drawable drawable = null; 55 56 try { 57 drawable = Drawable.createFromStream(new URL(url).openStream(), "img.png"); 58 } catch (Exception e) { 59 e.printStackTrace(); 60 } 61 62 return drawable; 63 } 64 65 // 回調方法 66 public interface Callback { 67 void imageLoaded(Drawable drawable); 68 } 69 }
類庫創建好了以後,在 Fragment 的後臺代碼中進行調用(含代碼建立頁面佈局),代碼以下:
1 public class HomeFrg extends Fragment { 2 3 private LinearLayout _layout; 4 //private TestImage _testImage = new TestImage(); 5 6 public HomeFrg() { 7 // Required empty public constructor 8 } 9 10 @Override 11 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 13 View view = inflater.inflate(R.layout.frg_home, container, false); 14 initView(view); 15 16 // Inflate the layout for this fragment 17 return view; 18 } 19 20 private void initView(View view) { 21 _layout = (LinearLayout) view.findViewById(R.id.frg_home); 22 23 for (int i = 0; i < 3; i++) { 24 initCell(view); 25 } 26 } 27 28 private void initCell(View view) { 29 Context self = this.getContext(); 30 31 // 建立單個的單元格的容器(RelativeLayout) 32 RelativeLayout.LayoutParams layoutWrapper = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); 33 RelativeLayout wrapper = new RelativeLayout(self); 34 wrapper.setBackgroundColor(Helper.getColor(self, R.color.colorWhite)); 35 wrapper.setPadding(0, 30, 0, 30); 36 _layout.addView(wrapper, layoutWrapper); 37 38 // 建立封面圖片(ImageView) 39 RelativeLayout.LayoutParams layoutCover = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 600); 40 ImageView imgCover = new ImageView(self); 41 int idCover = view.generateViewId(); 42 imgCover.setId(idCover); 43 // 異步加載網絡圖片(圖片URL爲測試圖片) 44 loadImage("http://pic9.nipic.com/20100904/4845745_195609329636_2.jpg", imgCover); 45 imgCover.setScaleType(ImageView.ScaleType.CENTER_CROP); 46 imgCover.setPadding(20, 0, 20, 0); 47 wrapper.addView(imgCover, layoutCover); 48 49 // 建立標題(TextView) 50 RelativeLayout.LayoutParams layoutTitle = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); 51 layoutTitle.setMargins(20, 0, 20, 0); 52 layoutTitle.addRule(RelativeLayout.BELOW, idCover); 53 TextView txtTitle = new TextView(self); 54 int idTitle = view.generateViewId(); 55 txtTitle.setId(idTitle); 56 txtTitle.setText("標題內容標題內容標題內容標題內容標題內容標題內容"); 57 txtTitle.setTextSize(20); 58 // 標題單行顯示,多餘的字符用省略號代替(包括如下兩行) 59 txtTitle.setEllipsize(TextUtils.TruncateAt.END); 60 txtTitle.setSingleLine(); 61 txtTitle.setTextColor(Helper.getColor(self, R.color.colorBlack)); 62 wrapper.addView(txtTitle, layoutTitle); 63 64 // 建立做者(TextView) 65 RelativeLayout.LayoutParams layoutAuthor = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); 66 layoutAuthor.setMargins(20, 0, 20, 0); 67 layoutAuthor.addRule(RelativeLayout.BELOW, idTitle); 68 TextView txtAuthor = new TextView(self); 69 int idAuthor = view.generateViewId(); 70 txtAuthor.setId(idAuthor); 71 txtAuthor.setText("做者名稱"); 72 txtAuthor.setTextColor(Helper.getColor(self, R.color.colorBlack)); 73 wrapper.addView(txtAuthor, layoutAuthor); 74 75 // 建立日期(TextView) 76 RelativeLayout.LayoutParams layoutTime = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); 77 layoutTime.setMargins(20, 0, 20, 0); 78 layoutTime.addRule(RelativeLayout.BELOW, idAuthor); 79 TextView txtTime = new TextView(self); 80 txtTime.setText("2016年9月22日 16:33"); 81 wrapper.addView(txtTime, layoutTime); 82 } 83 84 // 再次封裝 TestImage,實現異步加載,方便頁面內調用 85 private void loadImage(String url, final ImageView imageView) { 86 Drawable imgCache = new TestImage().getImage(url, new TestImage.Callback() { 87 88 @Override 89 public void imageLoaded(Drawable drawable) { 90 imageView.setImageDrawable(drawable); 91 } 92 }); 93 94 if (imgCache != null) { 95 imageView.setImageDrawable(imgCache); 96 } 97 } 98 }
至此,全部功能實現完畢。
【特別說明】
上述代碼在建立佈局時,若是碰到最終效果,多個控件(包括 ImageView 和 TextView)重疊時,那是因爲 RelativeLayout 的佈局的特殊性,須要聲明幾個關鍵的東西:
一、聲明 LayoutParams layout
二、控件.setId(view.generateViewId())
三、layout.addRule(RelativeLayout.BELOW, 上述 generateViewId() 所產生的 Id)
注意以上三點,便可在 RelativeLayout 中,將各個控件依次分開排列布局。同時,可經過 layout.setMargins 或 控件.setPadding 進行各處留白距離的微調。