【Android】純代碼建立頁面佈局(含異步加載圖片)

開發環境: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 進行各處留白距離的微調。

相關文章
相關標籤/搜索