首先我们拿到这三个类:分别是FancyCoverFlow、FancyCoverFlowAdapter、FancyCoverFlowItemWrapper。这三个类分别有不同的含义。
FancyCoverFlow:这个类是控件的主类,要在xml(布局文件)里面写的。
FancyCoverFlowAdapter:这个类是获取图片的资源(当然这个不一定是图片),获取资源的那个类必须要继承FancyCoverFlowAdapter类。里面会有4个方法有点像ListView里面的Item一样。getCount();getItem;getItemId();还有getCoverFlowItem();我要提的一点是里面的布局文件要自己纯代码来写,我试过用View vie = mInflater.inflate(R.layout.xxx,null);来获取里面的布局,这样写的话,无法得到我们想要的结果。我们只能通过纯代码来创建布局。
FancyCoverFlowItemWrapper:这个类的话是设置每个Item的倒影。
好了,如果其他的类都弄好了,接下来就只有调用几个方法就OK了。
比如我在一个MainActivity创建的一个布局文件。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.office.dierchi.MainActivity">
<com.example.office.dierchi.FancyCoverFlow
android:id="@+id/fancycover"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.example.office.dierchi.FancyCoverFlow>
</LinearLayout>
结下来我们只要在MainActivity中简单的设置就OK,我们可以设置未选中的图片的饱和度、未被选中的图片的比例、图片之间的距离、设置图片是否要倒影等等。(这里面要值得注意的是,每个图片的来源都在继承FancyCoverFlowAdapter类里面设置的,还有每张图片的显示的大小也在那里设置imageView.setLayoutParams(new FancyCoverFlow.LayoutParams(500, 680));)
package com.example.office.dierchi;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
public class MainActivity extends AppCompatActivity {
private FancyCoverFlow fancyCoverFlow;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
fancyCoverFlow= (FancyCoverFlow) findViewById(R.id.fancycover);
//设置数据的来源
fancyCoverFlow.setAdapter(new FancyCoverFloeShap());
//设置透明度 未被选中的的透明度
fancyCoverFlow.setUnselectedAlpha(0.3f);
//设置未被选中的饱和度
fancyCoverFlow.setUnselectedSaturation(0.4f);
//设置未被选中的缩放的比例
fancyCoverFlow.setUnselectedScale(0.2f);
//设置图片的距离
fancyCoverFlow.setSpacing(1);
//设置未被选中图片的旋转的角度
fancyCoverFlow.setScaleDownGravity(0.3f);
//3D的倒影
fancyCoverFlow.setReflectionEnabled(true);
fancyCoverFlow.setActionDistance(FancyCoverFlow.ACTION_DISTANCE_AUTO);
}
public class FancyCoverFloeShap extends FancyCoverFlowAdapter{
//设置图片的来源
private int [] images={R.mipmap.image1,R.mipmap.image2,R.mipmap.image3,R.mipmap.image4,R.mipmap.image5,R.mipmap.image6};
@Override
public int getCount() {
return images.length;
}
@Override
public Integer getItem(int position) {
return images[position];
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getCoverFlowItem(int i, View reusableView, ViewGroup parent) {
ImageView imageView = null;
//有可以重用的ImageView对象。直接返回即可
if (reusableView != null) {
imageView = (ImageView) reusableView;
} else {
//如果为空,没有新的ImageView,就创建新的View控件
imageView = new ImageView(parent.getContext());
//设置显示类型,缩放类型 CENTER_INSIDE:在中心内部显示
imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
//设置显示的尺寸
imageView.setLayoutParams(new FancyCoverFlow.LayoutParams(500, 680));
}
//设置图像资源
imageView.setImageResource(this.getItem(i));
return imageView;
}
}
}
好的,现在我把其他的几个类的代码都复制上去。
首先是FancyCoverFlow类
/*
- Copyright 2015 David Schreiber
- 2015 John Paul Nalog
- 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.
*/
package cn.wom.fancycoverflow;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.*;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.Transformation;
import android.widget.Gallery;
import android.widget.SpinnerAdapter;
/**
- 3D画廊的核心实现类
- @author WUPENG
-
*/
@SuppressWarnings("deprecation")
public class FancyCoverFlow extends Gallery {// =============================================================================
// Constants
// =============================================================================public static final int ACTION_DISTANCE_AUTO = Integer.MAX_VALUE;
public static final float SCALEDOWN_GRAVITY_TOP = 0.0f;
public static final float SCALEDOWN_GRAVITY_CENTER = 0.5f;
public static final float SCALEDOWN_GRAVITY_BOTTOM = 1.0f;
// =============================================================================
// Private members
// =============================================================================private float reflectionRatio = 0.4f;
private int reflectionGap = 20;
private boolean reflectionEnabled = false;
/**
- TODO: Doc
*/
private float unselectedAlpha;
/**
- Camera used for view transformation.
*/
private Camera transformationCamera;
/**
- TODO: Doc
*/
private int maxRotation = 75;
/**
- Factor (0-1) that defines how much the unselected children should be scaled down. 1 means no scaledown.
*/
private float unselectedScale;
/**
- TODO: Doc
*/
private float scaleDownGravity = SCALEDOWN_GRAVITY_CENTER;
/**
- Distance in pixels between the transformation effects (alpha, rotation, zoom) are applied.
*/
private int actionDistance;
/**
- Saturation factor (0-1) of items that reach the outer effects distance.
*/
private float unselectedSaturation;
// =============================================================================
// Constructors
// =============================================================================public FancyCoverFlow(Context context) {
super(context);
this.initialize();
}public FancyCoverFlow(Context context, AttributeSet attrs) {
super(context, attrs);
this.initialize();
this.applyXmlAttributes(attrs);
}public FancyCoverFlow(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.initialize();
this.applyXmlAttributes(attrs);
}private void initialize() {
this.transformationCamera = new Camera();
this.setSpacing(0);
}private void applyXmlAttributes(AttributeSet attrs) {
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.FancyCoverFlow);this.actionDistance = a.getInteger(R.styleable.FancyCoverFlow_actionDistance, ACTION_DISTANCE_AUTO); this.scaleDownGravity = a.getFloat(R.styleable.FancyCoverFlow_scaleDownGravity, 1.0f); this.maxRotation = a.getInteger(R.styleable.FancyCoverFlow_maxRotation, 45); this.unselectedAlpha = a.getFloat(R.styleable.FancyCoverFlow_unselectedAlpha, 0.3f); this.unselectedSaturation = a.getFloat(R.styleable.FancyCoverFlow_unselectedSaturation, 0.0f); this.unselectedScale = a.getFloat(R.styleable.FancyCoverFlow_unselectedScale, 0.75f);
}
// =============================================================================
// Getter / Setter
// =============================================================================public float getReflectionRatio() {
return reflectionRatio;
}public void setReflectionRatio(float reflectionRatio) {
if (reflectionRatio <= 0 reflectionRatio > 0.5f) {
throw new IllegalArgumentException("reflectionRatio may only be in the interval (0, 0.5]");
}this.reflectionRatio = reflectionRatio; if (this.getAdapter() != null) { ((FancyCoverFlowAdapter) this.getAdapter()).notifyDataSetChanged(); }
}
public int getReflectionGap() {
return reflectionGap;
}public void setReflectionGap(int reflectionGap) {
this.reflectionGap = reflectionGap;if (this.getAdapter() != null) { ((FancyCoverFlowAdapter) this.getAdapter()).notifyDataSetChanged(); }
}
public boolean isReflectionEnabled() {
return reflectionEnabled;
}public void setReflectionEnabled(boolean reflectionEnabled) {
this.reflectionEnabled = reflectionEnabled;if (this.getAdapter() != null) { ((FancyCoverFlowAdapter) this.getAdapter()).notifyDataSetChanged(); }
}
/**
- Use this to provide a {@link FancyCoverFlowAdapter} to the coverflow. This
- method will throw an {@link ClassCastException} if the passed adapter does not
- subclass {@link FancyCoverFlowAdapter}.
- @param adapter
- 在类中重写类父类的setAdapter方法
- 要求Adapter必须是实现的FancyCoverFlowAdapter的对象或其子类的对象,
-
如果不是这个对象就会抛出异常
*/
@Override
public void setAdapter(SpinnerAdapter adapter) {
if (!(adapter instanceof FancyCoverFlowAdapter)) {
throw new ClassCastException(FancyCoverFlow.class.getSimpleName() + " only works in conjunction with a " + FancyCoverFlowAdapter.class.getSimpleName());
}super.setAdapter(adapter);
}
/**
- Returns the maximum rotation that is applied to items left and right of the center of the coverflow.
- @return
*/
public int getMaxRotation() {
return maxRotation;
}
/**
- Sets the maximum rotation that is applied to items left and right of the center of the coverflow.
- @param maxRotation
*/
public void setMaxRotation(int maxRotation) {
this.maxRotation = maxRotation;
}
/**
- TODO: Write doc
- @return
*/
public float getUnselectedAlpha() {
return this.unselectedAlpha;
}
/**
- TODO: Write doc
- @return
*/
public float getUnselectedScale() {
return unselectedScale;
}
/**
- TODO: Write doc
- @param unselectedScale
*/
public void setUnselectedScale(float unselectedScale) {
this.unselectedScale = unselectedScale;
}
/**
- TODO: Doc
- @return
*/
public float getScaleDownGravity() {
return scaleDownGravity;
}
/**
- TODO: Doc
- @param scaleDownGravity
*/
public void setScaleDownGravity(float scaleDownGravity) {
this.scaleDownGravity = scaleDownGravity;
}
/**
- TODO: Write doc
- @return
*/
public int getActionDistance() {
return actionDistance;
}
/**
- TODO: Write doc
- @param actionDistance
*/
public void setActionDistance(int actionDistance) {
this.actionDistance = actionDistance;
}
/**
- TODO: Write doc
- @param unselectedAlpha
*/
@Override
public void setUnselectedAlpha(float unselectedAlpha) {
super.setUnselectedAlpha(unselectedAlpha);
this.unselectedAlpha = unselectedAlpha;
}
/**
- TODO: Write doc
- @return
*/
public float getUnselectedSaturation() {
return unselectedSaturation;
}
/**
- TODO: Write doc
- @param unselectedSaturation
*/
public void setUnselectedSaturation(float unselectedSaturation) {
this.unselectedSaturation = unselectedSaturation;
}
/**
- 作用:当Gallery绘制每一个Item时会调用该方法来产生一些动画的特效(实现原理:内部是一个矩阵的转换)
- 该方法中包括:
- 1:透明度
- 2:饱和度
- 3:旋转
-
4:缩放
*/
@Override
protected boolean getChildStaticTransformation(View child, Transformation t) {
// 获取当前Item对象
FancyCoverFlowItemWrapper item = (FancyCoverFlowItemWrapper) child;// 如果版本大于等于16时 刷新页面 Android本身原因
if (android.os.Build.VERSION.SDK_INT >= 16) {
item.invalidate();
}
//获取控件的宽度
final int coverFlowWidth = this.getWidth();
//获取控件宽度的一半
final int coverFlowCenter = coverFlowWidth / 2;
//获取Item的宽度(中心横坐标)
final int childWidth = item.getWidth();
//获取Item的高度
final int childHeight = item.getHeight();
//获取Item的中心位置
final int childCenter = item.getLeft() + childWidth / 2;/**
- 每一个Item距离中心的距离
- 如果等于设置的常量
*/
final int actionDistance = (this.actionDistance == ACTION_DISTANCE_AUTO) ?
(int) ((coverFlowWidth + childWidth) / 2.0f) : this.actionDistance;// 保证这个变量的值-1.0到1.0之间 item距离中心点越远,该值越大
final float effectsAmount = Math.min(1.0f, Math.max(-1.0f, (1.0f / actionDistance) * (childCenter - coverFlowCenter)));// 清除以前的变换
t.clear();
//设置类型,同时进行alpha和matrix变换
t.setTransformationType(Transformation.TYPE_BOTH);// 透明度变换
if (this.unselectedAlpha != 1) {
final float alphaAmount = (this.unselectedAlpha - 1) * Math.abs(effectsAmount) + 1;
t.setAlpha(alphaAmount);
}// 饱和度变换
if (this.unselectedSaturation != 1) {
final float saturationAmount = (this.unselectedSaturation - 1) * Math.abs(effectsAmount) + 1;
item.setSaturation(saturationAmount);
}final Matrix imageMatrix = t.getMatrix();
// 旋转变化.
if (this.maxRotation != 0) {
//计算旋转角度(越远离中心点的item,旋转角度就会越大)
final int rotationAngle = (int) (-effectsAmount * this.maxRotation);
this.transformationCamera.save();
this.transformationCamera.rotateY(rotationAngle);
this.transformationCamera.getMatrix(imageMatrix);
this.transformationCamera.restore();
}// 缩放变换.
if (this.unselectedScale != 1) {
//远离中心点的item就会变得更小
final float zoomAmount = (this.unselectedScale - 1) Math.abs(effectsAmount) + 1;
// 平移的相对水平距离
final float translateX = childWidth / 2.0f;
// 平移的相对垂直距离
final float translateY = childHeight this.scaleDownGravity;
//将锚点移动到坐标原点(左下角)
imageMatrix.preTranslate(-translateX, -translateY);
//开始缩放
imageMatrix.postScale(zoomAmount, zoomAmount);
//将锚点重新移动到中心点
imageMatrix.postTranslate(translateX, translateY);
}return true;
}
// =============================================================================
// Public classes
// =============================================================================public static class LayoutParams extends Gallery.LayoutParams {
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
}public LayoutParams(int w, int h) { super(w, h); } public LayoutParams(ViewGroup.LayoutParams source) { super(source); }
}
}
——————————————————————————————————————————————————
如果就这样直接复制FancyCoverFlow类的话就会报错,因为在value里面加一个attr.xml文件。里面的文件内容如下:
< ?xml version="1.0" encoding="utf-8"?>
< resources>
< declare-styleable name="FancyCoverFlow">
< attr name="unselectedAlpha" format="float"/>
< attr name="unselectedSaturation" format="float"/>
< attr name="unselectedScale" format="float"/>
< attr name="maxRotation" format="integer"/>
< attr name="scaleDownGravity" format="float"/>
< attr name="actionDistance" format="integer">
< enum name="auto" value="2147483647" />
< /attr>
< /declare-styleable>
< /resources>
—————————————————————————————————————————————————— - TODO: Doc
接下是FancyCoverFlowAdapter类
package cn.wom.fancycoverflow;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
/**
- 3D画廊的核心实现类Adapter
- @author WUPENG
-
*/
public abstract class FancyCoverFlowAdapter extends BaseAdapter {// =============================================================================
// Supertype overrides
// =============================================================================@Override
public final View getView(int i, View reusableView, ViewGroup viewGroup) {
FancyCoverFlow coverFlow = (FancyCoverFlow) viewGroup;View wrappedView = null; FancyCoverFlowItemWrapper coverFlowItem; if (reusableView != null) { coverFlowItem = (FancyCoverFlowItemWrapper) reusableView; wrappedView = coverFlowItem.getChildAt(0); coverFlowItem.removeAllViews(); } else { coverFlowItem = new FancyCoverFlowItemWrapper(viewGroup.getContext()); } wrappedView = this.getCoverFlowItem(i, wrappedView, viewGroup); if (wrappedView == null) { throw new NullPointerException("getCoverFlowItem() was expected to return a view, but null was returned."); } //实现3D倒影的效果 final boolean isReflectionEnabled = coverFlow.isReflectionEnabled(); coverFlowItem.setReflectionEnabled(isReflectionEnabled); if(isReflectionEnabled) { coverFlowItem.setReflectionGap(coverFlow.getReflectionGap()); coverFlowItem.setReflectionRatio(coverFlow.getReflectionRatio()); } coverFlowItem.addView(wrappedView); coverFlowItem.setLayoutParams(wrappedView.getLayoutParams()); return coverFlowItem;
}
// =============================================================================
// Abstract methods
// =============================================================================public abstract View getCoverFlowItem(int position, View reusableView, ViewGroup parent);
}
共同学习,写下你的评论
评论加载中...
作者其他优质文章