热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

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

这篇文章主要介绍了Android自定义Gallery控件实现3D图片浏览器,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

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

话不多说,先看效果。

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

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

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

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

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

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 

上面这个方法的作用,就是获取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) &#63; -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 

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

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

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

@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; 
  } 
 
   
} 

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

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

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

<&#63;xml version="1.0" encoding="utf-8"&#63;> 
 
 
   
 
   
 
 

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

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  parent, View view, int position, long id) { 
    // 当点击上面的小图片的时候,获取图片的绝对路径,然后设置给mSwitcher 
    String photoURL = ImageList.get(position); 
    mSwitcher.setImageURI(Uri.parse(photoURL)); 
  } 
 
  @Override 
  public void onNothingSelected(AdapterView<&#63;> 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 listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 本文讲述了如何通过代码在Android中更改Recycler视图项的背景颜色。通过在onBindViewHolder方法中设置条件判断,可以实现根据条件改变背景颜色的效果。同时,还介绍了如何修改底部边框颜色以及提供了RecyclerView Fragment layout.xml和项目布局文件的示例代码。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • Android系统移植与调试之如何修改Android设备状态条上音量加减键在横竖屏切换的时候的显示于隐藏
    本文介绍了如何修改Android设备状态条上音量加减键在横竖屏切换时的显示与隐藏。通过修改系统文件system_bar.xml实现了该功能,并分享了解决思路和经验。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • Android开发实现的计时器功能示例
    本文分享了Android开发实现的计时器功能示例,包括效果图、布局和按钮的使用。通过使用Chronometer控件,可以实现计时器功能。该示例适用于Android平台,供开发者参考。 ... [详细]
  • 本文是关于自学Android的笔记,包括查看类的源码的方法,活动注册的必要性以及布局练习的重要性。通过学习本文,读者可以了解到在自学Android过程中的一些关键点和注意事项。 ... [详细]
  • 本文介绍了在使用MSXML解析XML文件时出现DTD禁用问题的解决方案。通过代码示例和错误信息获取方法,解释了默认情况下DTD是禁用的,以及如何启用DTD的方法。此外,还提到了网上关于该问题的信息相对较少,因此本文提供了解决方案以供参考。 ... [详细]
  • 在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板
    本文介绍了在Xamarin XAML语言中如何在页面级别构建ControlTemplate控件模板的方法和步骤,包括将ResourceDictionary添加到页面中以及在ResourceDictionary中实现模板的构建。通过本文的阅读,读者可以了解到在Xamarin XAML语言中构建控件模板的具体操作步骤和语法形式。 ... [详细]
  • r2dbc配置多数据源
    R2dbc配置多数据源问题根据官网配置r2dbc连接mysql多数据源所遇到的问题pom配置可以参考官网,不过我这样配置会报错我并没有这样配置将以下内容添加到pom.xml文件d ... [详细]
  • 本文介绍了使用cacti监控mssql 2005运行资源情况的操作步骤,包括安装必要的工具和驱动,测试mssql的连接,配置监控脚本等。通过php连接mssql来获取SQL 2005性能计算器的值,实现对mssql的监控。详细的操作步骤和代码请参考附件。 ... [详细]
author-avatar
醒来时t我尚年少你未老
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有