안 드 로 이 드 폭포 흐름 사진 벽 불규칙 배열 의 아름다움 체험

전통 적 인 인터페이스의 구조 방식 은 항상 행렬 이 뚜렷 하고 질서 가 있다.이런 구 조 는 흔히 볼 수 있 는 것 이 고 자신 도 모 르 는 사이 에 모두 가 이에 대해 심미 적 피 로 를 느 꼈 다.이때 폭포 의 흐름 구조 가 등장 하면 서 사람들 에 게 새로운 느낌 을 주 었 다.이런 구 조 는 불규칙 한 것 처럼 보이 지만 말 할 수 없 는 미 적 감각 이 생 겨 서 대량의 사이트 와 응용 프로그램 이 이런 새로운 구 조 를 사용 하여 인터페이스 를 만 들 었 다.
제 가 예전 에 안 드 로 이 드 에서 포 토 월 기능 을 어떻게 실현 하 는 지 에 관 한 글 을 썼 던 기억 이 있 습 니 다.그런데 그 때 는 GridView 를 사용 하여 레이아웃 을 했 습 니 다.이런 레이아웃 방식 은'벽'에 있 는 모든 그림 의 크기 가 똑 같은 경우 에 만 적 용 됩 니 다.그림 의 크기 가 들쭉날쭉 하면 GridView 에 나타 나 면 매우 보기 싫 습 니 다.폭포 류 의 배치 방식 을 사용 하면 이 문 제 를 잘 해결 할 수 있 기 때문에 오늘 도 트 렌 드 를 따라 잡 아 안 드 로 이 드 에서 폭포 류 사진 벽의 기능 을 어떻게 실현 하 는 지 살 펴 보 자.
우선 실현 원 리 를 말 해 보 자.폭포 류 의 구조 방식 은 자 유 롭 게 배열 되 어 있 는 것 처럼 보이 지만 사실은 과학적 인 배열 규칙 이 있다.전체 화면 은 화면의 너비 에 따라 등 폭 의 몇 열 로 나 눌 것 이다.핸드폰 의 화면 이 크 지 않 기 때문에 여기 서 우 리 는 세 열 로 나 눌 것 이다.그림 을 추가 해 야 할 때마다 이 그림 의 너 비 를 열 과 같은 너비 로 압축 한 다음 에 같은 압축 비율 로 그림 의 높이 를 압축 한 다음 에 이 세 열 에서 현재 높이 가 가장 작은 열 을 찾 아 그림 을 이 열 에 추가 합 니 다.이후 새로운 그림 을 추가 해 야 할 때마다 위의 조작 을 반복 하면 폭포 흐름 구조의 사진 벽 이 형성 된다.설명 도 는 다음 과 같다.

내 가 이렇게 말 한 것 을 들 으 면 폭포 흐름 의 구조 가 매우 간단 하 다 고 느 낄 수 있 습 니 다.세 개의 LinearLayout 를 사용 하여 전체 화면 폭 을 평평 하 게 나 눈 다음 에 동적 으로 addView()를 들 어가 면 됩 니 다.그 렇 긴 하 다.단지 기능 을 실현 하기 위해 서 라면 이렇게 간단 하 다.하지만 우 리 는 휴대 전화 개발 을 하고 있다 는 것 을 잊 지 마 세 요.리 니 어 라 이 엇 에 그림 을 계속 추가 하면 프로그램 이 곧 OOM 이 될 것 입 니 다.따라서 우 리 는 이미지 자원 을 방출 하 는 합 리 적 인 방안 이 필요 하 다.여 기 는 아직도 LruCache 알고리즘 을 사용 하려 고 하 는데 이 알고리즘 에 익숙 하지 않 은 친 구 는 Android 고 효율 로드 큰 그림,다 중 그림 방안,프로그램 OOM 을 효과적으로 피 할 수 있 습 니 다. 을 참고 할 수 있다.
다음은 안 드 로 이 드 프로젝트 를 새로 만 들 고 PhotoWallFalls Demo 라 는 이름 을 짓 고 4.0 API 를 선택 하 겠 습 니 다.
첫 번 째 로 고려 해 야 할 문 제 는 크기 가 들쭉날쭉 한 그림 들 을 어디서 수집 하 느 냐 는 것 이다.여기 서 저 는 사전에 바 이 두 에서 풍경 사진 을 많이 검색 하고 그들의 방문 안정성 을 확보 하기 위해 이 사진 들 을 제 CSDN 앨범 에 올 렸 습 니 다.그래서 여기 서 사진 을 다운로드 하면 됩 니 다.그림%1 개의 캡 션 을 편 집 했 습 니 다.

public class Images { 
 
 public final static String[] imageUrls = new String[] { 
 "http://img.my.csdn.net/uploads/201309/01/1378037235_3453.jpg", 
 "http://img.my.csdn.net/uploads/201309/01/1378037235_7476.jpg", 
 "http://img.my.csdn.net/uploads/201309/01/1378037235_9280.jpg", 
 "http://img.my.csdn.net/uploads/201309/01/1378037234_3539.jpg", 
 "http://img.my.csdn.net/uploads/201309/01/1378037234_6318.jpg", 
 "http://img.my.csdn.net/uploads/201309/01/1378037194_2965.jpg", 
 "http://img.my.csdn.net/uploads/201309/01/1378037193_1687.jpg", 
 "http://img.my.csdn.net/uploads/201309/01/1378037193_1286.jpg", 
 "http://img.my.csdn.net/uploads/201309/01/1378037192_8379.jpg", 
 "http://img.my.csdn.net/uploads/201309/01/1378037178_9374.jpg", 
 "http://img.my.csdn.net/uploads/201309/01/1378037177_1254.jpg", 
 "http://img.my.csdn.net/uploads/201309/01/1378037177_6203.jpg", 
 "http://img.my.csdn.net/uploads/201309/01/1378037152_6352.jpg", 
 "http://img.my.csdn.net/uploads/201309/01/1378037151_9565.jpg", 
 "http://img.my.csdn.net/uploads/201309/01/1378037151_7904.jpg", 
 "http://img.my.csdn.net/uploads/201309/01/1378037148_7104.jpg", 
 "http://img.my.csdn.net/uploads/201309/01/1378037129_8825.jpg", 
 "http://img.my.csdn.net/uploads/201309/01/1378037128_5291.jpg", 
 "http://img.my.csdn.net/uploads/201309/01/1378037128_3531.jpg", 
 "http://img.my.csdn.net/uploads/201309/01/1378037127_1085.jpg", 
 "http://img.my.csdn.net/uploads/201309/01/1378037095_7515.jpg", 
 "http://img.my.csdn.net/uploads/201309/01/1378037094_8001.jpg", 
 "http://img.my.csdn.net/uploads/201309/01/1378037093_7168.jpg", 
 "http://img.my.csdn.net/uploads/201309/01/1378037091_4950.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949643_6410.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949642_6939.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949630_4505.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949630_4593.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949629_7309.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949629_8247.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949615_1986.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949614_8482.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949614_3743.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949614_4199.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949599_3416.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949599_5269.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949598_7858.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949598_9982.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949578_2770.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949578_8744.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949577_5210.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949577_1998.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949482_8813.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949481_6577.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949480_4490.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949455_6792.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949455_6345.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949442_4553.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949441_8987.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949441_5454.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949454_6367.jpg", 
 "http://img.my.csdn.net/uploads/201308/31/1377949442_4562.jpg" }; 
} 
그 다음 에 이미지 Loader 류 를 새로 만 들 면 그림 을 관리 하 는 데 편리 합 니 다.코드 는 다음 과 같 습 니 다.

public class ImageLoader { 
 
 /** 
 *           ,            ,                         。 
 */ 
 private static LruCache<String, Bitmap> mMemoryCache; 
 
 /** 
 * ImageLoader   。 
 */ 
 private static ImageLoader mImageLoader; 
 
 private ImageLoader() { 
 //              
 int maxMemory = (int) Runtime.getRuntime().maxMemory(); 
 int cacheSize = maxMemory / 8; 
 //                   1/8 
 mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { 
 @Override 
 protected int sizeOf(String key, Bitmap bitmap) { 
 return bitmap.getByteCount(); 
 } 
 }; 
 } 
 
 /** 
 *   ImageLoader   。 
 * 
 * @return ImageLoader   。 
 */ 
 public static ImageLoader getInstance() { 
 if (mImageLoader == null) { 
 mImageLoader = new ImageLoader(); 
 } 
 return mImageLoader; 
 } 
 
 /** 
 *         LruCache 。 
 * 
 * @param key 
 * LruCache  ,       URL  。 
 * @param bitmap 
 * LruCache  ,           Bitmap  。 
 */ 
 public void addBitmapToMemoryCache(String key, Bitmap bitmap) { 
 if (getBitmapFromMemoryCache(key) == null) { 
 mMemoryCache.put(key, bitmap); 
 } 
 } 
 
 /** 
 *  LruCache       ,        null。 
 * 
 * @param key 
 * LruCache  ,       URL  。 
 * @return       Bitmap  ,  null。 
 */ 
 public Bitmap getBitmapFromMemoryCache(String key) { 
 return mMemoryCache.get(key); 
 } 
 
 public static int calculateInSampleSize(BitmapFactory.Options options, 
 int reqWidth) { 
 //        
 final int width = options.outWidth; 
 int inSampleSize = 1; 
 if (width > reqWidth) { 
 //                 
 final int widthRatio = Math.round((float) width / (float) reqWidth); 
 inSampleSize = widthRatio; 
 } 
 return inSampleSize; 
 } 
 
 public static Bitmap decodeSampledBitmapFromResource(String pathName, 
 int reqWidth) { 
 //       inJustDecodeBounds   true,        
 final BitmapFactory.Options options = new BitmapFactory.Options(); 
 options.inJustDecodeBounds = true; 
 BitmapFactory.decodeFile(pathName, options); 
 //            inSampleSize  
 options.inSampleSize = calculateInSampleSize(options, reqWidth); 
 //       inSampleSize        
 options.inJustDecodeBounds = false; 
 return BitmapFactory.decodeFile(pathName, options); 
 } 
 
} 
여기에서 ImageLoader 클래스 를 하나의 예 로 설정 하고 구조 함수 에서 LruCache 클래스 를 초기 화 하 며 최대 캐 시 용량 을 최대 사용 가능 한 메모리 의 1/8 로 설정 합 니 다.그리고 LruCache 를 조작 하고 그림 을 압축 하고 읽 을 수 있 는 다른 몇 가지 방법 을 제공 했다.
다음 에 새로 만 든 MyScrollView 는 ScrollView 에서 계승 합 니 다.코드 는 다음 과 같 습 니 다.

public class MyScrollView extends ScrollView implements OnTouchListener { 
 
 /** 
 *            
 */ 
 public static final int PAGE_SIZE = 15; 
 
 /** 
 *             
 */ 
 private int page; 
 
 /** 
 *        
 */ 
 private int columnWidth; 
 
 /** 
 *          
 */ 
 private int firstColumnHeight; 
 
 /** 
 *          
 */ 
 private int secondColumnHeight; 
 
 /** 
 *          
 */ 
 private int thirdColumnHeight; 
 
 /** 
 *         layout,  onLayout            
 */ 
 private boolean loadOnce; 
 
 /** 
 *             
 */ 
 private ImageLoader imageLoader; 
 
 /** 
 *        
 */ 
 private LinearLayout firstColumn; 
 
 /** 
 *        
 */ 
 private LinearLayout secondColumn; 
 
 /** 
 *        
 */ 
 private LinearLayout thirdColumn; 
 
 /** 
 *                 。 
 */ 
 private static Set<LoadImageTask> taskCollection; 
 
 /** 
 * MyScrollView       。 
 */ 
 private static View scrollLayout; 
 
 /** 
 * MyScrollView     。 
 */ 
 private static int scrollViewHeight; 
 
 /** 
 *             。 
 */ 
 private static int lastScrollY = -1; 
 
 /** 
 *           ,              。 
 */ 
 private List<ImageView> imageViewList = new ArrayList<ImageView>(); 
 
 /** 
 *  Handler             ,           。 
 */ 
 private static Handler handler = new Handler() { 
 
 public void handleMessage(android.os.Message msg) { 
 MyScrollView myScrollView = (MyScrollView) msg.obj; 
 int scrollY = myScrollView.getScrollY(); 
 //               ,        
 if (scrollY == lastScrollY) { 
 //        ,              ,           
 if (scrollViewHeight + scrollY >= scrollLayout.getHeight() 
  && taskCollection.isEmpty()) { 
  myScrollView.loadMoreImages(); 
 } 
 myScrollView.checkVisibility(); 
 } else { 
 lastScrollY = scrollY; 
 Message message = new Message(); 
 message.obj = myScrollView; 
 // 5               
 handler.sendMessageDelayed(message, 5); 
 } 
 }; 
 
 }; 
 
 /** 
 * MyScrollView     。 
 * 
 * @param context 
 * @param attrs 
 */ 
 public MyScrollView(Context context, AttributeSet attrs) { 
 super(context, attrs); 
 imageLoader = ImageLoader.getInstance(); 
 taskCollection = new HashSet<LoadImageTask>(); 
 setOnTouchListener(this); 
 } 
 
 /** 
 *              ,  MyScrollView   ,           。              。 
 */ 
 @Override 
 protected void onLayout(boolean changed, int l, int t, int r, int b) { 
 super.onLayout(changed, l, t, r, b); 
 if (changed && !loadOnce) { 
 scrollViewHeight = getHeight(); 
 scrollLayout = getChildAt(0); 
 firstColumn = (LinearLayout) findViewById(R.id.first_column); 
 secondColumn = (LinearLayout) findViewById(R.id.second_column); 
 thirdColumn = (LinearLayout) findViewById(R.id.third_column); 
 columnWidth = firstColumn.getWidth(); 
 loadOnce = true; 
 loadMoreImages(); 
 } 
 } 
 
 /** 
 *          ,                   。 
 */ 
 @Override 
 public boolean onTouch(View v, MotionEvent event) { 
 if (event.getAction() == MotionEvent.ACTION_UP) { 
 Message message = new Message(); 
 message.obj = this; 
 handler.sendMessageDelayed(message, 5); 
 } 
 return false; 
 } 
 
 /** 
 *           ,                 。 
 */ 
 public void loadMoreImages() { 
 if (hasSDCard()) { 
 int startIndex = page * PAGE_SIZE; 
 int endIndex = page * PAGE_SIZE + PAGE_SIZE; 
 if (startIndex < Images.imageUrls.length) { 
 Toast.makeText(getContext(), "    ...", Toast.LENGTH_SHORT) 
  .show(); 
 if (endIndex > Images.imageUrls.length) { 
  endIndex = Images.imageUrls.length; 
 } 
 for (int i = startIndex; i < endIndex; i++) { 
  LoadImageTask task = new LoadImageTask(); 
  taskCollection.add(task); 
  task.execute(Images.imageUrls[i]); 
 } 
 page++; 
 } else { 
 Toast.makeText(getContext(), "       ", Toast.LENGTH_SHORT) 
  .show(); 
 } 
 } else { 
 Toast.makeText(getContext(), "   SD ", Toast.LENGTH_SHORT).show(); 
 } 
 } 
 
 /** 
 *   imageViewList      ,           ,              ,           。 
 */ 
 public void checkVisibility() { 
 for (int i = 0; i < imageViewList.size(); i++) { 
 ImageView imageView = imageViewList.get(i); 
 int borderTop = (Integer) imageView.getTag(R.string.border_top); 
 int borderBottom = (Integer) imageView 
  .getTag(R.string.border_bottom); 
 if (borderBottom > getScrollY() 
  && borderTop < getScrollY() + scrollViewHeight) { 
 String imageUrl = (String) imageView.getTag(R.string.image_url); 
 Bitmap bitmap = imageLoader.getBitmapFromMemoryCache(imageUrl); 
 if (bitmap != null) { 
  imageView.setImageBitmap(bitmap); 
 } else { 
  LoadImageTask task = new LoadImageTask(imageView); 
  task.execute(imageUrl); 
 } 
 } else { 
 imageView.setImageResource(R.drawable.empty_photo); 
 } 
 } 
 } 
 
 /** 
 *        SD 。 
 * 
 * @return  SD   true,    false。 
 */ 
 private boolean hasSDCard() { 
 return Environment.MEDIA_MOUNTED.equals(Environment 
 .getExternalStorageState()); 
 } 
 
 /** 
 *          。 
 * 
 * @author guolin 
 */ 
 class LoadImageTask extends AsyncTask<String, Void, Bitmap> { 
 
 /** 
 *    URL   
 */ 
 private String mImageUrl; 
 
 /** 
 *       ImageView 
 */ 
 private ImageView mImageView; 
 
 public LoadImageTask() { 
 } 
 
 /** 
 *        ImageView   
 * 
 * @param imageView 
 */ 
 public LoadImageTask(ImageView imageView) { 
 mImageView = imageView; 
 } 
 
 @Override 
 protected Bitmap doInBackground(String... params) { 
 mImageUrl = params[0]; 
 Bitmap imageBitmap = imageLoader 
  .getBitmapFromMemoryCache(mImageUrl); 
 if (imageBitmap == null) { 
 imageBitmap = loadImage(mImageUrl); 
 } 
 return imageBitmap; 
 } 
 
 @Override 
 protected void onPostExecute(Bitmap bitmap) { 
 if (bitmap != null) { 
 double ratio = bitmap.getWidth() / (columnWidth * 1.0); 
 int scaledHeight = (int) (bitmap.getHeight() / ratio); 
 addImage(bitmap, columnWidth, scaledHeight); 
 } 
 taskCollection.remove(this); 
 } 
 
 /** 
 *      URL,       。           SD  ,    SD    ,         。 
 * 
 * @param imageUrl 
 *    URL   
 * @return         。 
 */ 
 private Bitmap loadImage(String imageUrl) { 
 File imageFile = new File(getImagePath(imageUrl)); 
 if (!imageFile.exists()) { 
 downloadImage(imageUrl); 
 } 
 if (imageUrl != null) { 
 Bitmap bitmap = ImageLoader.decodeSampledBitmapFromResource( 
  imageFile.getPath(), columnWidth); 
 if (bitmap != null) { 
  imageLoader.addBitmapToMemoryCache(imageUrl, bitmap); 
  return bitmap; 
 } 
 } 
 return null; 
 } 
 
 /** 
 *  ImageView        
 * 
 * @param bitmap 
 *        
 * @param imageWidth 
 *       
 * @param imageHeight 
 *       
 */ 
 private void addImage(Bitmap bitmap, int imageWidth, int imageHeight) { 
 LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( 
  imageWidth, imageHeight); 
 if (mImageView != null) { 
 mImageView.setImageBitmap(bitmap); 
 } else { 
 ImageView imageView = new ImageView(getContext()); 
 imageView.setLayoutParams(params); 
 imageView.setImageBitmap(bitmap); 
 imageView.setScaleType(ScaleType.FIT_XY); 
 imageView.setPadding(5, 5, 5, 5); 
 imageView.setTag(R.string.image_url, mImageUrl); 
 findColumnToAdd(imageView, imageHeight).addView(imageView); 
 imageViewList.add(imageView); 
 } 
 } 
 
 /** 
 *              。              ,                  。 
 * 
 * @param imageView 
 * @param imageHeight 
 * @return           
 */ 
 private LinearLayout findColumnToAdd(ImageView imageView, 
 int imageHeight) { 
 if (firstColumnHeight <= secondColumnHeight) { 
 if (firstColumnHeight <= thirdColumnHeight) { 
  imageView.setTag(R.string.border_top, firstColumnHeight); 
  firstColumnHeight += imageHeight; 
  imageView.setTag(R.string.border_bottom, firstColumnHeight); 
  return firstColumn; 
 } 
 imageView.setTag(R.string.border_top, thirdColumnHeight); 
 thirdColumnHeight += imageHeight; 
 imageView.setTag(R.string.border_bottom, thirdColumnHeight); 
 return thirdColumn; 
 } else { 
 if (secondColumnHeight <= thirdColumnHeight) { 
  imageView.setTag(R.string.border_top, secondColumnHeight); 
  secondColumnHeight += imageHeight; 
  imageView 
  .setTag(R.string.border_bottom, secondColumnHeight); 
  return secondColumn; 
 } 
 imageView.setTag(R.string.border_top, thirdColumnHeight); 
 thirdColumnHeight += imageHeight; 
 imageView.setTag(R.string.border_bottom, thirdColumnHeight); 
 return thirdColumn; 
 } 
 } 
 
 /** 
 *       SD     。 
 * 
 * @param imageUrl 
 *    URL  。 
 */ 
 private void downloadImage(String imageUrl) { 
 HttpURLConnection con = null; 
 FileOutputStream fos = null; 
 BufferedOutputStream bos = null; 
 BufferedInputStream bis = null; 
 File imageFile = null; 
 try { 
 URL url = new URL(imageUrl); 
 con = (HttpURLConnection) url.openConnection(); 
 con.setConnectTimeout(5 * 1000); 
 con.setReadTimeout(15 * 1000); 
 con.setDoInput(true); 
 con.setDoOutput(true); 
 bis = new BufferedInputStream(con.getInputStream()); 
 imageFile = new File(getImagePath(imageUrl)); 
 fos = new FileOutputStream(imageFile); 
 bos = new BufferedOutputStream(fos); 
 byte[] b = new byte[1024]; 
 int length; 
 while ((length = bis.read(b)) != -1) { 
  bos.write(b, 0, length); 
  bos.flush(); 
 } 
 } catch (Exception e) { 
 e.printStackTrace(); 
 } finally { 
 try { 
  if (bis != null) { 
  bis.close(); 
  } 
  if (bos != null) { 
  bos.close(); 
  } 
  if (con != null) { 
  con.disconnect(); 
  } 
 } catch (IOException e) { 
  e.printStackTrace(); 
 } 
 } 
 if (imageFile != null) { 
 Bitmap bitmap = ImageLoader.decodeSampledBitmapFromResource( 
  imageFile.getPath(), columnWidth); 
 if (bitmap != null) { 
  imageLoader.addBitmapToMemoryCache(imageUrl, bitmap); 
 } 
 } 
 } 
 
 /** 
 *            。 
 * 
 * @param imageUrl 
 *    URL  。 
 * @return          。 
 */ 
 private String getImagePath(String imageUrl) { 
 int lastSlashIndex = imageUrl.lastIndexOf("/"); 
 String imageName = imageUrl.substring(lastSlashIndex + 1); 
 String imageDir = Environment.getExternalStorageDirectory() 
  .getPath() + "/PhotoWallFalls/"; 
 File file = new File(imageDir); 
 if (!file.exists()) { 
 file.mkdirs(); 
 } 
 String imagePath = imageDir + imageName; 
 return imagePath; 
 } 
 } 
 
} 
마 이 스크롤 뷰 는 폭포 흐름 을 실현 하 는 포 토 월 의 핵심 클래스 로,제 가 중점적으로 소개 해 드 리 겠 습 니 다.우선 스크롤 뷰 에서 계승 한 것 으로 스크롤 방식 으로 더 많은 그림 을 볼 수 있 습 니 다.다음 페이지 의 그림 을 불 러 오 는 데 사용 되 는 loadmore Images()방법 을 제공 합 니 다.따라서 onLayout()방법 에서 첫 페이지 의 그림 을 초기 화하 기 위해 서 이 방법 을 한 번 호출 해 야 합 니 다.그리고 onTouch 방법 에 서 는 손가락 이 화면 을 떠 나 는 이 벤트 를 들 을 때마다 handler 를 통 해 현재 ScrollView 의 스크롤 상 태 를 판단 합 니 다.맨 밑 으로 굴 러 간 것 을 발견 하면 다음 페이지 의 그림 을 다시 불 러 옵 니 다.
그럼 로드 모어 이미지()방법의 내부 디 테 일 을 살 펴 보 겠 습 니 다.이 방법 에 서 는 이 페이지 의 모든 그림 을 불 러 오 는 순환 을 사용 합 니 다.매번 LoadImageTask 를 열 어 그림 을 비동기 로 불 러 옵 니 다.그리고 LoadImageTask 에 서 는 먼저 이 그림 이 SD 카드 에 이미 존재 하 는 지 확인 하고,아직 존재 하지 않 는 다 면 인터넷 에서 다운로드 한 다음 이 그림 을 LruCache 에 저장 합 니 다.이 어 이 그림 을 일정한 비율 로 압축 하고 현재 높이 가 가장 작은 열 을 찾 아 압축 된 그림 을 추가 하면 된다.
또 사진 벽 에 있 는 그림 이 모두 적절하게 회 수 될 수 있 도록 체크 비 전 빌 리 티(checkVisibility)방법 을 추가 했다.이 방법의 핵심 사상 은 현재 사진 벽 에 있 는 모든 그림 을 검사 하고 어떤 것 이 보이 고 어떤 것 이 보이 지 않 는 지 판단 하 는 것 이다.그리고 보이 지 않 는 그림 들 을 모두 빈 그림 으로 바 꾸 면 프로그램 이 항상 높 은 메모 리 를 차지 하지 않도록 할 수 있다.이 그림 들 이 다시 보 이 는 것 으로 바 뀌 었 을 때 는 LruCache 에서 이 그림 들 을 다시 꺼 내 면 된다.만약 어떤 그림 이 LruCache 에서 제거 되 었 다 면 LoadImageTask 를 열 어 이 그림 을 메모리 에 다시 불 러 옵 니 다.
그리고 액 티 비 티 를 열거 나 새로 만 듭 니 다main.xml,그 안에 폭포 흐름 의 배치 방식 을 설정 합 니 다.다음 과 같 습 니 다.

<com.example.photowallfallsdemo.MyScrollView xmlns:android="http://schemas.android.com/apk/res/android" 
 android:id="@+id/my_scroll_view" 
 android:layout_width="match_parent" 
 android:layout_height="match_parent" > 
 
 <LinearLayout 
 android:layout_width="match_parent" 
 android:layout_height="wrap_content" 
 android:orientation="horizontal" > 
 
 <LinearLayout 
 android:id="@+id/first_column" 
 android:layout_width="0dp" 
 android:layout_height="wrap_content" 
 android:layout_weight="1" 
 android:orientation="vertical" > 
 </LinearLayout> 
 
 <LinearLayout 
 android:id="@+id/second_column" 
 android:layout_width="0dp" 
 android:layout_height="wrap_content" 
 android:layout_weight="1" 
 android:orientation="vertical" > 
 </LinearLayout> 
 
 <LinearLayout 
 android:id="@+id/third_column" 
 android:layout_width="0dp" 
 android:layout_height="wrap_content" 
 android:layout_weight="1" 
 android:orientation="vertical" > 
 </LinearLayout> 
 </LinearLayout> 
 
</com.example.photowallfallsdemo.MyScrollView> 
이 를 통 해 알 수 있 듯 이 우 리 는 방금 작 성 된 MyScrollView 를 루트 레이아웃 으로 사용 한 다음 에 그 안에 직접 하위 레이아웃 LinearLayout 를 넣 어 현재 미끄럼 구조의 높이 를 통계 한 다음 에 이 레이아웃 에 세 개의 등 폭 LinearLayout 를 각각 1 열,2 열,3 열 로 추가 했다.이렇게 하면 MyScrollView 에서 이 세 개의 LinearLayout 에 그림 을 동적 으로 추가 할 수 있 습 니 다.
마지막 으로 네트워크 와 SD 카드 에 저 장 된 기능 을 사 용 했 기 때문에 AndroidManifest.xml 에 다음 과 같은 권한 을 추가 해 야 합 니 다.

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 
<uses-permission android:name="android.permission.INTERNET" /> 
이렇게 하면 우리 의 모든 인 코딩 작업 이 이미 완성 되 었 습 니 다.지금 은 실행 을 시도 해 볼 수 있 습 니 다.효 과 는 다음 그림 과 같 습 니 다.

폭포 흐름 모드 의 사진 벽 과 는 정말 아름 답 습 니 다.그리고 우 리 는 매우 완벽 한 자원 방출 체 제 를 가지 기 때문에 사진 벽 에 얼마나 많은 그림 을 추가 하 든 프로그램 이 메모 리 를 차지 하 는 것 은 합 리 적 인 범위 내 에서 유 지 됩 니 다.다음 글 에서 저 는 여러분 을 데 리 고 이 프로그램 을 계속 보완 할 것 입 니 다.클릭 하여 큰 그림 을 보고 여러 개의 터치 로 크기 를 조정 하 는 기능 을 추가 할 것 입 니 다.관심 이 있 는 분 들 은 Android 멀 티 터치 기술 실전,자 유 롭 게 그림 크기 조정 및 이동 을 계속 읽 으 세 요.
원본 다운로드:http://xiazai.jb51.net/201610/yuanma/AndroidPhotoWallFalls(jb51.net).rar
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기