公司最近有一个需求,是打算做一个轮播图的展示界面,不过和传统意义上不同,并非是在手机app的顶部展示几张定时切换的固定大小宽高的图片,而是中间长方形,两边向里倾斜,形成对称感的特殊界面,如下图:

需要实现功能:无限循环,自动跳转,倒影效果。

(原本的企划是动画轮播的时候,下面会呈现一条Listview,里面会因为展示的不同界面而呈现不同的内容,但是后面放弃了。)

下面开始上代码:

MainActivity:

package com.example.gallery;import com.example.gallery.view.MyGallery;
import com.example.gallery.view.ImageUtil;import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Gallery.LayoutParams;
import android.widget.ImageView;
import android.widget.Toast;import java.util.Timer;
import java.util.TimerTask;public class MainActivity extends Activity {/*** 图片资源数组*/private int[] imageResIDs;private MyGallery gallery;private int index = 0;private final int AUTOPLAY = 2;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);imageResIDs = new int[]{R.drawable.a00, R.drawable.a01, R.drawable.a02, R.drawable.a03,R.drawable.a04, R.drawable.a05,};gallery = (MyGallery) findViewById(R.id.mygallery);ImageAdapter adapter = new ImageAdapter();gallery.setAdapter(adapter);gallery.setSpacing(50); //图片之间的间距gallery.setSelection((Integer.MAX_VALUE / 2) - (Integer.MAX_VALUE / 2) % imageResIDs.length);gallery.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {@Overridepublic void onItemSelected(AdapterView<?> parent, View view, int position, long id) {}@Overridepublic void onNothingSelected(AdapterView<?> parent) {}});// 设置点击事件监听gallery.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position, long id) {Toast.makeText(MainActivity.this, "当前位置position:"+position+"的图片被选中了", Toast.LENGTH_SHORT).show();}});Timer timer = new Timer();timer.schedule(task, 3000, 3000);}/*** 定时器,实现自动播放*/private TimerTask task = new TimerTask() {@Overridepublic void run() {Message message = new Message();message.what = AUTOPLAY;index = gallery.getSelectedItemPosition();index++;handler.sendMessage(message);}};private Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what) {case AUTOPLAY:gallery.setSelection(index);break;default:break;}}};public class ImageAdapter extends BaseAdapter {@Overridepublic int getCount() {return Integer.MAX_VALUE;//用于循环滚动}@Overridepublic Object getItem(int position) {if (position >= imageResIDs.length) {position = position % imageResIDs.length;}return position;}@Overridepublic long getItemId(int position) {if (position >= imageResIDs.length) {position = position % imageResIDs.length;}return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ImageView imageView;if (convertView != null) {imageView = (ImageView) convertView;} else {imageView = new ImageView(MainActivity.this);}if (position >= imageResIDs.length) {position = position % imageResIDs.length;}Bitmap bitmap = ImageUtil.getImageBitmap(getResources(),imageResIDs[position]);BitmapDrawable drawable = new BitmapDrawable(bitmap);drawable.setAntiAlias(true); // 消除锯齿imageView.setImageDrawable(drawable);LayoutParams params = new LayoutParams(240, 320);imageView.setLayoutParams(params);return imageView;}}
}

备注:自己根据界面适当设置图片间距,这样会呈现不同的展示效果。

自定义Gallery:

package com.example.gallery.view;import android.content.Context;
import android.graphics.Camera;
import android.graphics.Matrix;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Transformation;
import android.widget.Gallery;
import android.widget.ImageView;public class MyGallery extends Gallery {/** Gallery的中心点 */private int galleryCenterPoint = 0;/** 摄像机对象 */private Camera camera;public MyGallery(Context context, AttributeSet attrs) {super(context, attrs);// 启动getChildStaticTransformationsetStaticTransformationsEnabled(true);camera = new Camera();}/*** 当Gallery的宽和高改变时回调此方法,第一次计算gallery的宽和高时,也会调用此方法*/@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);galleryCenterPoint = getGalleryCenterPoint();}/*** 返回gallery的item的子图形的变换效果* * @param t*            指定当前item的变换效果*/@Overrideprotected boolean getChildStaticTransformation(View child, Transformation t) {int viewCenterPoint = getViewCenterPoint(child); // view的中心点int rotateAngle = 0; // 旋转角度,默认为0// 如果view的中心点不等于gallery中心,两边图片需要计算旋转的角度if (viewCenterPoint != galleryCenterPoint) {// gallery中心点 - view中心点 = 差值int diff = galleryCenterPoint - viewCenterPoint;// 差值 / 图片的宽度 = 比值float scale = (float) diff / (float) child.getWidth();// 比值 * 最大旋转角度 = 最终view的旋转角度(最大旋转角度定为50度)rotateAngle = (int) (scale * 50);if (Math.abs(rotateAngle) > 50) {// 当最终旋转角度 》 最大旋转角度,要改成50或-50rotateAngle = rotateAngle > 0 ? 50 : -50;}}// 设置变换效果前,需要把Transformation中的上一个item的变换效果清除t.clear();t.setTransformationType(Transformation.TYPE_MATRIX); // 设置变换效果的类型为矩阵类型startTransformationItem((ImageView) child, rotateAngle, t);return true;}/*** 设置变换的效果* * @param iv*            gallery的item* @param rotateAngle*            旋转的角度* @param t*            变换的对象*/private void startTransformationItem(ImageView iv, int rotateAngle,Transformation t) {camera.save(); // 保存状态int absRotateAngle = Math.abs(rotateAngle);// 1.放大效果(中间的图片要比两边的图片大)camera.translate(0, 0, 100f); // 给摄像机定位int zoom = -250 + (absRotateAngle * 2);camera.translate(0, 0, zoom);// 2.透明度(中间的图片完全显示,两边有一定的透明度)int alpha = (int) (255 - (absRotateAngle * 2.5));iv.setAlpha(alpha);// 3.旋转(中间的图片没有旋转角度,只要不在中间的图片都有旋转角度)camera.rotateY(rotateAngle);Matrix matrix = t.getMatrix(); // 变换的矩阵,将变换效果添加到矩阵中camera.getMatrix(matrix); // 把matrix矩阵给camera对象,camera对象会把上面添加的效果转换成矩阵添加到matrix对象中matrix.preTranslate(-iv.getWidth() / 2, -iv.getHeight() / 2); // 矩阵前乘matrix.postTranslate(iv.getWidth() / 2, iv.getHeight() / 2); // 矩阵后乘camera.restore(); // 恢复之前保存的状态}/*** 获取Gallery的中心点* * @return*/private int getGalleryCenterPoint() {return this.getWidth() / 2;}/*** 获取item上view的中心点* * @param v* @return*/private int getViewCenterPoint(View v) {return v.getWidth() / 2 + v.getLeft(); // 图片宽度的一半+图片距离屏幕左边距}}

对图片进行处理:

package com.example.gallery.view;import java.lang.ref.SoftReference;
import java.util.Hashtable;import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Shader.TileMode;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.util.Log;public class ImageUtil {private static final String TAG = "ImageUtil";/** 缓存集合 */private static Hashtable<Integer, SoftReference<Bitmap>> mImageCache = new Hashtable<Integer, SoftReference<Bitmap>>();/*** 根据id返回一个处理后的图片* * @param res* @param resID* @return*/public static Bitmap getImageBitmap(Resources res, int resID) {// 先去集合中取当前resID是否已经拿过图片,如果集合中有,说明已经拿过,直接使用集合中的图片返回SoftReference<Bitmap> reference = mImageCache.get(resID);if (reference != null) {Bitmap bitmap = reference.get();if (bitmap != null) {// 从内存中取Log.i(TAG, "从内存中取");return bitmap;}}// 如果集合中没有,就调用getInvertImage得到一个图片,需要向集合中保留一张,最后返回当前图片Log.i(TAG, "重新加载");Bitmap invertBitmap = getInvertBitmap(res, resID);// 在集合中保存一份,便于下次获取时直接在集合中获取mImageCache.put(resID, new SoftReference<Bitmap>(invertBitmap));return invertBitmap;}/*** 根据图片的id,获取到处理之后的图片* * @param resID* @return*/public static Bitmap getInvertBitmap(Resources res, int resID) {// 1.获取原图Bitmap sourceBitmap = BitmapFactory.decodeResource(res, resID);// 2.生成倒影图片Matrix m = new Matrix(); // 图片矩阵m.setScale(1.0f, -1.0f); // 让图片按照矩阵进行反转Bitmap invertBitmap = Bitmap.createBitmap(sourceBitmap, 0,sourceBitmap.getHeight() / 2, sourceBitmap.getWidth(),sourceBitmap.getHeight() / 2, m, false);// 3.两张图片合成一张图片Bitmap resultBitmap = Bitmap.createBitmap(sourceBitmap.getWidth(),(int) (sourceBitmap.getHeight() * 1.5 + 5), Config.ARGB_8888);Canvas canvas = new Canvas(resultBitmap); // 为合成图片指定一个画板canvas.drawBitmap(sourceBitmap, 0f, 0f, null); // 将原图片画在画布的上方canvas.drawBitmap(invertBitmap, 0f, sourceBitmap.getHeight() + 5, null); // 将倒影图片画在画布的下方// 4.添加遮罩效果Paint paint = new Paint();// 设置遮罩的颜色,这里使用的是线性梯度LinearGradient shader = new LinearGradient(0,sourceBitmap.getHeight() + 5, 0, resultBitmap.getHeight(),0x70ffffff, 0x00ffffff, TileMode.CLAMP);paint.setShader(shader);// 设置模式为:遮罩,取交集paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));canvas.drawRect(0, sourceBitmap.getHeight() + 5,sourceBitmap.getWidth(), resultBitmap.getHeight(), paint);return resultBitmap;}
}

布局:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@android:color/black"><com.example.gallery.view.MyGalleryandroid:id="@+id/mygallery"android:layout_width="match_parent"android:layout_height="match_parent" ></com.example.gallery.view.MyGallery></RelativeLayout>

~Demo下载链接~

Android 3D画廊采用Gallery实现无限循环、自动轮播相关推荐

  1. html轮播图循环效果,TremulaJS-跨设备多功能的无限循环js轮播图插件

    TremulaJS是一款非常酷的跨设备多功能的无限循环js轮播图插件.TremulaJS是一个客户端javascript UI组件,它基于贝兹曲线和物理动量效应制作各种效果,可以制作无限循环的图片流, ...

  2. android 定时更新banner图片,Android 用banner简单实现图片无限循环

    直接上图 不知道怎么放动态图. 实现步骤 1.导入引入所需要的包implementation 'com.youth.banner:banner:1.4.10' implementation 'com. ...

  3. react无缝滚动_react 实现一个无限循环的轮播器 附github地址

    一个简单的轮播 为了更具有通用和参考性,轮播组件中,轮播只使用了react,没有添加其他的状态管理,或者参数类型限制的库. 所以这个轮播的方法,同样可以用于vue 等其他框架 github地址 最终效 ...

  4. 广告栏(自动轮播,无限循环)-图片轮播控件Banner的简单使用总结

    Gradle dependencies{compile 'com.youth.banner:banner:1.1.5' //指定版本compile 'com.youth.banner:banner:+ ...

  5. android轮播图简单实现(左右无限滑动,自动轮播)

    直接上代码了,都有注释,原理很简单 public class MainActivity extends AppCompatActivity { private static final String ...

  6. 文字从上到下无缝轮播,一直循环滚动轮播

    思路:无缝循环轮播,是一个轮播框(父节点)包含两个子节点,其中一个子节点是文字主体,另一个是这个子节点的复制品,即:在父类节点一定的高度下,这两个子节点实现由下而上的滚动. 贴代码前说下大家一般遇到的 ...

  7. Android TV 3D卡片无限循环效果

    TV 3D卡片无限循环效果 ##前言 需求:实现3个卡片实现无限循环效果:1-2-3-1-2-3-1-,而且要实现3D效果:中间突出,两侧呈角度显示 Viewpager实现方式 (1) LoopVie ...

  8. html5 coverflow,使用FancyCoverFlow实现3D无限循环切换视图

    FancyCoverFlow重写了gallery实现了画廊特效.这里记录下具体的使用方法: 1 在布局文件中添加控件 android:id="@+id/fancy_cover" a ...

  9. android3d画廊自动切换,Android实例(一)—— 3D画廊

    3D画廊 之前我都是写的学习的内容,我在写这些教程时遇到有趣的炫酷的小例子也会专门拿出来写一篇文章,今天就写一个酷炫的小例子,叫3D画廊,它是属于ViewPage的进阶版. 下面的指示器是使用的一大神 ...

  10. android星星爆炸效果图,Android_Android仿开心消消乐大树星星无限循环效果,啥都不说先上效果图,这个是 - phpStudy...

    Android仿开心消消乐大树星星无限循环效果 啥都不说先上效果图,这个是我项目里的效果: 下面的是我抽取出来的 demo 适配啥的我基本上都做好了没做其他的 ok 下面 说一下思路把 首先 说一下原 ...

最新文章

  1. Powershell实战之管道参数绑定
  2. 全国青少年信息学奥林匹克联赛
  3. webstorm与Idea禁用自动保存
  4. c语言 结构作用是什么,C语言选择结构知识点
  5. 2012CSDN年度博客之星评选http://vote.blog.csdn.net/item/blogstar/xyz_lmn
  6. DEVC配置C++11标准
  7. 在一个数组中找到第k小的数(线性时间选择)
  8. web漏洞扫描器原理_「网络安全」安全设备篇(11)——漏洞扫描器
  9. 关于NuDaqPci 数据采集
  10. 2021年新版阿里云服务器价格表(收费标准报价)
  11. Element表格固定第一列和第一行,并通过属性名动态渲染数据
  12. win10无法装载iso文件_win10系统打开iso格式文件的四种方法
  13. MIT6.S081 2021
  14. Android(15)——ButterKnife
  15. Java面试题(一)100家大公司java笔试题汇总
  16. 基于Egteks mPower1203仪器和KEYSIGHT N6705仪器的一款智能穿戴产品的低功耗电流测试评估
  17. 操作系统之进程管理相关总结
  18. float类型为什么有6位有效数字
  19. java架构师视频,附源代码
  20. Prolific PL2303 usb 转串口Win8 Win8.1驱动

热门文章

  1. 小程序更新数组操作push、pop、unshift、shift
  2. react 报 Objects are not valid as a React child (found: object with keys {}). If you meant to render.
  3. wdcp虚拟主机管理系统注入漏洞
  4. UVA 11572 唯一的雪花 Unique Snowflakes
  5. Kinect黑客:机械人科技未来的转变者
  6. 结巴分词--关键词抽取
  7. 搞笑很好玩的14个缎子
  8. 机器学习-初级进阶(Thompson 抽样算法 )
  9. 移远M26实现短信接收
  10. Setting语言与输入法列表客制化