我们还是来看一款示例:(蘑菇街)
看起来很像我们的gridview吧,不过又不像,因为item大小不固定的,看起来是不是别有一番风味,确实如此.就如我们的方角图形,斯通见惯后也就出现了圆角.下面我简单介绍下实现方法.
第一种:
我们在配置文件中定义好列数.如上图也就是3列.我们需要定义三个LinearLayout,然后把获取到的图片add里面就ok了.
main.xml
1. <?xml version="1.0" encoding="utf-8"?>
2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3. "fill_parent"
4. "fill_parent"
5. "@android:color/background_light"
6. "vertical" >
7.
8. <include
9. "@+id/progressbar"
10. "@layout/loading" />
11.
12. <com.jj.waterfall.LazyScrollView
13. "@+id/lazyscrollview"
14. "fill_parent"
15. "fill_parent"
16. "1"
17. "@null" >
18.
19. <LinearLayout
20. "fill_parent"
21. "fill_parent"
22. "@android:color/background_light"
23. "horizontal"
24. "2dp" >
25.
26. <LinearLayout
27. "@+id/layout01"
28. "fill_parent"
29. "fill_parent"
30. "1"
31. "vertical" >
32. </LinearLayout>
33.
34. <LinearLayout
35. "@+id/layout02"
36. "fill_parent"
37. "fill_parent"
38. "1"
39. "vertical" >
40. </LinearLayout>
41.
42. <LinearLayout
43. "@+id/layout03"
44. "fill_parent"
45. "fill_parent"
46. "1"
47. "vertical" >
48. </LinearLayout>
49. </LinearLayout>
50. </com.jj.waterfall.LazyScrollView>
51.
52. <TextView
53. "@+id/loadtext"
54. "fill_parent"
55. "wrap_content"
56. "@drawable/loading_bg"
57. "center"
58. "10dp"
59. "Loading..."
60. "@android:color/background_dark" />
61.
62. </LinearLayout>
在这里因为图片很多就把图片放在assets文件中,如果想从网上拉取数据,自己写额外部分.
1. @Override
2. public void onCreate(Bundle savedInstanceState) {
3. super.onCreate(savedInstanceState);
4. InitView();
5.
6. this.getAssets();
7. // 获取显示图片宽度
8. 4) / 3;
9. try {
10. "images"));// 获取图片名称
11. catch (IOException e) {
12. e.printStackTrace();
13. }
14.
15. addImage(current_page, count);
16.
17. }
1. /***
2. * 加载更多
3. *
4. * @param current_page
5. * 当前页数
6. * @param count
7. * 每页显示个数
8. */
9. private void addImage(int current_page, int count) {
10. for (int x = current_page * count; x < (current_page + 1) * count
11. && x < image_filenames.size(); x++) {
12. addBitMapToImage(image_filenames.get(x), y, x);
13. y++;
14. if (y >= 3)
15. 0;
16. }
17.
18. }
1. /***
2. * 添加imageview 到layout
3. *
4. * @param imagePath 图片name
5. * @param j 列
6. * @param i 行
7. */
8. public void addBitMapToImage(String imagePath, int j, int i) {
9. ImageView imageView = getImageview();
10. new ImageDownLoadAsyncTask(this, imagePath, imageView,
11. Image_width);
12. asyncTask.setProgressbar(progressbar);
13. asyncTask.setLoadtext(loadtext);
14. asyncTask.execute();
15.
16. imageView.setTag(i);
17. if (j == 0) {
18. layout01.addView(imageView);
19. else if (j == 1) {
20. layout02.addView(imageView);
21. else if (j == 2) {
22. layout03.addView(imageView);
23. }
24.
25. new OnClickListener() {
26.
27. @Override
28. public void onClick(View v) {
29. this,
30. "您点击了" + v.getTag() + "个Item", Toast.LENGTH_SHORT)
31. .show();
32.
33. }
34. });
35. }
注释已经很明确,相信大家都看的明白,我就不过多解释了.
因为瀑布流不是一个规则的试图,所以我们不可能用listview那种“底部加一个按钮试图,点击加载更多,这样看起来很难看”。因此我们最好滑动到低端自动加载.
我们这里用到的自定义ScrollView,因为我们要实现下滑分页,这里要判断是否要进行分页等操作.
LazyScrollView.Java (这个法很实用哦.)
1. /***
2. * 自定义ScrollView
3. *
4. * @author zhangjia
5. *
6. */
7. public class LazyScrollView extends ScrollView {
8. private static final String tag = "LazyScrollView";
9. private Handler handler;
10. private View view;
11.
12. public LazyScrollView(Context context) {
13. super(context);
14. }
15.
16. public LazyScrollView(Context context, AttributeSet attrs) {
17. super(context, attrs);
18. }
19.
20. public LazyScrollView(Context context, AttributeSet attrs, int defStyle) {
21. super(context, attrs, defStyle);
22. }
23.
24. // 这个获得总的高度
25. public int computeVerticalScrollRange() {
26. return super.computeHorizontalScrollRange();
27. }
28.
29. public int computeVerticalScrollOffset() {
30. return super.computeVerticalScrollOffset();
31. }
32.
33. /***
34. * 初始化
35. */
36. private void init() {
37.
38. this.setOnTouchListener(onTouchListener);
39. new Handler() {
40. @Override
41. public void handleMessage(Message msg) {
42. // process incoming messages here
43. super.handleMessage(msg);
44. switch (msg.what) {
45. case 1:
46. if (view.getMeasuredHeight() <= getScrollY() + getHeight()) {
47. if (onScrollListener != null) {
48. onScrollListener.onBottom();
49. }
50.
51. else if (getScrollY() == 0) {
52. if (onScrollListener != null) {
53. onScrollListener.onTop();
54. }
55. else {
56. if (onScrollListener != null) {
57. onScrollListener.onScroll();
58. }
59. }
60. break;
61. default:
62. break;
63. }
64. }
65. };
66.
67. }
68.
69. new OnTouchListener() {
70.
71. @Override
72. public boolean onTouch(View v, MotionEvent event) {
73. // TODO Auto-generated method stub
74. switch (event.getAction()) {
75. case MotionEvent.ACTION_DOWN:
76. break;
77. case MotionEvent.ACTION_UP:
78. if (view != null && onScrollListener != null) {
79. 1), 200);
80. }
81. break;
82.
83. default:
84. break;
85. }
86. return false;
87. }
88.
89. };
90.
91. /**
92. * 获得参考的View,主要是为了获得它的MeasuredHeight,然后和滚动条的ScrollY+getHeight作比较。
93. */
94. public void getView() {
95. this.view = getChildAt(0);
96. if (view != null) {
97. init();
98. }
99. }
100.
101. /**
102. * 定义接口
103. *
104. * @author admin
105. *
106. */
107. public interface OnScrollListener {
108. void onBottom();
109.
110. void onTop();
111.
112. void onScroll();
113. }
114.
115. private OnScrollListener onScrollListener;
116.
117. public void setOnScrollListener(OnScrollListener onScrollListener) {
118. this.onScrollListener = onScrollListener;
119. }
我们还需要一个类,异步加载实现,我想有开发经验的朋友一定用过好多次了,这里就不展示代码了,想看的朋友,可以点击下载(如果认为还不错的话,请您一定要表示一下哦.)
对了,忘记一点,我们还需要对MainActivity 中的lazyScrollView实现OnScrollListener接口,对滑动到底部进行监听.
效果图:
/**************************************************************************/
下面我介绍另外一种做法:(相对上面更灵活)
我们动态添加列.
配置文件就不贴了,和上面那例子一样,只不过里面值包含一个LinearLayout布局.
在这里我们动态添加列布局.
1. /***
2. * init view
3. */
4. public void initView() {
5. setContentView(R.layout.main);
6. lazyScrollView = (LazyScrollView) findViewById(R.id.waterfall_scroll);
7. lazyScrollView.getView();
8. this);
9. waterfall_container = (LinearLayout) findViewById(R.id.waterfall_container);
10. progressbar = (LinearLayout) findViewById(R.id.progressbar);
11. loadtext = (TextView) findViewById(R.id.loadtext);
12.
13. item_width = getWindowManager().getDefaultDisplay().getWidth() / column;
14. new ArrayList<LinearLayout>();
15.
16. // 添加列到waterfall_container
17. for (int i = 0; i < column; i++) {
18. new LinearLayout(this);
19. new LinearLayout.LayoutParams(
20. item_width, LayoutParams.WRAP_CONTENT);
21. layout.setOrientation(LinearLayout.VERTICAL);
22. layout.setLayoutParams(itemParam);
23. linearLayouts.add(layout);
24. waterfall_container.addView(layout);
25. }
26.
27. }
1. /***
2. * 获取imageview
3. *
4. * @param imageName
5. * @return
6. */
7. public ImageView getImageview(String imageName) {
8. BitmapFactory.Options options = getBitmapBounds(imageName);
9. // 创建显示图片的对象
10. new ImageView(this);
11. new LayoutParams(LayoutParams.WRAP_CONTENT,
12. LayoutParams.FILL_PARENT);
13. imageView.setLayoutParams(layoutParams);
14. //
15. imageView.setMinimumHeight(options.outHeight);
16. imageView.setMinimumWidth(options.outWidth);
17. 2, 0, 2, 2);
18. imageView.setBackgroundResource(R.drawable.image_border);
19. if (options != null)
20. null;
21. return imageView;
22. }
23.
24. /***
25. *
26. * 获取相应图片的 BitmapFactory.Options
27. */
28. public BitmapFactory.Options getBitmapBounds(String imageName) {
29. int h, w;
30. new BitmapFactory.Options();
31. true;// 只返回bitmap的大小,可以减少内存使用,防止OOM.
32. null;
33. try {
34. "/" + imageName);
35. catch (IOException e) {
36. e.printStackTrace();
37. }
38. null, options);
39. return options;
40.
41. }
在这里我稍微修改了下,为要显示的iamgeview添加一个边框,这样看起来效果不错,我们动态滑动的同时, 然后图片陆续的填充边框.蘑菇街就是这种效果哦.
效果图:
显示成4列,因此图片有点小,仔细看的话,你应该可以看到有好多边框,然后图片陆续的填充边框.这种效果感觉对上面那个用户体验更友好些.
最后简单总结下:针对瀑布流最好使用第二种方法,这种可扩展性比较大,哪天老大说四列太丑了,改成三列,那么我们只需要把column改成3就ok了,简单吧。
注意:由于图片量太多,占用空间太大,因此我将图片上传到网上,获取源码的同学下载该文件放到项目的assets文件夹下,然后运行就ok了.
如果有不足之处,请留言指出,