本篇文章主要介绍如何使用自定义的Gallery控件,实现3D效果的图片浏览器的效果。
话不多说,先看效果。
上面是一个自定义的Gallery控件,实现倒影和仿3D的效果,下面是一个图片查看器,点击上面的小图片,可以在下面查看大图片。
下面重点说一下,实现图片查看器的思路。
首先,先不管图片如何展示,如果我们想实现图片查看器的功能,我们首先需要做的是获取到所有的图片的路径信息,只有这样,我们才能实现对图片的查看。
我们可以使用下面的代码实现
private List getImagesFromSD() {
List imageList = new ArrayList();
File f = Environment.getExternalStorageDirectory();
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
f = new File(Environment.getExternalStorageDirectory().toString());
} else {
Toast.makeText(MainActivity.this, R.string.sdcarderror, Toast.LENGTH_LONG).show();
return imageList;
}
File[] files = f.listFiles();
if (files == null || files.length == 0)
return imageList;
for (int i = 0; i < files.length; i++) {
File file = files[i];
if (isImageFile(file.getPath()))
imageList.add(file.getPath());
}
return imageList;
}
上面这个方法的作用,就是获取SD卡中,所有文件的后缀名满足图片后缀名的文件的路径,然后放到List容器中返回。
isImageFile方法是这样实现的
private boolean isImageFile(String fName) {
String end = fName.substring(fName.lastIndexOf(".") + 1, fName.length()).toLowerCase();
if (end.equals("jpg") || end.equals("gif") || end.equals("png") || end.equals("jpeg") || end.equals("bmp")) {
return true;
}
return false;
}
/**
* 3D效果Gallery实现
*
* @time 2014年6月26日 下午9:10:47
*/
@SuppressWarnings("deprecation")
public class GalleryFlow extends Gallery {
private Camera mCamera = new Camera();
// 两侧图片最大旋转角度
private int mMaxRotationAngle = 60;
private int mMaxZoom = -120;
private int mCoveflowCenter;
public GalleryFlow(Context context) {
super(context);
this.setStaticTransformationsEnabled(true);
}
public GalleryFlow(Context context, AttributeSet attrs) {
super(context, attrs);
this.setStaticTransformationsEnabled(true);
}
public GalleryFlow(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.setStaticTransformationsEnabled(true);
}
// 设置最大旋转角
public void setMaxRotationAngle(int maxRotationAngle) {
mMaxRotationAngle = maxRotationAngle;
}
// 获取当前控件中心点x轴位置
private int getCenterOfCoverflow() {
return (getWidth() - getPaddingLeft() - getPaddingRight()) / 2 + getPaddingLeft();
}
// 获取view控件的x轴位置
private static int getCenterOfView(View view) {
return view.getLeft() + view.getWidth() / 2;
}
// 默认返回值是false,若设置城true,则每次gallery生成子控件的时候,都会调用这个方法,所以我们可以将返回值设置为true,然后完成child的旋转等变形操作
protected boolean getChildStaticTransformation(View child, Transformation t) {
final int childCenter = getCenterOfView(child);
final int childWidth = child.getWidth();
int rotationAngle = 0;
t.clear();
t.setTransformationType(Transformation.TYPE_MATRIX);
// 如果child控件在中心位置,则不旋转
if (childCenter == mCoveflowCenter) {
transformImageBitmap((ImageView) child, t, 0);
} else {
// 否则,将当前child控件旋转一定角度
rotationAngle = (int) (((float) (mCoveflowCenter - childCenter) / childWidth) * mMaxRotationAngle);
if (Math.abs(rotationAngle) > mMaxRotationAngle) {
rotationAngle = (rotationAngle < 0) ? -mMaxRotationAngle : mMaxRotationAngle;
}
transformImageBitmap((ImageView) child, t, rotationAngle);
}
return true;
}
//重新计算控件的x轴位置
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mCoveflowCenter = getCenterOfCoverflow();
super.onSizeChanged(w, h, oldw, oldh);
}
// 将child控件旋转rotationAngle方法的实现
private void transformImageBitmap(ImageView child, Transformation t, int rotationAngle) {
mCamera.save();
final Matrix imageMatrix = t.getMatrix();
final int imageHeight = child.getLayoutParams().height;
final int imageWidth = child.getLayoutParams().width;
final int rotation = Math.abs(rotationAngle);
// 在Z轴上正向移动camera的视角,实际效果为放大图片。 如果在Y轴上移动,则图片上下移动;X轴上对应图片左右移动。
mCamera.translate(0.0f, 0.0f, 100.0f);
if (rotation < mMaxRotationAngle) {
float zoomAmount = (float) (mMaxZoom + (rotation * 1.5));
mCamera.translate(0.0f, 0.0f, zoomAmount);
}
// 在Y轴上旋转,对应图片竖向向里翻转。如果在X轴上旋转,则对应图片横向向里翻转。
mCamera.rotateY(rotationAngle);
mCamera.getMatrix(imageMatrix);
imageMatrix.preTranslate(-(imageWidth / 2), -(imageHeight / 2));
imageMatrix.postTranslate((imageWidth / 2), (imageHeight / 2));
// 恢复相机原状态
mCamera.restore();
}
}
@SuppressWarnings({ "deprecation", "unused" })
public class ImageAdapter extends BaseAdapter {
private Context mContext;
//用于存放图片的路径
private List imageFileList;
//原始图片
private Bitmap originalImage;
//反射的倒影图片,高度为原始图片一半
private Bitmap reflectionImage;
//用于存放处理后的整个图片,高度为原始图片的1.5倍
private Bitmap bitmapWithReflection;
//图片的宽高
private int width;
private int height;
//矩阵
private Matrix matrix;
//画布
private Canvas canvas;
//原始图像与反射的倒影图像之间的间隔高度
final int reflectionGap = 4;
//用于getView返回
private ImageView imageView;
//倒影的阴影模糊效果
private LinearGradient shader;
public ImageAdapter(Context c, List _imageFileList) {
mContext = c;
imageFileList = _imageFileList;
matrix = new Matrix();
//设置为x轴翻转
matrix.preScale(1, -1);
}
@Override
public int getCount() {
return imageFileList.size();
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
//返回经过处理的ImageView对象
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return createReflectedImages(imageFileList.get(position));
}
//这是最主要的方法,完成了对图片的倒映效果处理
public ImageView createReflectedImages(String filePath) {
//获取原始图片
originalImage = BitmapFactory.decodeFile(filePath);
width = originalImage.getWidth();
height = originalImage.getHeight();
//创建倒影图像,高度是原始图像的一半,并且使用矩阵进行了x轴反转,也就是倒影效果
reflectionImage = Bitmap.createBitmap(originalImage, 0, height / 2, width, height / 2, matrix, false);
//初始化Bitmap对象,用于存放处理后的图片,高度为原始图片的1.5倍
bitmapWithReflection = Bitmap.createBitmap(width, (height + height / 2), Config.ARGB_8888);
//根据bitmapWithReflection对象,创建一个画布
canvas = new Canvas(bitmapWithReflection);
//先把原始图像画上
canvas.drawBitmap(originalImage, 0, 0, null);
Paint paint = new Paint();
//画出原始图像与反射图像之间的小空隙,高度为reflectionGap
canvas.drawRect(0, height, width, height + reflectionGap, paint);
//画出倒影
canvas.drawBitmap(reflectionImage, 0, height + reflectionGap, null);
//设置画笔的阴影效果
shader = new LinearGradient(0, originalImage.getHeight(), 0, bitmapWithReflection.getHeight() + reflectionGap, 0x70ffffff, 0x00ffffff,
TileMode.CLAMP);
paint.setShader(shader);
paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
//在倒影图上用带阴影的画笔绘制矩形
canvas.drawRect(0, height, width, bitmapWithReflection.getHeight() + reflectionGap, paint);
//初始化一个ImageView对象
imageView = new ImageView(mContext);
//将处理后的图像设置为图片资源
imageView.setImageBitmap(bitmapWithReflection);
imageView.setLayoutParams(new Gallery.LayoutParams(120, 160));
imageView.setScaleType(ScaleType.CENTER_INSIDE);
return imageView;
}
}
public class MainActivity extends Activity implements AdapterView.OnItemSelectedListener, ViewSwitcher.ViewFactory {
private List ImageList;
private ImageSwitcher mSwitcher;
private Gallery gallery;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 获取图片路径
ImageList = getImagesFromSD();
mSwitcher = (ImageSwitcher) findViewById(R.id.switcher);
gallery = (Gallery) findViewById(R.id.mygallery);
// ImageSwitcher控件必须实现ViewSwitcher.ViewFactory接口,然后在makeView方法中,返回我们需要显示的控件即可
mSwitcher.setFactory(this);
// 设置图片的进入和离开的动画效果
mSwitcher.setInAnimation(AnimationUtils.loadAnimation(this, android.R.anim.slide_in_left));
mSwitcher.setOutAnimation(AnimationUtils.loadAnimation(this, android.R.anim.slide_out_right));
// 给gallery设置适配器
gallery.setAdapter(new ImageAdapter(this, ImageList));
gallery.setOnItemSelectedListener(this);
}
private List getImagesFromSD() {
List imageList = new ArrayList();
File f = Environment.getExternalStorageDirectory();
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
f = new File(Environment.getExternalStorageDirectory().toString());
} else {
Toast.makeText(MainActivity.this, R.string.sdcarderror, Toast.LENGTH_LONG).show();
return imageList;
}
File[] files = f.listFiles();
if (files == null || files.length == 0)
return imageList;
for (int i = 0; i < files.length; i++) {
File file = files[i];
if (isImageFile(file.getPath()))
imageList.add(file.getPath());
}
return imageList;
}
@SuppressLint("DefaultLocale")
private boolean isImageFile(String fName) {
String end = fName.substring(fName.lastIndexOf(".") + 1, fName.length()).toLowerCase();
if (end.equals("jpg") || end.equals("gif") || end.equals("png") || end.equals("jpeg") || end.equals("bmp")) {
return true;
}
return false;
}
@Override
public void onItemSelected(AdapterView> parent, View view, int position, long id) {
// 当点击上面的小图片的时候,获取图片的绝对路径,然后设置给mSwitcher
String photoURL = ImageList.get(position);
mSwitcher.setImageURI(Uri.parse(photoURL));
}
@Override
public void onNothingSelected(AdapterView> parent) {
}
@Override
public View makeView() {
ImageView i = new ImageView(this);
i.setBackgroundColor(0x00000000);
i.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
i.setLayoutParams(new ImageSwitcher.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
return i;
}
}