package com.llllz.letscdf.views; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.hardware.SensorEvent; import android.os.AsyncTask; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.widget.ImageView; import android.widget.RelativeLayout; import android.widget.TextView; import com.imagefilter.GaussianBlurFilter; import com.imagefilter.Image; import com.imagefilter.ThreeDGridFilter; import com.llllz.letscdf.R; import com.llllz.letscdf.listener.CardListener; import com.llllz.letscdf.listener.SecondCardBgListener; import com.llllz.letscdf.model.Recommend; import com.llllz.letscdf.model.Sex; import com.nineoldandroids.animation.AnimatorSet; import com.nineoldandroids.animation.ObjectAnimator; import com.nineoldandroids.view.ViewHelper; import com.squareup.picasso.Callback; import com.squareup.picasso.Picasso; import com.squareup.picasso.Transformation; import java.io.IOException; import legency.graphic.drawable.TransitionDrawable; public class Card extends RelativeLayout { private static final boolean SENSORENABLE = true; public CardState cardState; private ImageView avatar_im; private ImageView like; private ImageView hate; private Rect mBounds; private float mDeltaX; private float mPointerX; private VelocityTracker mVelocityTracker; private boolean mTapped; private float mVelocity; private float mWidthDismissTrigger; private float mCardWidth; private CardListener choiceListener; private SecondCardBgListener bgChangeListener; private int mTapSlop; private float mPointerY; private float mDeltaY; private AnimatorSet animatorSet; private TextView name; private TextView age; private int card_malecard; private int card_femalecard; private View card; private boolean touching; private float accsensorx; private float accsensory; private Recommend recommend; protected BitmapDrawable bgd; public boolean isAnimating() { return animatorSet != null && animatorSet.isStarted(); } public boolean isTouching() { return touching; } public Card(Context context) { this(context, null); } public Card(Context context, AttributeSet attrs) { this(context, attrs, R.attr.femalecard); } static public Card inflateMale(Context context) { return new Card(context, null, R.attr.malecard); } void setCardStyleRes(Context context, int cardstyleres) { TypedArray cardstyle = context.getTheme().obtainStyledAttributes( cardstyleres, R.styleable.cardstyle); int card_name_color = cardstyle.getColor( R.styleable.cardstyle_name_color, Color.WHITE); int card_age_color = cardstyle.getColor( R.styleable.cardstyle_age_color, Color.WHITE); int resid = cardstyle.getResourceId(R.styleable.cardstyle_bg, R.drawable.card_shadow); card.setBackgroundResource(resid); name.setTextColor(card_name_color); age.setTextColor(card_age_color); cardstyle.recycle(); } public Card(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); TypedArray cardTypedArray = context.getTheme().obtainStyledAttributes( attrs, R.styleable.card, defStyle, R.style.PinkTheme_Card); int sex = cardTypedArray.getInt(R.styleable.card_sex, 0); card_malecard = cardTypedArray.getResourceId(R.styleable.card_malecard, R.style.PinkTheme_Card_Male); card_femalecard = cardTypedArray.getResourceId( R.styleable.card_femalecard, R.style.PinkTheme_Card_Female); int layoutResourceId = cardTypedArray.getResourceId( R.styleable.card_layoutid, R.layout.card); cardTypedArray.recycle(); Drawable avatar = cardTypedArray.getDrawable(R.styleable.card_avatar); setLayerType(View.LAYER_TYPE_HARDWARE, null); setDrawingCacheEnabled(true); setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH); setAnimationCacheEnabled(true); // LayoutInflater inflater = (LayoutInflater) context // .getSystemService(Context.LAYOUT_INFLATER_SERVICE); // inflater.inflate(layoutResourceId, this, true); inflate(context, layoutResourceId, this); avatar_im = (ImageView) findViewById(R.id.avatar); card = findViewById(R.id.card); like = (ImageView) findViewById(R.id.like); hate = (ImageView) findViewById(R.id.hate); name = (TextView) findViewById(R.id.name); age = (TextView) findViewById(R.id.age); setAvatar(avatar); ViewHelper.setAlpha(like, 0.0f); ViewHelper.setAlpha(hate, 0.0f); this.mCardWidth = getResources().getDimension(R.dimen.card_width); mWidthDismissTrigger = (mCardWidth / 2.0f); mTapSlop = ViewConfiguration.get(context).getScaledPagingTouchSlop(); setCardStyle(sex == 0, context); } void setCardStyle(boolean ismale, Context context) { if (ismale) setCardStyleRes(context, card_malecard); else setCardStyleRes(context, card_femalecard); } void setCardStyle(boolean ismale) { if (ismale) setCardStyleRes(getContext(), card_malecard); else setCardStyleRes(getContext(), card_femalecard); } @Override public boolean onTouchEvent(MotionEvent event) { if (choiceListener == null) return false; switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: Log.i("down", "down"); requestDisallowInterceptTouchEvent(true); this.mPointerX = event.getRawX(); this.mPointerY = event.getRawY(); mVelocityTracker = VelocityTracker.obtain(); mTapped = true; touching = true; return true; case MotionEvent.ACTION_UP: Log.i("up", "up"); mVelocityTracker.computeCurrentVelocity(1); mVelocity = mVelocityTracker.getXVelocity(); mDeltaX = (event.getRawX() - mPointerX); mDeltaY = (event.getRawY() - mPointerY); if (Math.abs(this.mVelocity) >= 2.0F) { if (this.mDeltaX < cardState.mTranslationX) { if ((this.animatorSet != null) && (this.animatorSet.isStarted())) this.animatorSet.cancel(); hateCard(); return false; } if (this.mDeltaX > cardState.mTranslationX) { if ((this.animatorSet != null) && (this.animatorSet.isStarted())) this.animatorSet.cancel(); likeCard(); return false; } } if (mDeltaX >= mWidthDismissTrigger) { likeCard(); return false; } if (mDeltaX <= -mWidthDismissTrigger) { hateCard(); return false; } resetPosition(); touching = false; return false; case MotionEvent.ACTION_MOVE: Log.i("move", "move"); mVelocityTracker.addMovement(event); mDeltaX = (event.getRawX() - mPointerX); mDeltaY = (event.getRawY() - mPointerY); mBounds = new Rect(); getDrawingRect(mBounds); mBounds.offset((int) mDeltaX, (int) mDeltaY); ViewHelper.setTranslationX(this, this.mDeltaX); ViewHelper.setTranslationY(this, this.mDeltaY); float a = mDeltaX / 30; // ViewHelper.setRotationX(this, a); ViewHelper.setRotation(this, a); invalidate(mBounds); if (this.mDeltaX < cardState.mTranslationX) { like.setVisibility(View.INVISIBLE); hate.setVisibility(View.VISIBLE); float f2 = Math.min(Math.abs(this.mDeltaX) / 220.0F, 1.0F); ViewHelper.setAlpha(hate, f2); } else { hate.setVisibility(View.INVISIBLE); like.setVisibility(View.VISIBLE); float f2 = Math.min((Math.abs(mDeltaX) / 220.0f), 1.0f); ViewHelper.setAlpha(like, f2); } float cardalpha = Math.max( Math.min(220.0F / Math.abs(this.mDeltaX), 1.0F), 0.5F); ViewHelper.setAlpha(this, cardalpha); boolean localconst = Math.abs(mDeltaX) <= mTapSlop; mTapped = localconst; choiceListener.onmove(mDeltaX); return true; case MotionEvent.ACTION_CANCEL: mVelocityTracker.recycle(); break; default: break; } return false; } private void likeCard() { choiceListener.likeswiped(); } private void hateCard() { choiceListener.hateswiped(); } private void resetPosition() { Log.i("reset", "position"); ViewHelper.setAlpha(hate, 0.0F); ViewHelper.setAlpha(like, 0.0F); hate.setVisibility(View.INVISIBLE); like.setVisibility(View.INVISIBLE); animatorSet = new AnimatorSet(); Log.i("cardstate", getCardState().toString()); reset(SENSORENABLE); choiceListener.resetPosition(); Log.i("v", this.getVisibility() + "View.VISIBLE" + View.VISIBLE); Log.i("cardstate", getCardState().toString()); } private void reset(boolean sensorenable) { // if (sensorenable) { animatorSet.playTogether(ObjectAnimator.ofFloat(this, "translationX", accsensorx), ObjectAnimator.ofFloat(this, "translationY", accsensory), ObjectAnimator.ofFloat(this, "rotation", cardState.mRotation), ObjectAnimator.ofFloat( this, "alpha", cardState.mAlphaState)); animatorSet.setDuration(300L).start(); } else { reset(); } } public void setAvatar(Drawable avatar) { if (avatar != null) avatar_im.setImageDrawable(avatar); } public ImageView getLike() { return like; } public void setLike(ImageView like) { this.like = like; } public ImageView getHate() { return hate; } public void setHate(ImageView hate) { this.hate = hate; } public void setChoiceListener(final CardListener choiceListener) { this.choiceListener = choiceListener; if (bgd != null) { choiceListener.ImageLoaded(bgd); } // if (recommend != null) { // Target arg0 = new Target() { // // @Override // public void onPrepareLoad(Drawable arg0) { // } // // @Override // public void onBitmapLoaded(Bitmap arg0, LoadedFrom arg1) { // FadeDrawable bitmapbg = new FadeDrawable(getResources(), // arg0); // choiceListener.ImageLoaded(bitmapbg); // } // // @Override // public void onBitmapFailed(Drawable arg0) { // // } // }; // Picasso.with(getContext()).load(recommend.getAvatorurl()) // .transform(new Transformation() { // // @Override // public Bitmap transform(Bitmap arg0) { // // GaussianBlurFilter filter = new GaussianBlurFilter(); // filter.Sigma = 10.0F; // return Image.doWithImage(arg0).addFilter(filter) // .ok(); // } // // @Override // public String key() { // return "GaussianBlurFilter"; // } // }).into(arg0); // } } public CardState reserveCardState() { return this.cardState = getCardState(); } private CardState getCardState() { CardState s = new CardState(); s.mAlphaState = ViewHelper.getAlpha(this); s.mPivotX = ViewHelper.getPivotX(this); s.mPivotY = ViewHelper.getPivotY(this); s.mTranslationX = ViewHelper.getTranslationX(this); s.mTranslationY = ViewHelper.getTranslationY(this); s.mRotation = ViewHelper.getRotation(this); s.mRotationX = ViewHelper.getRotationX(this); s.mRotationY = ViewHelper.getRotationY(this); s.mScaleX = ViewHelper.getScaleX(this); s.mScaleY = ViewHelper.getScaleY(this); s.mScrollX = ViewHelper.getScrollX(this); s.mScrollY = ViewHelper.getScrollY(this); return s; } void reset() { animatorSet.playTogether( ObjectAnimator.ofFloat(this, "translationX", Math.abs(cardState.mTranslationX)), ObjectAnimator.ofFloat(this, "translationY", Math.abs(cardState.mTranslationY)), ObjectAnimator.ofFloat(this, "rotation", cardState.mRotation), ObjectAnimator.ofFloat(this, "alpha", cardState.mAlphaState)); animatorSet.setDuration(300L).start(); } public void animateToCard(Card target, float x) { float doffset = Math.abs(x) / 220.0F; float rotated = (target.cardState.mRotation - cardState.mRotation); float rotate = cardState.mRotation + rotated * Math.min(doffset, 1); ViewHelper.setRotation(this, rotate); float alphad = (target.cardState.mAlphaState - cardState.mAlphaState); float alpha = cardState.mAlphaState + alphad * Math.min(doffset, 1); ViewHelper.setAlpha(this, alpha); float xd = (target.cardState.mTranslationX - cardState.mTranslationX); float tx = cardState.mTranslationX + xd * Math.min(doffset, 1); ViewHelper.setTranslationX(this, tx); float yd = (target.cardState.mTranslationY - cardState.mTranslationY); float ty = cardState.mTranslationY + yd * Math.min(doffset, 1); ViewHelper.setTranslationY(this, ty); float sxd = (target.cardState.mScaleX - cardState.mScaleX); float scalx = cardState.mScaleX + sxd * Math.min(doffset, 1); ViewHelper.setScaleX(this, scalx); float syd = (target.cardState.mScaleY - cardState.mScaleY); float scaly = cardState.mScaleY + syd * Math.min(doffset, 1); ViewHelper.setScaleY(this, scaly); } public void setCardState(CardState state) { ViewHelper.setAlpha(this, state.mAlphaState); // ViewHelper.setPivotX(this, this.getWidth() / 2); // ViewHelper.setPivotY(this, this.getHeight() / 2); ViewHelper.setTranslationX(this, state.mTranslationX); ViewHelper.setTranslationY(this, state.mTranslationY); ViewHelper.setRotation(this, state.mRotation); ViewHelper.setRotationX(this, state.mRotationX); ViewHelper.setRotationY(this, state.mRotationY); ViewHelper.setScaleX(this, state.mScaleX); ViewHelper.setScaleY(this, state.mScaleY); ViewHelper.setScrollX(this, (int) state.mScrollX); ViewHelper.setScrollY(this, (int) state.mScrollY); this.cardState = state; } public Recommend getRecommend() { return recommend; } public void bind(final Recommend recommend) { this.recommend = recommend; int placeholderResId = R.drawable.no_avatar_femle; if (recommend.getSex() == Sex.Male) { placeholderResId = R.drawable.no_avatar_male; setCardStyle(true); } else { setCardStyle(false); } Callback ca = new Callback() { @Override public void onSuccess() { new BgTask2(recommend).execute(); } @Override public void onError() { } }; Picasso.with(getContext()).load(recommend.getAvatorurl()) .resize(400, 800).placeholder(placeholderResId) .transform(new Transformation() { @Override public Bitmap transform(Bitmap arg0) { return Image.doWithImage(arg0) .addFilter(new ThreeDGridFilter(10, 10)) .finish(true); } @Override public String key() { return "as"; } }).centerCrop().into(avatar_im, ca); name.setText(recommend.getName()); age.setText(recommend.getAgeString()); } public void sensorEventChange(SensorEvent event) { // ������ ���� �ƶ� // final float FILTERING_FACTOR = 0.7f; // float x = ViewHelper.getTranslationX(this); // float y = ViewHelper.getTranslationY(this); // accsensorx = (float) (-event.values[0] * FILTERING_FACTOR * 10 + x // * (1.0 - FILTERING_FACTOR)); // accsensory = (float) (event.values[1] * FILTERING_FACTOR * 10 + y // * (1.0 - FILTERING_FACTOR)); // ViewHelper.setTranslationX(this, accsensorx); // ViewHelper.setTranslationY(this, accsensory); // ���� // float scalx = ViewHelper.getScaleX(this); // float scalxn = (float) (event.values[2] * 0.05 + scalx // * (1.0 - 0.05)); // ViewHelper.setScaleX(this, scalxn); // // float scaly = ViewHelper.getScaleY(this); // float scalyn = (float) (event.values[2] * 0.05 + scaly // * (1.0 - 0.05)); // ViewHelper.setScaleY(this, scalyn); } public class BgTask2 extends AsyncTask<Void, Void, BitmapDrawable> { private Recommend recommend; public BgTask2(Recommend recommend) { this.recommend = recommend; } @Override protected BitmapDrawable doInBackground(Void... params) { Bitmap as = null; try { as = Picasso.with(getContext()).load(recommend.getAvatorurl()).resize(100, 100) .get(); } catch (IOException e) { e.printStackTrace(); } GaussianBlurFilter filter = new GaussianBlurFilter(); filter.Sigma = 5.0F; Bitmap a = Image.doWithImage(as).addFilter(filter) .finish(false); return new BitmapDrawable(getResources(), a); } @Override protected void onPostExecute(BitmapDrawable result) { super.onPostExecute(result); bgd = result; if (bgChangeListener != null) bgChangeListener.secbgloaded(bgd); if (choiceListener != null) choiceListener.ImageLoaded(bgd); } } public TransitionDrawable buildbg(Drawable currentbg) { Drawable[] layers = new Drawable[2]; layers[0] = currentbg; layers[1] = bgd; return new TransitionDrawable(layers); } public SecondCardBgListener getBgChangeListener() { return bgChangeListener; } public void setBgChangeListener(SecondCardBgListener bgChangeListener) { this.bgChangeListener = bgChangeListener; if (bgd != null) { bgChangeListener.secbgloaded(bgd); } } }