Android自定义Gallery控件实现3D图片浏览器

本篇文章主要介绍如何使用自定义的Gallery控件,实现3D效果的图片浏览器的效果。

话不多说,先看效果。

上面是一个自定义的Gallery控件,实现倒影和仿3D的效果,下面是一个图片查看器,点击上面的小图片,可以在下面查看大图片。

下面重点说一下,实现图片查看器的思路。

1.手机中图片路径的获取

首先,先不管图片如何展示,如果我们想实现图片查看器的功能,我们首先需要做的是获取到所有的图片的路径信息,只有这样,我们才能实现对图片的查看。

我们可以使用下面的代码实现

private List<String> getImagesFromSD() {
    List<String> imageList = new ArrayList<String>();
    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; 

  }

2.上方小图片3D效果展示的实现

在完成了图片路径的获取之后,我们下面要做的就是将图片展示在上面的有3D效果的自定义Gallery控件上面。现在版本中Gallery控件已经不再推荐使用,取而代之的ViewPager和HorizonalScrollView控件。
下面介绍具有自定义Gallery控件的实现

/**
 * 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();
  }
}

通过自定义gallery控件,现在我们已经实现了当滑动Gallery里面的图片时,两侧的图片会发生一定角度的旋转,也就是完成了3D效果的第一部,下一步,就需要我们在Gallery的Adapter里面,对getView方法,进行改造,从而完成预览小图片的倒影效果

3.实现Adapter,完成倒影效果

要完成倒映效果,我们需要在getView方法中,对穿进来的图片进行处理,具体代码如下

@SuppressWarnings({ "deprecation", "unused" })
public class ImageAdapter extends BaseAdapter { 

  private Context mContext;
  //用于存放图片的路径
  private List<String> 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<String> _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;
  } 

}

最主要的还是理解如何实现的倒影效果。注释应该是很详细了,不过多解释。

4.如何使用自定义的Gallery控件实现最终的图片查看器

下面,我们看一下,如何使用这个控件,实现我们最终的效果。
布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:background="#F9F900"
  android:gravity="center_horizontal"
  android:orientation="vertical" > 

  <com.examole.gallery.GalleryFlow
    android:id="@+id/mygallery"
    android:layout_width="match_parent"
    android:layout_height="100dp"
    android:layout_marginTop="20dp"
    android:gravity="center_vertical" /> 

  <ImageSwitcher
    android:id="@+id/switcher"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="center_horizontal" /> 

</LinearLayout>

我们在这里使用了一个很陌生的类,那就是ImageSwicher,我们看一下,在Activity如何使用

public class MainActivity extends Activity implements AdapterView.OnItemSelectedListener, ViewSwitcher.ViewFactory { 

  private List<String> 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<String> getImagesFromSD() {
    List<String> imageList = new ArrayList<String>();
    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;
  }
}

除了ImageSwitcher这个控件,其他的应该都很熟悉了,经过这几个步骤,我们终于实现了一个简单的仿3D效果的图片查看器。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

您可能感兴趣的文章:

  • Android实现幻灯片式图片浏览器
  • Android实现中轴旋转特效 Android制作别样的图片浏览器
  • Android实现网络图片浏览器
  • Android使用gallery和imageSwitch制作可左右循环滑动的图片浏览器
  • Android编程实现的超炫图片浏览器
  • Android实现图片浏览器示例
(0)

相关推荐

  • Android实现幻灯片式图片浏览器

    我们来实现一个幻灯片式图片浏览器: 最下面一个画廊视图,选中画廊中的图片,会在上面的ImageSwitcher控件中显示大图. 效果图如图 实现方法: 在布局文件中添加图片切换控件ImageSwitcher和画廊视图控件Gallery res/layout/main.xml: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas

  • Android实现图片浏览器示例

    本文所述为一个基础的Android图片浏览器代码,是仿写Google原版实现的,代码中实现了主要的实现过程和方法,具体的完善还需要自己添加,代码中有很多注释,可帮助新手们快速理解代码,使用了部分图像资源. 主要功能代码如下: package com.android.coding; import android.app.Activity; import android.content.Context; import android.os.Bundle; import android.view.Vi

  • Android实现中轴旋转特效 Android制作别样的图片浏览器

    Android API Demos中有很多非常Nice的例子,这些例子的代码都写的很出色,如果大家把API Demos中的每个例子研究透了,那么恭喜你已经成为一个真正的Android高手了.这也算是给一些比较迷茫的Android开发者一个指出了一个提升自我能力的方向吧.API Demos中的例子众多,今天我们就来模仿其中一个3D变换的特效,来实现一种别样的图片浏览器. 既然是做中轴旋转的特效,那么肯定就要用到3D变换的功能.在Android中如果想要实现3D效果一般有两种选择,一是使用Open

  • Android使用gallery和imageSwitch制作可左右循环滑动的图片浏览器

    效果图: 为了使图片浏览器左右无限循环滑动 我们要自定义gallery的adapter 如果要想自定义adapter首先要了解这几个方法 @Override public int getCount() { // TODO Auto-generated method stub return 0; } @Override public Object getItem(int position) { // TODO Auto-generated method stub return null; } @O

  • Android编程实现的超炫图片浏览器

    本文实例讲述了Android编程实现的超炫图片浏览器.分享给大家供大家参考,具体如下: 使用过Android自带的gallery组件的人都知道,gallery实现的效果就是拖动浏览一组图片,相比iphone里也是用于拖动浏览图片的coverflow,显然逊色不少.实际上,可以通过扩展gallery,通过伪3D变换可以基本实现coverflow的效果.本文通过源代码解析这一功能的实现.具体代码作用可参照注释. 最终实现效果如下: 要使用gallery,我们必须首先给其指定一个adapter.在这里

  • Android实现网络图片浏览器

    本文实例为大家分享了Android网络图片浏览器的制作过程,供大家参考,具体内容如下 一.创建一个"网络图片浏览器的应用程序",并设计用户交互界面,"网络图片浏览器"对应的布局文件(activity_main.xml)代码如下: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.and

  • Android自定义Gallery控件实现3D图片浏览器

    本篇文章主要介绍如何使用自定义的Gallery控件,实现3D效果的图片浏览器的效果. 话不多说,先看效果. 上面是一个自定义的Gallery控件,实现倒影和仿3D的效果,下面是一个图片查看器,点击上面的小图片,可以在下面查看大图片. 下面重点说一下,实现图片查看器的思路. 1.手机中图片路径的获取 首先,先不管图片如何展示,如果我们想实现图片查看器的功能,我们首先需要做的是获取到所有的图片的路径信息,只有这样,我们才能实现对图片的查看. 我们可以使用下面的代码实现 private List<St

  • Android自定义组合控件之自定义下拉刷新和左滑删除实例代码

    绪论 最近项目里面用到了下拉刷新和左滑删除,网上找了找并没有可以用的,有比较好的左滑删除,但是并没有和下拉刷新上拉加载结合到一起,要不就是一些比较水的结合,并不能在项目里面使用,小编一着急自己组合了一个,做完了和QQ的对比了一下,并没有太大区别,今天分享给大家,其实并不难,但是不知道为什么网上没有比较好的Demo,当你的项目真的很急的时候,又没有比较好的Demo,那么"那条友谊的小船儿真是说翻就翻啊",好了,下面先来具体看一下实现后的效果吧: 代码已经上传到Github上了,小伙伴们记

  • Android自定义DigitalClock控件实现商品倒计时

    本文实例为大家分享了DigitalClock实现商品倒计时的具体代码,供大家参考,具体内容如下 自定义DigitalClock控件: package com.veally.timesale; import java.util.Calendar; import android.content.Context; import android.database.ContentObserver; import android.os.Handler; import android.os.SystemClo

  • Android自定义评分控件的完整实例

    目录 前言 自定义参数 解析参数 绘制 事件处理 评分监听 外部使用 总结 前言 无意中翻到几年前写过的一个RatingBar,可以拖拽,支持自定义星星图片,间距大小等参数. 自定义参数 为了方便扩展,支持更多的样式,这里将大部分参数设置成支持外部可配置的形式. <declare-styleable name="RatingBarPlus"> <attr name="hideImageResource" format="reference

  • Android自定义View控件实现刷新效果

    三种得到LinearInflater的方法 a. LayoutInflater inflater = getLayoutInflater(); b. LayoutInflater localinflater = (LayoutInflater)context.getSystemService (Context.LAYOUT_INFLATER_SERVICE); c. LayoutInflater inflater = LayoutInflater.from(context); onDraw 方法

  • Android 自定义Button控件实现按钮点击变色

    效果图如下所示: 一.shape 样式:(在drawable新建-->new-->Drawable resource file 在父级标签selector添加Item ) <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item and

  • android自定义倒计时控件示例

    自定义TextView控件TimeTextView代码: 复制代码 代码如下: import android.content.Context;import android.content.res.TypedArray;import android.graphics.Paint;import android.text.Html;import android.util.AttributeSet;import android.widget.TextView; import com.new0315.R;

  • Android自定义表格控件满足人们对视觉的需求

    Android平台已经给我们提供了很多标准的组件,如:TextView.EditView.Button.ImageView.Menu等,还有许多布局控件,常见的有:AbsoluteLayout.LinerLayout.RelativeLayout.TableLayout等.但随着人们对视觉的需求,基本组件已无法满足人们求新求异的要求,于是我们常常会自定义组件,用来实现更美观的UI界面. 实现自定义控件通常有两种途径,一种是继承View类,重写其中的重要方法,另一种是继承ViewGroup类,通过

  • Android自定义日历控件实例详解

    为什么要自定义控件 有时,原生控件不能满足我们对于外观和功能的需求,这时候可以自定义控件来定制外观或功能:有时,原生控件可以通过复杂的编码实现想要的功能,这时候可以自定义控件来提高代码的可复用性. 如何自定义控件 下面我通过我在github上开源的Android-CalendarView项目为例,来介绍一下自定义控件的方法.该项目中自定义的控件类名是CalendarView.这个自定义控件覆盖了一些自定义控件时常需要重写的一些方法. 构造函数 为了支持本控件既能使用xml布局文件声明,也可在ja

  • Android自定义View控件实现多种水波纹涟漪扩散效果

    效果图 实现思路 这个效果实现起来并不难,重要的是思路 此View满足了多种水波纹涟漪扩散效果,这要求它能满足很多的变化 根据上面的样式,可以看出此View需要满足以下变化 圆圈从中心可循环向外扩散 圆圈之间的扩散间距可以改变 可控制扩散圆的渐变度 圆圈可以是线条样式或者实心样式 圆圈扩散的速度可以控制 适配圆圈不同大小下的扩散效果 具体实现 创建自定义属性 首先为View创建自定义的xml属性 在工程的values目录下新建attrs.xml文件 <declare-styleable name

随机推荐