android ScrollView判断滑动到底部的两种方式

  • Post author:
  • Post category:其他


package com.example.photowallfallsdemo;

import java.io.BufferedInputStream;

import java.io.BufferedOutputStream;

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

import java.net.HttpURLConnection;

import java.net.URL;

import java.util.ArrayList;

import java.util.HashSet;

import java.util.List;

import java.util.Set;

import android.content.Context;

import android.content.Intent;

import android.graphics.Bitmap;

import android.os.AsyncTask;

import android.os.Environment;

import android.os.Handler;

import android.os.Message;

import android.util.AttributeSet;

import android.util.Log;

import android.view.MotionEvent;

import android.view.View;

import android.view.View.OnTouchListener;

import android.widget.ImageView;

import android.widget.ImageView.ScaleType;

import android.widget.LinearLayout;

import android.widget.ScrollView;

import android.widget.Toast;

/**

* @author guolin

*/

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) {




// 当滚动的最底部,并且当前没有正在下载的任务时,开始加载下一页的图片,这种只会是往下翻页的情况



// scrollLayout.getHeight表示内容的高度,getScrollY()方法表示已经滑动了多少的坐标,是左上角的Y坐标



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();



}



}


//这是第2种方式





@Override



protected void onScrollChanged(int l, int t, int oldl, int oldt) {




// TODO Auto-generated method stub



super.onScrollChanged(l, t, oldl, oldt);



if (t + getHeight() >= computeVerticalScrollRange() {




// ScrollView滑动到底部了






}



}



/**



* 监听用户的触屏事件,如果用户手指离开屏幕则开始进行滚动检测。



*/



@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(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(i);



}



} 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<Integer, Void, Bitmap> {



/**



* 图片的URL地址



*/



private String mImageUrl;



/**



* 可重复使用的ImageView



*/



private ImageView mImageView;



private int mItemPosition;



public LoadImageTask() {



}



/**



* 将可重复使用的ImageView传入



*



* @param imageView



*/



public LoadImageTask(ImageView imageView) {



mImageView = imageView;



}



@Override



protected Bitmap doInBackground(Integer… params) {



mItemPosition = params[0];



mImageUrl = Images.imageUrls[mItemPosition];



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);



imageView.setOnClickListener(new OnClickListener() {



@Override



public void onClick(View v) {



Intent intent = new Intent(getContext(),



ImageDetailsActivity.class);



intent.putExtra(“image_position”, mItemPosition);



getContext().startActivity(intent);



}



});



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;



}



}

}



版权声明:本文为luo446718254原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。