——————————————————————————————————————————————————
——————————————————————————————————————————————————
接下是FancyCoverFlowItemWrapper类
package cn.wom.fancycoverflow;
/**
- 倒影特效
/
import android.;
import android.R;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.*;
import android.os.Build;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
/**
- This class has only internal use (package scope).
- <p/>
- It is responsible for applying additional effects to each coverflow item, that can only be applied at view level
- (e.g. color saturation).
- <p/>
- This is a ViewGroup by intention to enable child views in layouts to stay interactive (like buttons) though
- transformed.
- <p/>
- Since this class is only used within the FancyCoverFlowAdapter it doesn't need to check if there are multiple
-
children or not (there can only be one at all times).
*/
@SuppressWarnings("ConstantConditions")
class FancyCoverFlowItemWrapper extends ViewGroup {// =============================================================================
// Private members
// =============================================================================private float saturation;
private boolean isReflectionEnabled = false;
private float imageReflectionRatio;
private int reflectionGap;
private float originalScaledownFactor;
/**
- This is a matrix to apply color filters (like saturation) to the wrapped view.
*/
private ColorMatrix colorMatrix;
/**
- This paint is used to draw the wrapped view including any filters.
*/
private Paint paint;
/**
- This is a cache holding the wrapped view's visual representation.
*/
private Bitmap wrappedViewBitmap;
/**
- This canvas is used to let the wrapped view draw it's content.
*/
private Canvas wrappedViewDrawingCanvas;
// =============================================================================
// Constructor
// =============================================================================public FancyCoverFlowItemWrapper(Context context) {
super(context);
this.init();
}public FancyCoverFlowItemWrapper(Context context, AttributeSet attrs) {
super(context, attrs);
this.init();
}public FancyCoverFlowItemWrapper(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.init();
}private void init() {
this.paint = new Paint();
this.colorMatrix = new ColorMatrix();
// TODO: Define a default value for saturation inside an XML.
this.setSaturation(1);
}// =============================================================================
// Getters / Setters
// =============================================================================void setReflectionEnabled(boolean hasReflection) {
if (hasReflection != this.isReflectionEnabled) {
this.isReflectionEnabled = hasReflection;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { // Turn off hardware acceleration if necessary (reflections won't support it). this.setLayerType(hasReflection ? View.LAYER_TYPE_SOFTWARE : View.LAYER_TYPE_HARDWARE, null); } this.remeasureChildren(); }
}
void setReflectionRatio(float imageReflectionRatio) {
if (imageReflectionRatio != this.imageReflectionRatio) {
this.imageReflectionRatio = imageReflectionRatio;
this.remeasureChildren();
}
}void setReflectionGap(int reflectionGap) {
if (reflectionGap != this.reflectionGap) {
this.reflectionGap = reflectionGap;
this.remeasureChildren();
}
}public void setSaturation(float saturation) {
if (saturation != this.saturation) {
this.saturation = saturation;
this.colorMatrix.setSaturation(saturation);
this.paint.setColorFilter(new ColorMatrixColorFilter(this.colorMatrix));
}
}// =============================================================================
// Supertype overrides
// =============================================================================@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
this.remeasureChildren();// If we have reflection enabled, the original image is scaled down and a reflection is added beneath. Thus, // while maintaining the same height the width decreases and we need to adjust measured width. // WARNING: This is a hack because we do not obey the EXACTLY MeasureSpec mode that we will get mostly. if (this.isReflectionEnabled) { this.setMeasuredDimension((int) (this.getMeasuredWidth() * this.originalScaledownFactor), this.getMeasuredHeight()); }
}
@SuppressLint("DrawAllocation")
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed) {
int measuredWidth = this.getMeasuredWidth();
int measuredHeight = this.getMeasuredHeight();if (this.wrappedViewBitmap == null this.wrappedViewBitmap.getWidth() != measuredWidth this.wrappedViewBitmap.getHeight() != measuredHeight) { this.wrappedViewBitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888); this.wrappedViewDrawingCanvas = new Canvas(this.wrappedViewBitmap); } View child = getChildAt(0); int childWidth = child.getMeasuredWidth(); int childHeight = child.getMeasuredHeight(); int childLeft = (measuredWidth - childWidth) / 2; int childRight = measuredWidth - childLeft; child.layout(childLeft, 0, childRight, childHeight); }
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
protected void dispatchDraw(Canvas canvas) {
View childView = getChildAt(0);if (childView != null) { // If on honeycomb or newer, cache the view. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { if (childView.isDirty()) { childView.draw(this.wrappedViewDrawingCanvas); if (this.isReflectionEnabled) { this.createReflectedImages(); } } } else { childView.draw(this.wrappedViewDrawingCanvas); } } canvas.drawBitmap(this.wrappedViewBitmap, (this.getWidth() - childView.getWidth()) / 2, 0, paint);
}
// =============================================================================
// Methods
// =============================================================================private void remeasureChildren() {
View child = this.getChildAt(0);if (child != null) { // When reflection is enabled calculate proportional scale down factor. final int originalChildHeight = this.getMeasuredHeight(); this.originalScaledownFactor = this.isReflectionEnabled ? (originalChildHeight * (1 - this.imageReflectionRatio) - reflectionGap) / originalChildHeight : 1.0f; final int childHeight = (int) (this.originalScaledownFactor * originalChildHeight); final int childWidth = (int) (this.originalScaledownFactor * getMeasuredWidth()); int heightSpec = MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.AT_MOST); int widthSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.AT_MOST); this.getChildAt(0).measure(widthSpec, heightSpec); }
}
/**
- 用于创建Item的倒影
-
*/
private void createReflectedImages() {
//获取Item的宽度
final int width = this.wrappedViewBitmap.getWidth();
//获取Item的高度
final int height = this.wrappedViewBitmap.getHeight();final Matrix matrix = new Matrix();
matrix.postScale(1, -1);//倒影未显示部分的高度
final int scaledDownHeight = (int) (height * originalScaledownFactor);
//倒影显示部分的高度
final int invertedHeight = height - scaledDownHeight - reflectionGap;
//必须是大于0的数,否则会抛出异常
final int invertedBitmapSourceTop = scaledDownHeight - invertedHeight;
//创建翻转的Bitmap对象
final Bitmap invertedBitmap = Bitmap.createBitmap(this.wrappedViewBitmap, 0, invertedBitmapSourceTop, width, invertedHeight, matrix, true);this.wrappedViewDrawingCanvas.drawBitmap(invertedBitmap, 0, scaledDownHeight + reflectionGap, null);
final Paint paint = new Paint();
//处理用于线性渐变的对象
final LinearGradient shader = new LinearGradient(0, height imageReflectionRatio + reflectionGap, 0, height, 0x70ffffff, 0x00ffffff, Shader.TileMode.CLAMP);
//设置渐变
paint.setShader(shader);
//设置模式
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
//绘制矩形,让渐变在矩形中发生
this.wrappedViewDrawingCanvas.drawRect(0, height (1 - imageReflectionRatio), width, height, paint);
}
}
——————————————————————————————————————————————————
——————————————————————————————————————————————————
最终实现的效果图为
- This is a matrix to apply color filters (like saturation) to the wrapped view.
如果想实现下面的效果图
就要在那个图片的资源的那个类里面做文章。
package cn.wom.fancycoverflow.example;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import cn.wom.fancycoverflow.FancyCoverFlow;
import cn.wom.fancycoverflow.FancyCoverFlowAdapter;
import cn.wom.fancycoverflow.R;
public class ViewGroupExample extends Activity {
// =============================================================================
// Supertype overrides
// =============================================================================
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.layout_inflate_example);
FancyCoverFlow fancyCoverFlow = (FancyCoverFlow) findViewById(R.id.fancyCoverFlow);
fancyCoverFlow.setAdapter(new ViewGroupExampleAdapter());
}
// =============================================================================
// Private classes
// =============================================================================
private static class ViewGroupExampleAdapter extends FancyCoverFlowAdapter {
// =============================================================================
// Private members
// =============================================================================
private int[] images = {R.drawable.image1, R.drawable.image2, R.drawable.image3, R.drawable.image4, R.drawable.image5, R.drawable.image6,};
// =============================================================================
// Supertype overrides
// =============================================================================
@Override
public int getCount() {
return images.length;
}
@Override
public Integer getItem(int i) {
return images[i];
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getCoverFlowItem(int i, View reuseableView, ViewGroup viewGroup) {
CustomViewGroup customViewGroup = null;
if (reuseableView != null) {
customViewGroup = (CustomViewGroup) reuseableView;
} else {
customViewGroup = new CustomViewGroup(viewGroup.getContext());
customViewGroup.setLayoutParams(new FancyCoverFlow.LayoutParams(300, 600));
}
customViewGroup.getImageView().setImageResource(this.getItem(i));
customViewGroup.getTextView().setText(String.format("Item %d", i));
return customViewGroup;
}
}
private static class CustomViewGroup extends LinearLayout {
// =============================================================================
// Child views
// =============================================================================
private TextView textView;
private ImageView imageView;
private Button button;
// =============================================================================
// Constructor
// =============================================================================
private CustomViewGroup(Context context) {
super(context);
this.setOrientation(VERTICAL);
this.textView = new TextView(context);
this.imageView = new ImageView(context);
this.button = new Button(context);
LinearLayout.LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
this.textView.setLayoutParams(layoutParams);
this.imageView.setLayoutParams(layoutParams);
this.button.setLayoutParams(layoutParams);
this.textView.setGravity(Gravity.CENTER);
this.imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
this.imageView.setAdjustViewBounds(true);
this.button.setText("Goto GitHub");
this.button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse("https://davidschreiber.github.com/FancyCoverFlow"));
view.getContext().startActivity(i);
}
});
this.addView(this.textView);
this.addView(this.imageView);
this.addView(this.button);
}
// =============================================================================
// Getters
// =============================================================================
private TextView getTextView() {
return textView;
}
private ImageView getImageView() {
return imageView;
}
}
}