Android CoverFlow

实现Android Coverflow效果的完整指南 在Android开发中,Gallery控件是一个重要的组件,用于创建水平滚动的图片画廊。尽管现在被的和等更灵活的方案所部分取代,但在某些特定的应用场景中,Gallery依然有其独特的魅力和价值。本章将介绍Gallery控件的基本概念、功能特点以及历史地位,为后续更深入的自定义和优化打下基础。1.1 历史地位与功能特点Gallery组件最初是Android的一部分,它允许用户在水平方向上浏览一系列的视图,通常用于图片浏览场景。 阅读详情

It's been a while now and I've been pretty busy with life, work, and other things, but at last here's a new version of the coverflow widget that I released a while back. There's not really much new functionality here, but I have cut down the amount of code needed by a lot. Gone are the CoverAbsSpinner and the CoverAdapterView classes and now we are left with just the CoverFlow class weighing in at less than 200 lines of code. Of course, you still have to instantiate it and populate it using an ImageAdapter so I'll also include the activity class for doing those tasks as well.


Background
The basic idea is that the Coverflow widget works very much like the standard Android Gallery widget, but with the addition of the rotation of the images. For more background information on the Coverflow widget see my original post  here . 

How to use
In your Android project create a package called com.example.coverflow, and in this place the  CoverFlow  class. Now all you need is an activity to instantiate the Coverflow widget in this example the activity class is called  CoverflowExample .  CoverFlowExample  simply extends Activity and instantiates a Coverflow class in it's  onCreate  method. It also has an internal Class,  ImageAdapter  which we use as the adapter for the Coverflow widget, much as we would for a Gallery widget. It is also possible to use the Coverflow widget when it is specified in an XML layout file.


The  CoverFlow  and  CoverflowExample  classes are here:

/*
 * Copyright (C) 2010 Neil Davies
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * This code is base on the Android Gallery widget and was Created 
 * by Neil Davies neild001 'at' gmail dot com to be a Coverflow widget
 * 
 * @author Neil Davies
 */
package com.example.coverflow;


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 CoverFlow extends Gallery {

    /**
     * Graphics Camera used for transforming the matrix of ImageViews
     */
    private Camera mCamera = new Camera();

    /**
     * The maximum angle the Child ImageView will be rotated by
     */    
    private int mMaxRotationAngle = 60;
    
    /**
     * The maximum zoom on the centre Child
     */
    private int mMaxZoom = -120;
    
    /**
     * The Centre of the Coverflow 
     */   
    private int mCoveflowCenter;
   
 public CoverFlow(Context context) {
  super(context);
  this.setStaticTransformationsEnabled(true);
 }

 public CoverFlow(Context context, AttributeSet attrs) {
  super(context, attrs);
        this.setStaticTransformationsEnabled(true);
 }
 
  public CoverFlow(Context context, AttributeSet attrs, int defStyle) {
   super(context, attrs, defStyle);
   this.setStaticTransformationsEnabled(true);   
  }
  
    /**
     * Get the max rotational angle of the image
  * @return the mMaxRotationAngle
  */
 public int getMaxRotationAngle() {
  return mMaxRotationAngle;
 }

 /**
  * Set the max rotational angle of each image
  * @param maxRotationAngle the mMaxRotationAngle to set
  */
 public void setMaxRotationAngle(int maxRotationAngle) {
  mMaxRotationAngle = maxRotationAngle;
 }

 /**
  * Get the Max zoom of the centre image
  * @return the mMaxZoom
  */
 public int getMaxZoom() {
  return mMaxZoom;
 }

 /**
  * Set the max zoom of the centre image
  * @param maxZoom the mMaxZoom to set
  */
 public void setMaxZoom(int maxZoom) {
  mMaxZoom = maxZoom;
 }

 /**
     * Get the Centre of the Coverflow
     * @return The centre of this Coverflow.
     */
    private int getCenterOfCoverflow() {
        return (getWidth() - getPaddingLeft() - getPaddingRight()) / 2 + getPaddingLeft();
    }
    
    /**
     * Get the Centre of the View
     * @return The centre of the given view.
     */
    private static int getCenterOfView(View view) {
        return view.getLeft() + view.getWidth() / 2;
    }  
    /**
  * {@inheritDoc}
  *
  * @see #setStaticTransformationsEnabled(boolean) 
  */ 
    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);
  
        if (childCenter == mCoveflowCenter) {
            transformImageBitmap((ImageView) child, t, 0);
        } else {      
            rotationAngle = (int) (((float) (mCoveflowCenter - childCenter)/ childWidth) *  mMaxRotationAngle);
            if (Math.abs(rotationAngle) > mMaxRotationAngle) {
             rotationAngle = (rotationAngle < 0) ? -mMaxRotationAngle : mMaxRotationAngle;   
            }
            transformImageBitmap((ImageView) child, t, rotationAngle);         
        }    
             
  return true;
 }

 /**
  * This is called during layout when the size of this view has changed. If
  * you were just added to the view hierarchy, you're called with the old
  * values of 0.
  *
  * @param w Current width of this view.
  * @param h Current height of this view.
  * @param oldw Old width of this view.
  * @param oldh Old height of this view.
     */
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
      mCoveflowCenter = getCenterOfCoverflow();
      super.onSizeChanged(w, h, oldw, oldh);
     }
  
     /**
      * Transform the Image Bitmap by the Angle passed 
      * 
      * @param imageView ImageView the ImageView whose bitmap we want to rotate
      * @param t transformation 
      * @param rotationAngle the Angle by which to rotate the Bitmap
      */
     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);
                     
      mCamera.translate(0.0f, 0.0f, 100.0f);
         
      //As the angle of the view gets less, zoom in     
      if ( rotation < mMaxRotationAngle ) {
       float zoomAmount = (float) (mMaxZoom +  (rotation * 1.5));
       mCamera.translate(0.0f, 0.0f, zoomAmount);          
      } 
      
      mCamera.rotateY(rotationAngle);
      mCamera.getMatrix(imageMatrix);               
      imageMatrix.preTranslate(-(imageWidth/2), -(imageHeight/2)); 
      imageMatrix.postTranslate((imageWidth/2), (imageHeight/2));
      mCamera.restore();
 }
}
Demo:
/*
 * Copyright (C) 2010 Neil Davies
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * This code is base on the Android Gallery widget and was Created 
 * by Neil Davies neild001 'at' gmail dot com to be a Coverflow widget
 * 
 * @author Neil Davies
 */
package com.example.coverflow;

import java.io.FileInputStream;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuffXfermode;
import android.graphics.Bitmap.Config;
import android.graphics.PorterDuff.Mode;
import android.graphics.Shader.TileMode;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;

public class CoverFlowExample extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);
     
     CoverFlow coverFlow;
     coverFlow = new CoverFlow(this);
     
     coverFlow.setAdapter(new ImageAdapter(this));

     ImageAdapter coverImageAdapter =  new ImageAdapter(this);
     
     //coverImageAdapter.createReflectedImages();
     
     coverFlow.setAdapter(coverImageAdapter);
     
     coverFlow.setSpacing(-25);
     coverFlow.setSelection(4, true);
     coverFlow.setAnimationDuration(1000);
     
     
     setContentView(coverFlow);
    }
}


Adapter:
 public class ImageAdapter extends BaseAdapter {
     int mGalleryItemBackground;
     private Context mContext;

     private FileInputStream fis;
        
     private Integer[] mImageIds = {
       R.drawable.kasabian_kasabian,
             R.drawable.starssailor_silence_is_easy,
             R.drawable.killers_day_and_age,
             R.drawable.garbage_bleed_like_me,
             R.drawable.death_cub_for_cutie_the_photo_album,
             R.drawable.kasabian_kasabian,
             R.drawable.massive_attack_collected,
             R.drawable.muse_the_resistance,
             R.drawable.starssailor_silence_is_easy
     };

     private ImageView[] mImages;
     
     public ImageAdapter(Context c) {
      mContext = c;
      mImages = new ImageView[mImageIds.length];
     }
  public boolean createReflectedImages() {
          //The gap we want between the reflection and the original image
          final int reflectionGap = 4;
          
          
          int index = 0;
          for (int imageId : mImageIds) {
        Bitmap originalImage = BitmapFactory.decodeResource(getResources(), 
          imageId);
           int width = originalImage.getWidth();
           int height = originalImage.getHeight();
           
     
           //This will not scale but will flip on the Y axis
           Matrix matrix = new Matrix();
           matrix.preScale(1, -1);
           
           //Create a Bitmap with the flip matrix applied to it.
           //We only want the bottom half of the image
           Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0, height/2, width, height/2, matrix, false);
           
               
           //Create a new bitmap with same width but taller to fit reflection
           Bitmap bitmapWithReflection = Bitmap.createBitmap(width 
             , (height + height/2), Config.ARGB_8888);
         
          //Create a new Canvas with the bitmap that's big enough for
          //the image plus gap plus reflection
          Canvas canvas = new Canvas(bitmapWithReflection);
          //Draw in the original image
          canvas.drawBitmap(originalImage, 0, 0, null);
          //Draw in the gap
          Paint deafaultPaint = new Paint();
          canvas.drawRect(0, height, width, height + reflectionGap, deafaultPaint);
          //Draw in the reflection
          canvas.drawBitmap(reflectionImage,0, height + reflectionGap, null);
          
          //Create a shader that is a linear gradient that covers the reflection
          Paint paint = new Paint(); 
          LinearGradient shader = new LinearGradient(0, originalImage.getHeight(), 0, 
            bitmapWithReflection.getHeight() + reflectionGap, 0x70ffffff, 0x00ffffff, 
            TileMode.CLAMP); 
          //Set the paint to use this shader (linear gradient)
          paint.setShader(shader); 
          //Set the Transfer mode to be porter duff and destination in
          paint.setXfermode(new PorterDuffXfermode(Mode.DST_IN)); 
          //Draw a rectangle using the paint with our linear gradient
          canvas.drawRect(0, height, width, 
            bitmapWithReflection.getHeight() + reflectionGap, paint); 
          
          ImageView imageView = new ImageView(mContext);
          imageView.setImageBitmap(bitmapWithReflection);
          imageView.setLayoutParams(new CoverFlow.LayoutParams(120, 180));
          imageView.setScaleType(ScaleType.MATRIX);
          mImages[index++] = imageView;
          
          }
       return true;
  }

     public int getCount() {
         return mImageIds.length;
     }

     public Object getItem(int position) {
         return position;
     }

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

     public View getView(int position, View convertView, ViewGroup parent) {

      //Use this code if you want to load from resources
         ImageView i = new ImageView(mContext);
         i.setImageResource(mImageIds[position]);
         i.setLayoutParams(new CoverFlow.LayoutParams(130, 130));
         i.setScaleType(ImageView.ScaleType.CENTER_INSIDE); 
         
         //Make sure we set anti-aliasing otherwise we get jaggies
         BitmapDrawable drawable = (BitmapDrawable) i.getDrawable();
         drawable.setAntiAlias(true);
         return i;
      
      //return mImages[position];
     }
   /** Returns the size (0.0f to 1.0f) of the views 
      * depending on the 'offset' to the center. */ 
      public float getScale(boolean focused, int offset) { 
        /* Formula: 1 / (2 ^ offset) */ 
          return Math.max(0, 1.0f / (float)Math.pow(2, Math.abs(offset))); 
      } 

 }


Code explanation
The  CoverflowExample  Code contains some extra code for creating reflections of the images, but apart from this is a standard activity class of the kind used with the Gallery widget.

The  CoverFlow  class extends the Gallery widget , but now we override a few methods to allow us to transform the images before they are displayed. The most important method that we override is the  getChildStaticTransformation  method. Here I have to say thank you to a user called Nerdrow on the Android developers group who first showed me an example of overriding this method.  By setting  setStaticTransformationsEnabled  in the constructors, we are telling the parent ViewGroup of the Coverflow class to invoke  getChildStaticTransformation  every time one of our images in drawn. In  getChildStaticTransformation  we simply calculate and apply a rotation and scale to the ImageView depending on it's position relative to the centre of the Coverflow widget. We also override the  onSizeChanged  method. This method is called every time the widget changes size e.g. when we change the orientation of the phone from portrait to landscape. In the  onSizeChanged  method we just get the centre position of the coverflow widget. There are also a few parameters that we can set,  mZoomMax  controls the maximum zoom of the central image and  mMaxRotationAngle  sets the maximum rotation angle of each image.

参考链接:

http://www.inter-fuser.com/2010/02/android-coverflow-widget-v2.html

http://www.eoeandroid.com/thread-29728-1-1.html


上述代码后半段的显示顺序有问题,需要重写Gallery的getChildDrawingOrder方法。

@Override
protected int getChildDrawingOrder(int childCount, int i)
{
	int mFirstPosition = getFirstVisiblePosition();
	int mSelectedPosition = getSelectedItemPosition();
	int selectedIndex = mSelectedPosition - mFirstPosition;

	if (i == 0)
	{
		lastPosition = 0;
	}

	int ret = 0;
	if (selectedIndex < 0)
	{
		return i;
	}

	if (i == childCount - 1)
	{
		ret = selectedIndex;
	}
	else if (i >= selectedIndex)
	{
		lastPosition++;
		ret = childCount - lastPosition;
	}
	else
	{
		ret = i;
	}

	return ret;
}




Android中实现coverflow效果 使用Android中的Gallery控件实现炫酷coverflow效果的图片展示 立即下载

相关推荐

Android版仿iOS的CoverFlow效果

Android版仿iOS的CoverFlow效果

Android-Coverflow 开源项目使用教程

Android-Coverflow 是一个为 Android 平台设计的精美封面流库,基于 ViewPager 实现。它允许开发者轻松创建具有封面流效果的界面,适用于展示图片、卡片等内容的场景。该项目在 GitHub 上开源,由 Hugo Yu 开发并维护。 ## 2、项目快速启动 ### 2.1 添加依赖 首先,将 JitPack 仓库添加到项目的 `build.gradle` 文件中:

gitblog_00327的博客 1025

Android-Coverflow,android漂亮的coverflow库.zip

基于viewpager的android平台漂亮的封面流程。

Android实现CoverFlow效果

先上一张效果图: 上代码,看了代码什么都明白 CoverFlow从Gallery继承过来 001 package com.coverflow;  002    003 import android.content.Context;  004 import android.graphics.Camera;  005 import android.

ywq5914251的专栏 483

android轮播CoverFlow流畅Demo

android CoverFlow轮播Demo,效果流畅,变换平滑;代码是面向TV应用的,当前可以在720P,1080P盒子或手机上正常运行,盒子上直接按遥控器的左右按键即可进行图片的切换,手机上则可以点击触摸按钮“Left"和"Right"进行操作。

Android改进版CoverFlow效果控件无限循环

Android改进版CoverFlow效果控件无限循环

android coverflow xml,Android-Coverflow 效果

http://blog.youkuaiyun.com/Android-CoverFlowA beautiful cover flow for android platform , base on ViewPager.GIF BuildStep 1. Add the JitPack repository to your build fileallprojects {repositories {...maven ...

weixin_39965490的博客 166

android 实现Coverflow

这是一个android平台的仿iphone的图片浏览demo,本人从网上学习,已经改好,适合初学者。

Android-Coverflow 效果

Android-Coverflow 效果

qq_43668118的博客 686

SAP OBYC自动过账全解析:从BSX到WRX的会计科目配置指南

本文深入解析SAP OBYC自动过账功能,从BSX到WRX的会计科目配置全流程,涵盖评估分组代码、事务码和评估类等核心概念。通过实战案例展示如何实现库存变动到财务过账的自动化流转,提升企业财务数据的准确性和效率。

weixin_29239279的博客 418

【Apollo规划模块探秘】—— 场景(Scenario)驱动的决策引擎

本文深入解析了Apollo自动驾驶平台规划模块的核心机制——场景(Scenario)驱动的决策引擎。文章通过类比日常驾驶,阐述了规划模块如何像经验丰富的司机一样,根据不同的路况(如车道跟随、无保护左转)切换不同的“驾驶模式”。重点剖析了场景管理器(ScenarioManager)如何基于感知信息进行场景判断与切换,以及“场景-阶段-任务”双层状态机如何精密协作,实现灵活、高效且安全的轨迹规划。

rnn9storyteller的博客 278

Android-Coverflow

git地址:https://github.com/crosswall/Android-Coverflow Android-CoverFlow A beautiful cover flow for android platform , base on ViewPager. Demo Vedio GIF Thanks vincent-pa

chenhuakang的博客 1827

Stata实战:DID平行趋势检验完整操作指南(附reghdfe+coefplot代码)

本文提供了一份使用Stata进行DID平行趋势检验的完整实战指南。文章详细讲解了从数据准备、生成相对时间变量,到利用reghdfe命令构建动态效应模型,以及使用coefplot命令进行结果可视化的全流程操作。核心在于通过检验政策前交互项的显著性,验证处理组与对照组是否满足平行趋势假设,为后续因果推断奠定可靠基础。

weixin_29231725的博客 1380

【Android】Coverflow Widget

效果预览: 实现代码: CoverFlow.java /* * Copyright (C) 2010 Neil Davies * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with th

YING 1148

Vue 前端导出页面A4大小pdf,Vue前端导出pdf自动切割换页不切割内容 Vue导出页面pdf自动分页和添加页码 导出的pdf提高清晰度

【代码】Vue 前端导出页面A4大小pdf,Vue前端导出pdf自动切割换页不切割内容 Vue导出页面pdf自动分页和添加页码 导出的pdf提高清晰度。

weixin_41346436的博客 1797

直击高频编程考点:字符串知识及经典算法题总结

字符串相关基本练习题总结(最长公共子串、最长回文子串、最长无重复字符子串、最小覆盖子串、字符串相乘、中文数字表达转实际数字格式等)

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 172万+

android coverflow xml,Android笔记:CoverFlow相关

====================效果一,修改getChildDrawingOrder方法=================================// 重载视图显示顺序让左到中间显示,再到右到中间显示protected int getChildDrawingOrder(int childCount, int i){// long t = getSelectedItemId();//...

weixin_35068573的博客 170

VMware如何安装img镜像,VMware如何安装openwrt软路由(含相关工具镜像)

VMware如何安装img镜像,VMware如何安装openwrt软路由(含相关工具镜像)

XiaoqiangClub的博客 4005

Android Coverflow Widget V2

Android Coverflow Widget V2 http://www.inter-fuser.com/2010/02/android-coverflow-widget-v2.html It's been a while now and I've been pretty busy with life, work, and other things, but at last here's a new version of the coverflow widget that I release

zhjp4295216的专栏 1568

UNet改进(24):注意力机制-从基础原理到高级融合策略

本文系统探讨了如何通过引入各类注意力机制增强UNet在医学图像分割中的性能。文章分为基础篇、进阶篇和高级篇三个层级:基础篇介绍了时序注意力、可变形注意力、分层注意力等8种基础机制;进阶篇提出了5种混合注意力设计;高级篇则探讨了全局+局部+多尺度等复杂组合机制。实验表明,这些注意力模块在心脏MRI、肺部感染等任务中能提升2-15%的分割精度。文章还提供了硬件适配建议和完整实现代码,为研究者提供了全面的技术参考。未来方向包括NAS优化、量子注意力等前沿探索,为UNet在医疗影像等领域的应用革新提供了理论指导。

2501_91516851的博客 764

鸿宇多用户商城user.php RCE漏洞复现

鸿宇多用户商城 user.php 存在任意命令执行漏洞,攻击者可通过该漏洞在服务器端任意执行代码,写入后门,获取服务器权限,进而控制整个web服务器。

0xSec 1621

Android-Coverflow进阶:实现联动ViewPager的同步滚动效果

Android-Coverflow是一款功能强大的Android封面流库,它基于ViewPager实现,能够为你的应用添加炫酷的3D封面浏览效果。今天我们将深入探讨如何利用这个库实现两个ViewPager的联动同步滚动功能,让你的应用界面更加流畅和专业。😊 ## 📱 什么是Android-Coverflow封面流库? Android-Coverflow是一个专门为Android平台设计的封

gitblog_00377的博客 431

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

上一篇: Android 安卓 ViewPager中使用Gallery!
下一篇: android系统信息(内存、cpu、sd卡、电量、版本)获取
nevercool
博客等级 码龄20年 4粉丝 2原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值