package com.barcicki.trio.views; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.Path; import android.graphics.PointF; import android.graphics.RectF; import android.util.AttributeSet; import android.view.View; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; import android.view.animation.AnimationUtils; import android.widget.ImageView; import com.barcicki.trio.R; import com.barcicki.trio.core.Card; import com.barcicki.trio.core.CardFlipAnimation; import com.barcicki.trio.core.CardViewResources; import com.barcicki.trio.core.FailAnimation; public class CardView extends ImageView { private Card card = null; private Bitmap cardCache = null; private boolean overdraw = true; public CardView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // TODO Auto-generated constructor stub } public CardView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CardView(Context context) { this(context, null); } public Card getCard() { return card; } public void setCard(Card card) { this.card = card; if (cardCache != null) { cardCache.recycle(); } cardCache = null; invalidate(); refreshDrawableState(); } public boolean isOverdrawn() { return overdraw; } public void setOverdraw(boolean overdraw) { this.overdraw = overdraw; } @Override public void setSelected(boolean selected) { super.setSelected(selected); this.cardCache = null; } @Override protected void onDraw(Canvas canvas) { if (null != card) { if (null == this.cardCache && getWidth() > 0 && getHeight() > 0) { this.cardCache = Bitmap.createBitmap(getWidth(), getHeight(), Config.ARGB_8888); Canvas cacheCanvas = new Canvas(this.cardCache); Bitmap square = CardViewResources.getBackgroundSqaure(isSelected()).getBitmap(); float width_ratio = (float) getWidth() / square.getWidth(); float height_ratio = (float) getHeight() / square.getHeight(); // ScaleType scaleType = getScaleType(); int x_offset = 0, y_offset = 0; // sqaure assumption, centering if (width_ratio > height_ratio) { // if (scaleType.equals(ScaleType.CENTER)) { x_offset = (getWidth() - getHeight()) / 2; // } else if (scaleType.equals(ScaleType.FIT_END)) { // x_offset = getWidth() - getHeight(); // } } else { y_offset = (getHeight() - getWidth()) / 2; } float ratio = Math.min( width_ratio, height_ratio); // Matrix matrix = new Matrix(); matrix.postScale(ratio, ratio); cacheCanvas.drawBitmap(Bitmap.createBitmap(square, 0, 0, square.getWidth(), square.getHeight(), matrix, false), x_offset, y_offset, CardViewResources.getBitmapPaint()); drawCard(cacheCanvas, card, (int) (square.getWidth() * ratio), (int) (square.getHeight() * ratio), x_offset, y_offset); } if (this.cardCache != null && this.overdraw && getWidth() > 0 && getHeight() > 0) { canvas.drawBitmap(this.cardCache, 0, 0, null); } else { super.onDraw(canvas); } } else { super.onDraw(canvas); } } public Canvas drawCard(Canvas canvas, Card card, int width, int height, int x_offset, int y_offset) { PointF[] points = {}; float item_size_width = width / 3f; float item_size_height = height / 3f; PointF point1, point2, point3; switch (card.getNumber()) { case Card.NUMBER_ONE: point1 = new PointF((width - item_size_width) / 2f + x_offset, (height - item_size_height) / 2f + y_offset); points = new PointF[] { point1 }; break; case Card.NUMBER_TWO: point1 = new PointF(width / 4f - item_size_width / 3f + x_offset, height / 4f - item_size_height / 3f + y_offset); point2 = new PointF(3 * width / 4f - 2 * item_size_width / 3f + x_offset, 3 * height / 4f - 2* item_size_height / 3f + y_offset); points = new PointF[] { point1, point2 }; break; case Card.NUMBER_THREE: point1 = new PointF(width / 4f - item_size_width / 3f + x_offset, height / 4f - item_size_height / 3f + y_offset); point2 = new PointF(3 * width / 4f - 2 * item_size_width / 3f + x_offset, height / 4f - item_size_height / 3f + y_offset); point3 = new PointF(width / 2f - item_size_width / 2f + x_offset, 3 * height / 4f - 2 * item_size_height / 3f + y_offset); points = new PointF[] { point1, point2, point3 }; break; } Paint paint = new Paint(); Paint shaderPaint = new Paint(); Paint whitePaint = new Paint(); whitePaint.setStyle(Style.FILL); whitePaint.setAntiAlias(true); whitePaint.setColor(CardViewResources.getWhiteColor()); shaderPaint.setStyle(Style.FILL); shaderPaint.setAntiAlias(true); paint.setAntiAlias(true); paint.setStrokeWidth(1); paint.setColor(CardViewResources.getCardColor(card.getColor())); shaderPaint.setShader(CardViewResources.getShader(card.getColor())); switch (card.getFill()) { case Card.FILL_FULL: paint.setStyle(Style.FILL_AND_STROKE); break; case Card.FILL_HALF: paint.setStyle(Style.STROKE); paint.setStrokeWidth(CardViewResources.getStrokeWidth()); break; case Card.FILL_EMPTY: paint.setStyle(Style.STROKE); paint.setStrokeWidth(CardViewResources.getStrokeWidth()); break; } for (int i = 0; i < (card.getNumber()+ 1); i++) { switch (card.getShape()) { case Card.SHAPE_CIRCLE: if (Card.FILL_HALF == card.getFill()) { canvas.drawCircle(points[i].x + item_size_width/2f, points[i].y + item_size_height/2f, item_size_width / 2f, shaderPaint); } if (Card.FILL_EMPTY == card.getFill()) { canvas.drawCircle(points[i].x + item_size_width/2f, points[i].y + item_size_height/2f, item_size_width / 2f, whitePaint); } canvas.drawCircle(points[i].x + item_size_width/2f, points[i].y + item_size_height/2f, item_size_width / 2f, paint); break; case Card.SHAPE_SQUARE: RectF rect = new RectF(points[i].x, points[i].y, points[i].x + item_size_width, points[i].y + item_size_height); if (Card.FILL_HALF == card.getFill()) { canvas.drawRect(rect, shaderPaint); } if (Card.FILL_EMPTY == card.getFill()) { canvas.drawRect(rect, whitePaint); } canvas.drawRect(rect, paint); break; case Card.SHAPE_TRIANGLE: Path path = new Path(); PointF top = new PointF(points[i].x + item_size_width / 2f, points[i].y + 0.1f * item_size_height); PointF bottom_left = new PointF(points[i].x, points[i].y + item_size_height); PointF bottom_right = new PointF(points[i].x + item_size_width, points[i].y + item_size_height); path.moveTo(top.x, top.y); path.lineTo(bottom_right.x, bottom_right.y); // path.moveTo(bottom_right.x, bottom_right.y); path.lineTo(bottom_left.x, bottom_left.y); // path.moveTo(bottom_left.x, bottom_left.y); path.lineTo(top.x, top.y); path.close(); if (Card.FILL_EMPTY == card.getFill()) { canvas.drawPath(path, whitePaint); } if (Card.FILL_HALF == card.getFill()) { canvas.drawPath(path, shaderPaint); } canvas.drawPath(path, paint); } } return canvas; } public void redraw() { this.cardCache = null; // invalidate(); // refreshDrawableState(); } private AnimationListener mFailAnimationListener = null; private AnimationListener mSwitchAnimationListener = null; private AnimationListener mRevealAniamiationListener = null; private AnimationListener mHideAnimationListener; private AnimationListener mShowAnimationListener; public void setFailAnimationLsitener(AnimationListener failAnimationListener) { mFailAnimationListener = failAnimationListener; } public void animateFail() { Animation failAnimation = new FailAnimation(); // Animation failAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.card_fail); failAnimation.setAnimationListener(new AnimationListener() { public void onAnimationStart(Animation animation) { // TODO Auto-generated method stub if (mFailAnimationListener != null) mFailAnimationListener.onAnimationStart(animation); } public void onAnimationRepeat(Animation animation) { // TODO Auto-generated method stub if (mFailAnimationListener != null) mFailAnimationListener.onAnimationRepeat(animation); } public void onAnimationEnd(Animation animation) { // TODO Auto-generated method stub invalidate(); refreshDrawableState(); setSelected(false); if (mFailAnimationListener != null) mFailAnimationListener.onAnimationEnd(animation); } }); startAnimation(failAnimation); } public void setSwitchAnimationLsitener(AnimationListener animationListener) { mSwitchAnimationListener = animationListener; } public void animateSwitchCard(final Card nextCard) { int duration = getResources().getInteger(R.integer.card_flip_anim_duration); animateSwitchCard(nextCard, duration); } public void animateSwitchCard(Card card, int duration) { animateSwitchCard(card, duration, 0); } public void stopSwitchingCard() { Animation currentAnimation = getAnimation(); if (currentAnimation != null) { currentAnimation.setAnimationListener(null); currentAnimation.cancel(); } } public void animateSwitchCard(final Card nextCard, int duration, int delay) { // Animation switchAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.card_flip); final Animation switchAnimation = new CardFlipAnimation(0, 90); // final Animation switchBackAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.card_reflip); final Animation switchBackAnimation = new CardFlipAnimation(270, 360); switchAnimation.setDuration(duration); switchAnimation.setStartOffset(delay); switchBackAnimation.setDuration(duration); switchBackAnimation.setAnimationListener(new AnimationListener() { public void onAnimationStart(Animation animation) { // TODO Auto-generated method stub } public void onAnimationRepeat(Animation animation) { // TODO Auto-generated method stub } public void onAnimationEnd(Animation animation) { // TODO Auto-generated method stub setSelected(false); invalidate(); refreshDrawableState(); if (mSwitchAnimationListener != null) mSwitchAnimationListener.onAnimationEnd(animation); } }); switchAnimation.setAnimationListener(new AnimationListener() { public void onAnimationStart(Animation animation) { // TODO Auto-generated method stub if (mSwitchAnimationListener != null) mSwitchAnimationListener.onAnimationStart(animation); } public void onAnimationRepeat(Animation animation) { // TODO Auto-generated method stub } public void onAnimationEnd(Animation animation) { // TODO Auto-generated method stub setCard(nextCard); setSelected(false); invalidate(); refreshDrawableState(); startAnimation(switchBackAnimation); } }); startAnimation(switchAnimation); } public void setRevealAnimationListener(AnimationListener animationListener) { mRevealAniamiationListener = animationListener; } public void animateReveal() { Animation switchAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.card_flip); final Animation switchBackAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.card_reflip); switchBackAnimation.setAnimationListener(new AnimationListener() { public void onAnimationStart(Animation animation) { // TODO Auto-generated method stub } public void onAnimationRepeat(Animation animation) { // TODO Auto-generated method stub } public void onAnimationEnd(Animation animation) { // TODO Auto-generated method stub invalidate(); refreshDrawableState(); setSelected(false); if (mRevealAniamiationListener != null) mRevealAniamiationListener.onAnimationEnd(animation); } }); switchAnimation.setAnimationListener(new AnimationListener() { public void onAnimationStart(Animation animation) { // TODO Auto-generated method stub setOverdraw(false); if (mRevealAniamiationListener != null) mRevealAniamiationListener.onAnimationStart(animation); } public void onAnimationRepeat(Animation animation) { // TODO Auto-generated method stub } public void onAnimationEnd(Animation animation) { // TODO Auto-generated method stub setSelected(false); invalidate(); refreshDrawableState(); setOverdraw(true); startAnimation(switchBackAnimation); } }); startAnimation(switchAnimation); } public void setHideAnimationListener(AnimationListener animationListener) { mHideAnimationListener = animationListener; } public void animateHide() { Animation hideAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.card_remove); hideAnimation.setAnimationListener(new AnimationListener() { public void onAnimationStart(Animation animation) { // TODO Auto-generated method stub if (mHideAnimationListener != null) mHideAnimationListener.onAnimationStart(animation); } public void onAnimationRepeat(Animation animation) { // TODO Auto-generated method stub if (mHideAnimationListener != null) mHideAnimationListener.onAnimationRepeat(animation); } public void onAnimationEnd(Animation animation) { // TODO Auto-generated method stub setVisibility(View.GONE); if (mHideAnimationListener != null) mHideAnimationListener.onAnimationEnd(animation); } }); startAnimation(hideAnimation); } public void setShowAnimationListener(AnimationListener animationListener) { mShowAnimationListener = animationListener; } public void animateShow() { Animation hideAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.card_appear); hideAnimation.setAnimationListener(new AnimationListener() { public void onAnimationStart(Animation animation) { // TODO Auto-generated method stub if (mShowAnimationListener != null) mShowAnimationListener.onAnimationStart(animation); } public void onAnimationRepeat(Animation animation) { // TODO Auto-generated method stub if (mShowAnimationListener != null) mShowAnimationListener.onAnimationRepeat(animation); } public void onAnimationEnd(Animation animation) { // TODO Auto-generated method stub setVisibility(View.VISIBLE); if (mShowAnimationListener != null) mShowAnimationListener.onAnimationEnd(animation); } }); startAnimation(hideAnimation); } public void forceMeasureSize(int width, int height) { setMeasuredDimension(width, height); } }