Android瀑布流照片墙实现,体验不规则排列的美感Demo

移动开发
Android瀑布流照片墙实现,体验不规则排列的美感Demo。

源码简介

Android瀑布流照片墙实现,体验不规则排列的美感Demo。
源码运行截图

 

源码片段

 

  1. /** 
  2.  * 自定义的ScrollView,在其中动态地对图片进行添加。 
  3.  * 
  4.  * @author guolin 
  5.  */ 
  6. public class MyScrollView extends ScrollView implements OnTouchListener { 
  7.   
  8.     /** 
  9.      * 每页要加载的图片数量 
  10.      */ 
  11.     public static final int PAGE_SIZE = 15
  12.   
  13.     /** 
  14.      * 记录当前已加载到第几页 
  15.      */ 
  16.     private int page; 
  17.   
  18.     /** 
  19.      * 每一列的宽度 
  20.      */ 
  21.     private int columnWidth; 
  22.   
  23.     /** 
  24.      * 当前第一列的高度 
  25.      */ 
  26.     private int firstColumnHeight; 
  27.   
  28.     /** 
  29.      * 当前第二列的高度 
  30.      */ 
  31.     private int secondColumnHeight; 
  32.   
  33.     /** 
  34.      * 当前第三列的高度 
  35.      */ 
  36.     private int thirdColumnHeight; 
  37.   
  38.     /** 
  39.      * 是否已加载过一次layout,这里onLayout中的初始化只需加载一次 
  40.      */ 
  41.     private boolean loadOnce; 
  42.   
  43.     /** 
  44.      * 对图片进行管理的工具类 
  45.      */ 
  46.     private ImageLoader imageLoader; 
  47.   
  48.     /** 
  49.      * 第一列的布局 
  50.      */ 
  51.     private LinearLayout firstColumn; 
  52.   
  53.     /** 
  54.      * 第二列的布局 
  55.      */ 
  56.     private LinearLayout secondColumn; 
  57.   
  58.     /** 
  59.      * 第三列的布局 
  60.      */ 
  61.     private LinearLayout thirdColumn; 
  62.   
  63.     /** 
  64.      * 记录所有正在下载或等待下载的任务。 
  65.      */ 
  66.     private static Set<loadimagetask> taskCollection; 
  67.   
  68.     /** 
  69.      * MyScrollView下的直接子布局。 
  70.      */ 
  71.     private static View scrollLayout; 
  72.   
  73.     /** 
  74.      * MyScrollView布局的高度。 
  75.      */ 
  76.     private static int scrollViewHeight; 
  77.   
  78.     /** 
  79.      * 记录上垂直方向的滚动距离。 
  80.      */ 
  81.     private static int lastScrollY = -1
  82.   
  83.     /** 
  84.      * 记录所有界面上的图片,用以可以随时控制对图片的释放。 
  85.      */ 
  86.     private List<imageview> imageViewList = new ArrayList<imageview>(); 
  87.   
  88.     /** 
  89.      * 在Handler中进行图片可见性检查的判断,以及加载更多图片的操作。 
  90.      */ 
  91.     private static Handler handler = new Handler() { 
  92.   
  93.         public void handleMessage(android.os.Message msg) { 
  94.             MyScrollView myScrollView = (MyScrollView) msg.obj; 
  95.             int scrollY = myScrollView.getScrollY(); 
  96.             // 如果当前的滚动位置和上次相同,表示已停止滚动 
  97.             if (scrollY == lastScrollY) { 
  98.                 // 当滚动的最底部,并且当前没有正在下载的任务时,开始加载下一页的图片 
  99.                 if (scrollViewHeight + scrollY >= scrollLayout.getHeight() 
  100.                         && taskCollection.isEmpty()) { 
  101.                     myScrollView.loadMoreImages(); 
  102.                 } 
  103.                 myScrollView.checkVisibility(); 
  104.             } else { 
  105.                 lastScrollY = scrollY; 
  106.                 Message message = new Message(); 
  107.                 message.obj = myScrollView; 
  108.                 // 5毫秒后再次对滚动位置进行判断 
  109.                 handler.sendMessageDelayed(message, 5); 
  110.             } 
  111.         }; 
  112.   
  113.     }; 
  114.   
  115.     /** 
  116.      * MyScrollView的构造函数。 
  117.      * 
  118.      * @param context 
  119.      * @param attrs 
  120.      */ 
  121.     public MyScrollView(Context context, AttributeSet attrs) { 
  122.         super(context, attrs); 
  123.         imageLoader = ImageLoader.getInstance(); 
  124.         taskCollection = new HashSet<loadimagetask>(); 
  125.         setOnTouchListener(this); 
  126.     } 
  127.   
  128.     /** 
  129.      * 进行一些关键性的初始化操作,获取MyScrollView的高度,以及得到第一列的宽度值。并在这里开始加载第一页的图片。 
  130.      */ 
  131.     @Override 
  132.     protected void onLayout(boolean changed, int l, int t, int r, int b) { 
  133.         super.onLayout(changed, l, t, r, b); 
  134.         if (changed && !loadOnce) { 
  135.             scrollViewHeight = getHeight(); 
  136.             scrollLayout = getChildAt(0); 
  137.             firstColumn = (LinearLayout) findViewById(R.id.first_column); 
  138.             secondColumn = (LinearLayout) findViewById(R.id.second_column); 
  139.             thirdColumn = (LinearLayout) findViewById(R.id.third_column); 
  140.             columnWidth = firstColumn.getWidth(); 
  141.             loadOnce = true
  142.             loadMoreImages(); 
  143.         } 
  144.     } 
  145.   
  146.     /** 
  147.      * 监听用户的触屏事件,如果用户手指离开屏幕则开始进行滚动检测。 
  148.      */ 
  149.     @Override 
  150.     public boolean onTouch(View v, MotionEvent event) { 
  151.         if (event.getAction() == MotionEvent.ACTION_UP) { 
  152.             Message message = new Message(); 
  153.             message.obj = this
  154.             handler.sendMessageDelayed(message, 5); 
  155.         } 
  156.         return false
  157.     } 
  158.   
  159.     /** 
  160.      * 开始加载下一页的图片,每张图片都会开启一个异步线程去下载。 
  161.      */ 
  162.     public void loadMoreImages() { 
  163.         if (hasSDCard()) { 
  164.             int startIndex = page * PAGE_SIZE; 
  165.             int endIndex = page * PAGE_SIZE + PAGE_SIZE; 
  166.             if (startIndex < Images.imageUrls.length) { 
  167.                 Toast.makeText(getContext(), "正在加载...", Toast.LENGTH_SHORT) 
  168.                         .show(); 
  169.                 if (endIndex > Images.imageUrls.length) { 
  170.                     endIndex = Images.imageUrls.length; 
  171.                 } 
  172.                 for (int i = startIndex; i < endIndex; i++) { 
  173.                     LoadImageTask task = new LoadImageTask(); 
  174.                     taskCollection.add(task); 
  175.                     task.execute(Images.imageUrls[i]); 
  176.                 } 
  177.                 page++; 
  178.             } else { 
  179.                 Toast.makeText(getContext(), "已没有更多图片", Toast.LENGTH_SHORT) 
  180.                         .show(); 
  181.             } 
  182.         } else { 
  183.             Toast.makeText(getContext(), "未发现SD卡", Toast.LENGTH_SHORT).show(); 
  184.         } 
  185.     } 
  186.   
  187.     /** 
  188.      * 遍历imageViewList中的每张图片,对图片的可见性进行检查,如果图片已经离开屏幕可见范围,则将图片替换成一张空图。 
  189.      */ 
  190.     public void checkVisibility() { 
  191.         for (int i = 0; i < imageViewList.size(); i++) { 
  192.             ImageView imageView = imageViewList.get(i); 
  193.             int borderTop = (Integer) imageView.getTag(R.string.border_top); 
  194.             int borderBottom = (Integer) imageView 
  195.                     .getTag(R.string.border_bottom); 
  196.             if (borderBottom > getScrollY() 
  197.                     && borderTop < getScrollY() + scrollViewHeight) { 
  198.                 String imageUrl = (String) imageView.getTag(R.string.image_url); 
  199.                 Bitmap bitmap = imageLoader.getBitmapFromMemoryCache(imageUrl); 
  200.                 if (bitmap != null) { 
  201.                     imageView.setImageBitmap(bitmap); 
  202.                 } else { 
  203.                     LoadImageTask task = new LoadImageTask(imageView); 
  204.                     task.execute(imageUrl); 
  205.                 } 
  206.             } else { 
  207.                 imageView.setImageResource(R.drawable.empty_photo); 
  208.             } 
  209.         } 
  210.     } 
  211.   
  212.     /** 
  213.      * 判断手机是否有SD卡。 
  214.      * 
  215.      * @return 有SD卡返回true,没有返回false。 
  216.      */ 
  217.     private boolean hasSDCard() { 
  218.         return Environment.MEDIA_MOUNTED.equals(Environment 
  219.                 .getExternalStorageState()); 
  220.     } 
  221.   
  222.     /** 
  223.      * 异步下载图片的任务。 
  224.      * 
  225.      * @author guolin 
  226.      */ 
  227.     class LoadImageTask extends AsyncTask<string, void,="" bitmap=""> { 
  228.   
  229.         /** 
  230.          * 图片的URL地址 
  231.          */ 
  232.         private String mImageUrl; 
  233.   
  234.         /** 
  235.          * 可重复使用的ImageView 
  236.          */ 
  237.         private ImageView mImageView; 
  238.   
  239.         public LoadImageTask() { 
  240.         } 
  241.   
  242.         /** 
  243.          * 将可重复使用的ImageView传入 
  244.          * 
  245.          * @param imageView 
  246.          */ 
  247.         public LoadImageTask(ImageView imageView) { 
  248.             mImageView = imageView; 
  249.         } 
  250.   
  251.         @Override 
  252.         protected Bitmap doInBackground(String... params) { 
  253.             mImageUrl = params[0]; 
  254.             Bitmap imageBitmap = imageLoader 
  255.                     .getBitmapFromMemoryCache(mImageUrl); 
  256.             if (imageBitmap == null) { 
  257.                 imageBitmap = loadImage(mImageUrl); 
  258.             } 
  259.             return imageBitmap; 
  260.         } 
  261.   
  262.         @Override 
  263.         protected void onPostExecute(Bitmap bitmap) { 
  264.             if (bitmap != null) { 
  265.                 double ratio = bitmap.getWidth() / (columnWidth * 1.0); 
  266.                 int scaledHeight = (int) (bitmap.getHeight() / ratio); 
  267.                 addImage(bitmap, columnWidth, scaledHeight); 
  268.             } 
  269.             taskCollection.remove(this); 
  270.         } 
  271.   
  272.         /** 
  273.          * 根据传入的URL,对图片进行加载。如果这张图片已经存在于SD卡中,则直接从SD卡里读取,否则就从网络上下载。 
  274.          * 
  275.          * @param imageUrl 
  276.          *            图片的URL地址 
  277.          * @return 加载到内存的图片。 
  278.          */ 
  279.         private Bitmap loadImage(String imageUrl) { 
  280.             File imageFile = new File(getImagePath(imageUrl)); 
  281.             if (!imageFile.exists()) { 
  282.                 downloadImage(imageUrl); 
  283.             } 
  284.             if (imageUrl != null) { 
  285.                 Bitmap bitmap = ImageLoader.decodeSampledBitmapFromResource( 
  286.                         imageFile.getPath(), columnWidth); 
  287.                 if (bitmap != null) { 
  288.                     imageLoader.addBitmapToMemoryCache(imageUrl, bitmap); 
  289.                     return bitmap; 
  290.                 } 
  291.             } 
  292.             return null
  293.         } 
  294.   
  295.         /** 
  296.          * 向ImageView中添加一张图片 
  297.          * 
  298.          * @param bitmap 
  299.          *            待添加的图片 
  300.          * @param imageWidth 
  301.          *            图片的宽度 
  302.          * @param imageHeight 
  303.          *            图片的高度 
  304.          */ 
  305.         private void addImage(Bitmap bitmap, int imageWidth, int imageHeight) { 
  306.             LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( 
  307.                     imageWidth, imageHeight); 
  308.             if (mImageView != null) { 
  309.                 mImageView.setImageBitmap(bitmap); 
  310.             } else { 
  311.                 ImageView imageView = new ImageView(getContext()); 
  312.                 imageView.setLayoutParams(params); 
  313.                 imageView.setImageBitmap(bitmap); 
  314.                 imageView.setScaleType(ScaleType.FIT_XY); 
  315.                 imageView.setPadding(5555); 
  316.                 imageView.setTag(R.string.image_url, mImageUrl); 
  317.                 findColumnToAdd(imageView, imageHeight).addView(imageView); 
  318.                 imageViewList.add(imageView); 
  319.             } 
  320.         } 
  321.   
  322.         /** 
  323.          * 找到此时应该添加图片的一列。原则就是对三列的高度进行判断,当前高度最小的一列就是应该添加的一列。 
  324.          * 
  325.          * @param imageView 
  326.          * @param imageHeight 
  327.          * @return 应该添加图片的一列 
  328.          */ 
  329.         private LinearLayout findColumnToAdd(ImageView imageView, 
  330.                 int imageHeight) { 
  331.             if (firstColumnHeight <= secondColumnHeight) { 
  332.                 if (firstColumnHeight <= thirdColumnHeight) { 
  333.                     imageView.setTag(R.string.border_top, firstColumnHeight); 
  334.                     firstColumnHeight += imageHeight; 
  335.                     imageView.setTag(R.string.border_bottom, firstColumnHeight); 
  336.                     return firstColumn; 
  337.                 } 
  338.                 imageView.setTag(R.string.border_top, thirdColumnHeight); 
  339.                 thirdColumnHeight += imageHeight; 
  340.                 imageView.setTag(R.string.border_bottom, thirdColumnHeight); 
  341.                 return thirdColumn; 
  342.             } else { 
  343.                 if (secondColumnHeight <= thirdColumnHeight) { 
  344.                     imageView.setTag(R.string.border_top, secondColumnHeight); 
  345.                     secondColumnHeight += imageHeight; 
  346.                     imageView 
  347.                             .setTag(R.string.border_bottom, secondColumnHeight); 
  348.                     return secondColumn; 
  349.                 } 
  350.                 imageView.setTag(R.string.border_top, thirdColumnHeight); 
  351.                 thirdColumnHeight += imageHeight; 
  352.                 imageView.setTag(R.string.border_bottom, thirdColumnHeight); 
  353.                 return thirdColumn; 
  354.             } 
  355.         } 
  356.   
  357.         /** 
  358.          * 将图片下载到SD卡缓存起来。 
  359.          * 
  360.          * @param imageUrl 
  361.          *            图片的URL地址。 
  362.          */ 
  363.         private void downloadImage(String imageUrl) { 
  364.             if (Environment.getExternalStorageState().equals( 
  365.                     Environment.MEDIA_MOUNTED)) { 
  366.                 Log.d("TAG""monted sdcard"); 
  367.             } else { 
  368.                 Log.d("TAG""has no sdcard"); 
  369.             } 
  370.             HttpURLConnection con = null
  371.             FileOutputStream fos = null
  372.             BufferedOutputStream bos = null
  373.             BufferedInputStream bis = null
  374.             File imageFile = null
  375.             try { 
  376.                 URL url = new URL(imageUrl); 
  377.                 con = (HttpURLConnection) url.openConnection(); 
  378.                 con.setConnectTimeout(5 * 1000); 
  379.                 con.setReadTimeout(15 * 1000); 
  380.                 con.setDoInput(true); 
  381.                 con.setDoOutput(true); 
  382.                 bis = new BufferedInputStream(con.getInputStream()); 
  383.                 imageFile = new File(getImagePath(imageUrl)); 
  384.                 fos = new FileOutputStream(imageFile); 
  385.                 bos = new BufferedOutputStream(fos); 
  386.                 byte[] b = new byte[1024]; 
  387.                 int length; 
  388.                 while ((length = bis.read(b)) != -1) { 
  389.                     bos.write(b, 0, length); 
  390.                     bos.flush(); 
  391.                 } 
  392.             } catch (Exception e) { 
  393.                 e.printStackTrace(); 
  394.             } finally { 
  395.                 try { 
  396.                     if (bis != null) { 
  397.                         bis.close(); 
  398.                     } 
  399.                     if (bos != null) { 
  400.                         bos.close(); 
  401.                     } 
  402.                     if (con != null) { 
  403.                         con.disconnect(); 
  404.                     } 
  405.                 } catch (IOException e) { 
  406.                     e.printStackTrace(); 
  407.                 } 
  408.             } 
  409.             if (imageFile != null) { 
  410.                 Bitmap bitmap = ImageLoader.decodeSampledBitmapFromResource( 
  411.                         imageFile.getPath(), columnWidth); 
  412.                 if (bitmap != null) { 
  413.                     imageLoader.addBitmapToMemoryCache(imageUrl, bitmap); 
  414.                 } 
  415.             } 
  416.         } 
  417.   
  418.         /** 
  419.          * 获取图片的本地存储路径。 
  420.          * 
  421.          * @param imageUrl 
  422.          *            图片的URL地址。 
  423.          * @return 图片的本地存储路径。 
  424.          */ 
  425.         private String getImagePath(String imageUrl) { 
  426.             int lastSlashIndex = imageUrl.lastIndexOf("/"); 
  427.             String imageName = imageUrl.substring(lastSlashIndex + 1); 
  428.             String imageDir = Environment.getExternalStorageDirectory() 
  429.                     .getPath() + "/PhotoWallFalls/"
  430.             File file = new File(imageDir); 
  431.             if (!file.exists()) { 
  432.                 file.mkdirs(); 
  433.             } 
  434.             String imagePath = imageDir + imageName; 
  435.             return imagePath; 
  436.         } 
  437.     } 
  438.   
  439. }</string,></loadimagetask></imageview></imageview></loadimagetask> 

源码下载:http://down.51cto.com/data/1980596

责任编辑:chenqingxiang 来源: 网络整理
相关推荐

2011-06-20 17:06:56

Qt Widget

2024-09-03 17:04:15

前端算法布局

2012-05-02 13:53:00

JavaScript

2015-07-17 13:31:20

按钮单独控制

2013-04-03 15:45:51

Android瀑布流android_wat

2024-08-19 14:01:00

2009-12-25 10:20:28

WPF窗口

2015-02-26 18:09:29

WaterFall V瀑布流Dynamic Gri

2010-09-08 17:20:42

CSS

2013-07-12 09:49:41

Android设计

2009-07-10 11:31:45

Swing支持透明和不规则窗口

2010-08-31 09:46:23

C#

2020-11-10 15:22:46

算法PythonIoU

2021-03-30 07:47:46

SVG 滤镜 CSS技巧

2018-12-03 09:00:00

App应用设计移动应用

2010-09-14 10:34:17

DIV CSS

2022-04-14 15:53:12

开发瀑布流组件

2022-12-22 08:34:22

CSS不规则图形

2016-06-13 10:21:49

二维码条形码二进制

2012-06-15 09:35:42

JavaScript
点赞
收藏

51CTO技术栈公众号