【Android】纯代码创建页面布局(含异步加载图片)

开发环境:macOS 10.12 + Android Studio 2.2,MinSDK Android 5.1

先看看总体效果

本示例是基于Fragment进行的,直接上代码:

【界面结构】

在 Fragment 中,采用 ScrollView + LinearLayout 实现。

 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来实现,实现方式见上述代码中的第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://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 的布局的特殊性,需要声明几个关键的东西:

1、声明 LayoutParams layout

2、控件.setId(view.generateViewId())

3、layout.addRule(RelativeLayout.BELOW, 上述 generateViewId() 所产生的 Id)

注意以上三点,即可在 RelativeLayout 中,将各个控件依次分开排列布局。同时,可通过 layout.setMargins 或 控件.setPadding 进行各处留白距离的微调。

时间: 2024-10-29 04:15:23

【Android】纯代码创建页面布局(含异步加载图片)的相关文章

Android 异步加载图片,使用LruCache和SD卡或手机缓存,效果非常的流畅

转载请注明出处http://blog.csdn.net/xiaanming/article/details/9825113 异步加载图片的例子,网上也比较多,大部分用了HashMap<String, SoftReference<Drawable>> imageCache ,但是现在已经不再推荐使用这种方式了,因为从 Android 2.3 (API Level 9)开始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象,这让软引用和弱引用变得不再可靠.另外,Android 3.0

Android之ListView异步加载图片且仅显示可见子项中的图片

折腾了好多天,遇到 N 多让人崩溃无语的问题,不过今天终于有些收获了,这是实验的第一版,有些混乱,下一步进行改造细分,先把代码记录在这儿吧. 网上查了很多资料,发现都千篇一律,抄来抄去,很多细节和完整实例都没看到,只有自己一点点研究了,总体感觉 android 下面要显示个图片真不容易啊. 项目主要实现的功能: 异步加载图片图片内存缓存.异步磁盘文件缓存解决使用 viewHolder 后出现的图片错位问题优化列表滚动性能,仅显示可见子项中的图片无需固定图片显示高度,对高度进行缓存使列表滚动时不会

页面优化——js异步加载

同步加载 在介绍js异步加载之前,我们先来看看什么是js同步加载.我们平时最常使用的就是这种同步加载形式: <script src="http://XXX.com/script.js"></script> 同步模式,又称阻塞模式,会阻止浏览器的后续处理,停止了后续的解析,因此停止了后续的文件加载(如图像).渲染.代码执行.一般的script标签(不带async等属性)加载时会阻塞浏览器,也就是说,浏览器在下载或执行该js代码块时,后面的标签不会被解析,例如在he

android开发干货:实现listview异步加载图片

针对listview异步加载图片这个问题,麦子学院android开发老师讲了一种非常实用的方法,麦子学院android开发老师说凡是是要通过网络获取图片资源一般使用这种方法比较好,用户体验好,下面就说实现方法,先贴上主方法的代码: package cn.wangmeng.test; import java.io.IOException; import java.io.InputStream; import java.lang.ref.SoftReference; import java.net.

android listview 异步加载图片并防止错位

网上找了一张图, listview 异步加载图片之所以错位的根本原因是重用了 convertView 且有异步操作. 如果不重用 convertView 不会出现错位现象, 重用 convertView 但没有异步操作也不会有问题. 我简单分析一下: 当重用 convertView 时,最初一屏显示 7 条记录, getView 被调用 7 次,创建了 7 个 convertView. 当 Item1 划出屏幕, Item8 进入屏幕时,这时没有为 Item8 创建新的 view 实例, Ite

android listview 异步加载图片并防止错位+双缓存

网上找了一张图, listview 异步加载图片之所以错位的根本原因是重用了 convertView 且有异步操作. 如果不重用 convertView 不会出现错位现象, 重用 convertView 但没有异步操作也不会有问题. 我简单分析一下: 当重用 convertView 时,最初一屏显示 7 条记录, getView 被调用 7 次,创建了 7 个 convertView. 当 Item1 划出屏幕, Item8 进入屏幕时,这时没有为 Item8 创建新的 view 实例, Ite

Android ListView异步加载图片乱序问题,原因分析及解决方案

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/45586553 在Android所有系统自带的控件当中,ListView这个控件算是用法比较复杂的了,关键是用法复杂也就算了,它还经常会出现一些稀奇古怪的问题,让人非常头疼.比如说在ListView中加载图片,如果是同步加载图片倒还好,但是一旦使用异步加载图片那么问题就来了,这个问题我相信很多Android开发者都曾经遇到过,就是异步加载图片会出现错位乱序的情况.遇到这个问题时,不

android listview 异步加载图片并防止错位 解决办法

网上找了一张图, listview 异步加载图片之所以错位的根本原因是重用了 convertView 且有异步操作. 如果不重用 convertView 不会出现错位现象, 重用 convertView 但没有异步操作也不会有问题. 我简单分析一下: 当重用 convertView 时,最初一屏显示 7 条记录, getView 被调用 7 次,创建了 7 个 convertView. 当 Item1 划出屏幕, Item8 进入屏幕时,这时没有为 Item8 创建新的 view 实例, Ite

Android批量图片加载经典系列——使用LruCache、AsyncTask缓存并异步加载图片

一.问题描述 使用LruCache.AsyncTask实现批量图片的加载并达到下列技术要求 1.从缓存中读取图片,若不在缓存中,则开启异步线程(AsyncTask)加载图片,并放入缓存中 2.及时移除无效的异步线程;保证异步加载图片时不会乱序 3.只对当前屏幕可见部分进行缓存.异步加载图片 4.优化性能杜绝OOM 二.案例介绍 案例实现照片墙效果 三.主要技术 LruCache 内存缓存技术,在Android中 专门用来做图片缓存处理的组件,主要使用步骤 (1) 设置缓存图片的内存大小,如设置为