【Android 界面效果11】android 瀑布流效果(仿蘑菇街)

十度 Android 2015年12月02日 收藏

我们还是来看一款示例:(蘑菇街)  

                

 看起来很像我们的gridview吧,不过又不像,因为item大小不固定的,看起来是不是别有一番风味,确实如此.就如我们的方角图形,斯通见惯后也就出现了圆角.下面我简单介绍下实现方法.

第一种:

我们在配置文件中定义好列数.如上图也就是3列.我们需要定义三个LinearLayout,然后把获取到的图片add里面就ok了.

main.xml

 

[java] view plaincopy
 
 
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="fill_parent"  
  5.     android:background="@android:color/background_light"  
  6.     android:orientation="vertical" >  
  7.   
  8.     <include  
  9.         android:id="@+id/progressbar"  
  10.         layout="@layout/loading" />  
  11.   
  12.     <com.jj.waterfall.LazyScrollView  
  13.         android:id="@+id/lazyscrollview"  
  14.         android:layout_width="fill_parent"  
  15.         android:layout_height="fill_parent"  
  16.         android:layout_weight="1"  
  17.         android:scrollbars="@null" >  
  18.   
  19.         <LinearLayout  
  20.             android:layout_width="fill_parent"  
  21.             android:layout_height="fill_parent"  
  22.             android:background="@android:color/background_light"  
  23.             android:orientation="horizontal"  
  24.             android:padding="2dp" >  
  25.   
  26.             <LinearLayout  
  27.                 android:id="@+id/layout01"  
  28.                 android:layout_width="fill_parent"  
  29.                 android:layout_height="fill_parent"  
  30.                 android:layout_weight="1"  
  31.                 android:orientation="vertical" >  
  32.             </LinearLayout>  
  33.   
  34.             <LinearLayout  
  35.                 android:id="@+id/layout02"  
  36.                 android:layout_width="fill_parent"  
  37.                 android:layout_height="fill_parent"  
  38.                 android:layout_weight="1"  
  39.                 android:orientation="vertical" >  
  40.             </LinearLayout>  
  41.   
  42.             <LinearLayout  
  43.                 android:id="@+id/layout03"  
  44.                 android:layout_width="fill_parent"  
  45.                 android:layout_height="fill_parent"  
  46.                 android:layout_weight="1"  
  47.                 android:orientation="vertical" >  
  48.             </LinearLayout>  
  49.         </LinearLayout>  
  50.     </com.jj.waterfall.LazyScrollView>  
  51.   
  52.     <TextView  
  53.         android:id="@+id/loadtext"  
  54.         android:layout_width="fill_parent"  
  55.         android:layout_height="wrap_content"  
  56.         android:background="@drawable/loading_bg"  
  57.         android:gravity="center"  
  58.         android:padding="10dp"  
  59.         android:text="Loading..."  
  60.         android:textColor="@android:color/background_dark" />  
  61.   
  62. </LinearLayout>  

 

在这里因为图片很多就把图片放在assets文件中,如果想从网上拉取数据,自己写额外部分.

 

[java] view plaincopy
 
 
  1. @Override  
  2.     public void onCreate(Bundle savedInstanceState) {  
  3.         super.onCreate(savedInstanceState);  
  4.         InitView();  
  5.   
  6.         assetManager = this.getAssets();  
  7.         // 获取显示图片宽度  
  8.         Image_width = (getWindowManager().getDefaultDisplay().getWidth() - 4) / 3;  
  9.         try {  
  10.             image_filenames = Arrays.asList(assetManager.list("images"));// 获取图片名称  
  11.         } catch (IOException e) {  
  12.             e.printStackTrace();  
  13.         }  
  14.   
  15.         addImage(current_page, count);  
  16.   
  17.     }  

 

 

[java] view plaincopy
 
 
  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.                 y = 0;  
  16.         }  
  17.   
  18.     }  


 

 

[java] view plaincopy
 
 
  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.         asyncTask = 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.         imageView.setOnClickListener(new OnClickListener() {  
  26.   
  27.             @Override  
  28.             public void onClick(View v) {  
  29.                 Toast.makeText(MainActivity.this,  
  30.                         "您点击了" + v.getTag() + "个Item", Toast.LENGTH_SHORT)  
  31.                         .show();  
  32.   
  33.             }  
  34.         });  
  35.     }  

 

注释已经很明确,相信大家都看的明白,我就不过多解释了.

因为瀑布流不是一个规则的试图,所以我们不可能用listview那种“底部加一个按钮试图,点击加载更多,这样看起来很难看”。因此我们最好滑动到低端自动加载.

我们这里用到的自定义ScrollView,因为我们要实现下滑分页,这里要判断是否要进行分页等操作.

LazyScrollView.java (这个法很实用哦.)

 

[java] view plaincopy
 
 
  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.         handler = 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.     OnTouchListener onTouchListener = 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.                     handler.sendMessageDelayed(handler.obtainMessage(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布局.

在这里我们动态添加列布局.

 

[java] view plaincopy
 
 
  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.         lazyScrollView.setOnScrollListener(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.         linearLayouts = new ArrayList<LinearLayout>();  
  15.   
  16.         // 添加列到waterfall_container  
  17.         for (int i = 0; i < column; i++) {  
  18.             LinearLayout layout = new LinearLayout(this);  
  19.             LinearLayout.LayoutParams itemParam = 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.     }  
[java] view plaincopy
 
 
  1. /*** 
  2.      * 获取imageview 
  3.      *  
  4.      * @param imageName 
  5.      * @return 
  6.      */  
  7.     public ImageView getImageview(String imageName) {  
  8.         BitmapFactory.Options options = getBitmapBounds(imageName);  
  9.         // 创建显示图片的对象  
  10.         ImageView imageView = new ImageView(this);  
  11.         LayoutParams layoutParams = 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.         imageView.setPadding(2022);  
  18.         imageView.setBackgroundResource(R.drawable.image_border);  
  19.         if (options != null)  
  20.             options = null;  
  21.         return imageView;  
  22.     }  
  23.   
  24.     /*** 
  25.      *  
  26.      * 获取相应图片的 BitmapFactory.Options 
  27.      */  
  28.     public BitmapFactory.Options getBitmapBounds(String imageName) {  
  29.         int h, w;  
  30.         BitmapFactory.Options options = new BitmapFactory.Options();  
  31.         options.inJustDecodeBounds = true;// 只返回bitmap的大小,可以减少内存使用,防止OOM.  
  32.         InputStream is = null;  
  33.         try {  
  34.             is = assetManager.open(file + "/" + imageName);  
  35.         } catch (IOException e) {  
  36.             e.printStackTrace();  
  37.         }  
  38.         BitmapFactory.decodeStream(is, null, options);  
  39.         return options;  
  40.   
  41.     }  

在这里我稍微修改了下,为要显示的iamgeview添加一个边框,这样看起来效果不错,我们动态滑动的同时, 然后图片陆续的填充边框.蘑菇街就是这种效果哦.

 效果图:

                 

显示成4列,因此图片有点小,仔细看的话,你应该可以看到有好多边框,然后图片陆续的填充边框.这种效果感觉对上面那个用户体验更友好些.

最后简单总结下:针对瀑布流最好使用第二种方法,这种可扩展性比较大,哪天老大说四列太丑了,改成三列,那么我们只需要把column改成3就ok了,简单吧。


注意:由于图片量太多,占用空间太大,因此我将图片上传到网上,获取源码的同学下载该文件放到项目的assets文件夹下,然后运行就ok了.