Android的改进版CoverFlow效果控件

最近研究了一下如何在Android上实现CoverFlow效果的控件,其实早在2010年,就有Neil Davies开发并开源出了这个控件,Neil大神的这篇博客地址http://www.inter-fuser.com/2010/02/android-coverflow-widget-v2.html。首先是阅读源码,弄明白核心思路后,自己重新写了一遍这个控件,并加入了详尽的注释以便日后查阅;而后在使用过程中,发现了有两点可以改进:(1)初始图片位于中间,左边空了一半空间,比较难看,可以改为重复滚动地展示、(2)由于图片一开始就需要加载出来,所以对内存开销较大,很容易OOM,需要对图片的内存空间进行压缩。

这个自定义控件包括4个部分,用于创建及提供图片对象的ImageAdapter,计算图片旋转角度等的自定义控件GalleryFlow,压缩采样率解析Bitmap的工具类BitmapScaleDownUtil,以及承载自定义控件的Gallery3DActivity。

首先是ImageAdapter,代码如下:

package pym.test.gallery3d.widget;

import pym.test.gallery3d.util.BitmapScaleDownUtil;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Shader.TileMode;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Gallery;
import android.widget.ImageView;

/**
 * @author pengyiming
 * @date 2013-9-30
 * @function GalleryFlow适配器
 */
public class ImageAdapter extends BaseAdapter
{
    /* 数据段begin */
    private final String TAG = "ImageAdapter";
    private Context mContext;

    //图片数组
    private int[] mImageIds ;
    //图片控件数组
    private ImageView[] mImages;
    //图片控件LayoutParams
    private GalleryFlow.LayoutParams mImagesLayoutParams;
    /* 数据段end */

    /* 函数段begin */
    public ImageAdapter(Context context, int[] imageIds)
    {
        mContext = context;
        mImageIds = imageIds;
        mImages = new ImageView[mImageIds.length];
        mImagesLayoutParams = new GalleryFlow.LayoutParams(Gallery.LayoutParams.WRAP_CONTENT, Gallery.LayoutParams.WRAP_CONTENT);
    }

    /**
     * @function 根据指定宽高创建待绘制的Bitmap,并绘制到ImageView控件上
     * @param imageWidth
     * @param imageHeight
     * @return void
     */
    public void createImages(int imageWidth, int imageHeight)
    {
        // 原图与倒影的间距5px
        final int gapHeight = 5;

        int index = 0;
        for (int imageId : mImageIds)
        {
            /* step1 采样方式解析原图并生成倒影 */
            // 解析原图,生成原图Bitmap对象
//            Bitmap originalImage = BitmapFactory.decodeResource(mContext.getResources(), imageId);
            Bitmap originalImage = BitmapScaleDownUtil.decodeSampledBitmapFromResource(mContext.getResources(), imageId, imageWidth, imageHeight);
            int width = originalImage.getWidth();
            int height = originalImage.getHeight();

            // Y轴方向反向,实质就是X轴翻转
            Matrix matrix = new Matrix();
            matrix.setScale(1, -1);
            // 且仅取原图下半部分创建倒影Bitmap对象
            Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0, height / 2, width, height / 2, matrix, false);

            /* step2 绘制 */
            // 创建一个可包含原图+间距+倒影的新图Bitmap对象
            Bitmap bitmapWithReflection = Bitmap.createBitmap(width, (height + gapHeight + height / 2), Config.ARGB_8888);
            // 在新图Bitmap对象之上创建画布
            Canvas canvas = new Canvas(bitmapWithReflection);
            // 抗锯齿效果
            canvas.setDrawFilter(new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG));
            // 绘制原图
            canvas.drawBitmap(originalImage, 0, 0, null);
            // 绘制间距
            Paint gapPaint = new Paint();
            gapPaint.setColor(0xFFCCCCCC);
            canvas.drawRect(0, height, width, height + gapHeight, gapPaint);
            // 绘制倒影
            canvas.drawBitmap(reflectionImage, 0, height + gapHeight, null);

            /* step3 渲染 */
            // 创建一个线性渐变的渲染器用于渲染倒影
            Paint paint = new Paint();
            LinearGradient shader = new LinearGradient(0, height, 0, (height + gapHeight + height / 2), 0x70ffffff, 0x00ffffff, TileMode.CLAMP);
            // 设置画笔渲染器
            paint.setShader(shader);
            // 设置图片混合模式
            paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));
            // 渲染倒影+间距
            canvas.drawRect(0, height, width, (height + gapHeight + height / 2), paint);

            /* step4 在ImageView控件上绘制 */
            ImageView imageView = new ImageView(mContext);
            imageView.setImageBitmap(bitmapWithReflection);
            imageView.setLayoutParams(mImagesLayoutParams);
            // 打log
            imageView.setTag(index);

            /* step5 释放heap */
            originalImage.recycle();
            reflectionImage.recycle();
//          bitmapWithReflection.recycle();

            mImages[index++] = imageView;
        }
    }

    @Override
    public int getCount()
    {
        return Integer.MAX_VALUE;
    }

    @Override
    public Object getItem(int position)
    {
        return mImages[position];
    }

    @Override
    public long getItemId(int position)
    {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent)
    {
        return mImages[position % mImages.length];
    }
    /* 函数段end */
}

查看本栏目更多精彩内容:http://www.bianceng.cnhttp://www.bianceng.cn/OS/extra/

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索android
, android canvas
, 控件
, imageview
, bitmap
, graphics
, import
, coverflow gallery
, imageview控件
, 图片压缩canvas
, imageview图片android
, imageview代码控件gridview
, 图片控件android
height
android coverflow、android cover flow、android实现coverflow、androidd coverflow、coverflow,以便于您获取更多的相关知识。

时间: 2024-08-29 07:18:01

Android的改进版CoverFlow效果控件的相关文章

分享Android仿刮奖效果控件_Android

本文实例为大家分享了Android刮刮卡效果控件,供大家参考,具体内容如下 刮刮卡类: package com.reyo.view; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.Canvas; import android.graphics.Paint; import android.gr

android 中win10 使用uwp控件实现进度条Marquez效果

本文将告诉大家,如何做一个带文字的进度条,这个进度条可以用在游戏,现在我做的挂机游戏就使用了他. 如何做上图的效果,实际需要的是两个控件,一个是显示文字 的 TextBlock 一个是进度条. 那么如何让 文字和左边的距离变化?使用 TranslateTransform 看起来 Marquez 的界面就是: <ProgressBar x:Name="Mcdon" Maximum="100" Minimum="0" Value="2

Android编程开发之Spinner控件用法实例分析_Android

本文实例讲述了Android编程开发之Spinner控件用法.分享给大家供大家参考,具体如下: 下拉列表 Spinner,Spinner是一个每次只能选择所有项的一个项的控件.它的项来自于与之相关联的适配器中. Spinner的使用,可以极大提高用户的体验性.当需要用户选择的时候,可以提供一个下拉列表将所有可选的项列出来.供用户选择. 一.使用数组作为数据源 布局文件: <RelativeLayout xmlns:android="http://schemas.android.com/ap

Android高效率编码-细节,控件,架包,功能,工具,开源汇总,你想要的这里都有

Android高效率编码-细节,控件,架包,功能,工具,开源汇总 其实写博客的初衷也并不是说什么分享技术,毕竟咱还只是个小程序员,最大的目的就是对自我的知识积累,以后万一编码的时候断片了,也可以翻出来看看,这样子对自己也有好处,所以今天就汇总一下一些需要的东西.多图来了,加油! 一.游戏 小熊打字,我刚接触电脑练习打字的时候用到的 下载地址:http://download.csdn.net/detail/qq_26787115/9365721 二.色彩 这张颜色表上的颜色都太赞了 三.控件 1.

Android开发技巧之ViewStub控件惰性装载_Android

在4.5.6节介绍过一个<include>标签,该标签可以在布局文件中引用另外一个布局文件,并可以覆盖被引用布局文件根节点所有与布局相关的属性,也就是以android:layout开头的属性.通过<include>标签可以将一个非常庞大的布局文件分解成若干个较小的布局文件,而且这些小的布局文件也可以被多次引用,从而达到一个重用的目的. <include>标签固然很好用,但有一个问题,就是布局文件中的控件并不一定在程序启动时全都用到,有一些控件只在特定的情况下才会被使用到

Android编程开发之TextView控件用法(2种方法)_Android

本文实例讲述了Android编程开发之TextView控件用法.分享给大家供大家参考,具体如下: 这里我们会讲讲常用控件的使用. 在今后的大多数章节里面也是一样的,我们会具体的说说某些控件的用法.因为只要把这些控件组合在一起它们就是一个应用了. 好吧我们直接看看这个控件怎么用. 细心的同学会发现,其实这个控件的内容是定义在values文件夹里面的strings.xml中的. 那么我们只需要给它加一段代码: 复制代码 代码如下: <string name="test">Wel

总结Android中MD风格相关控件_Android

要使用MD风格控件,首先需要在Gradle中加入Support Design Library,例如: compile 'com.android.support:design:24.1.1' 一.CoordinatorLayout 1.CoordinatorLayout + AppBarLayout 布局文件代码如下: <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.

Android自定义View之组合控件实现类似电商app顶部栏_Android

本文实例为大家分享了Android自定义View之组合控件,仿电商app顶部栏的相关代码,供大家参考,具体内容如下 效果图: 分析:左右两边可以是TextView和Button,设置drawableTop即可,中间的看着像是EditText,但是用过淘宝天猫等类似app的话会发现点击搜索不是在当前Activit进行搜索的,是跳转到另外的页面进行的,所以用TextView然后设置背景即可. 实现流程 参数列表: 设置属性文件:values下建立attrs.xml文件,添加需要自定义的属性. <?x

Android自定义滑动接听电话控件组实例_Android

本文根据组件开发思想,首先介绍android自定义控件,然后将自定义的控件封装为jar包.最为实现滑动接听电话控件组. 一.目录结构 二.运行效果 三.代码实现 首先,自定义一个类IncomingPhone继承RelativeLayout public IncomingPhone(Context context, AttributeSet attrs) { super(context, attrs); mContext = context; TextView textView = new Tex