开发环境:macOS 10.12 + Android Studio 2.2,MinSDK Android 5.1
先看看总体效果
本示例是基于Fragment进行的,直接上代码:
【界面结构】
在 Fragment 中,采用 ScrollView + LinearLayout 实现。
1 <ScrollView xmlns:android="http:///apk/res/android"
2 xmlns:tools="http:///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来实现,实现方式见上述代码中的第12、13行。
分割线采用 drawable 的 shape,注意:shape 中一定要添加 solid 和 size,并且 solid 的颜色必须定义,哪怕是透明的也要定义。
项目结构如下:
背景颜色的定义,在 values/colors 中实现,如下所示:
1 <color name="colorBG">#EEEEEE</color>
整个 divider 的代码如下:
1 <?xml version="1.0" encoding="utf-8"?>
2 <shape xmlns:android="http:///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(.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:///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 的布局的特殊性,需要声明几个关键的东西:
1、声明 LayoutParams layout
2、控件.setId(view.generateViewId())
3、layout.addRule(RelativeLayout.BELOW, 上述 generateViewId() 所产生的 Id)
注意以上三点,即可在 RelativeLayout 中,将各个控件依次分开排列布局。同时,可通过 layout.setMargins 或 控件.setPadding 进行各处留白距离的微调。
谁无虎落平阳日,待我风云再起时!