依赖
compile 'com.github.bumptech.glide:glide:3.5.2'
开始!
package com.example.accc.flingswipe;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.AdapterView;
/**
* Created by dionysis_lorentzos on 6/8/14
* for package com.lorentzos.swipecards
* and project Swipe cards.
* Use with caution dinausaurs might appear!
*/
abstract class BaseFlingAdapterView extends AdapterView {
private int heightMeasureSpec;
private int widthMeasureSpec;
public BaseFlingAdapterView(Context context) {
super(context);
}
public BaseFlingAdapterView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public BaseFlingAdapterView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public void setSelection(int i) {
throw new UnsupportedOperationException("Not supported");
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
this.widthMeasureSpec = widthMeasureSpec;
this.heightMeasureSpec = heightMeasureSpec;
}
public int getWidthMeasureSpec() {
return widthMeasureSpec;
}
public int getHeightMeasureSpec() {
return heightMeasureSpec;
}
}
继续
package com.example.accc.flingswipe;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.example.accc.R;
import java.util.List;
public class CardAdapter extends BaseAdapter {
private Context mContext;
private List<CardMode> mCardList;
public CardAdapter(Context mContext, List<CardMode> mCardList) {
this.mContext = mContext;
this.mCardList = mCardList;
}
@Override
public int getCount() {
return mCardList.size();
}
@Override
public Object getItem(int position) {
return mCardList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
convertView = inflater.inflate(R.layout.item, parent, false);
holder = new ViewHolder();
holder.mCardImageView = (ImageView) convertView.findViewById(R.id.helloText);
holder.mCardName = (TextView) convertView.findViewById(R.id.card_name);
holder.mCardImageNum = (TextView) convertView.findViewById(R.id.card_image_num);
holder.mCardYear = (TextView) convertView.findViewById(R.id.card_year);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Glide.with(mContext)
.load(mCardList.get(position).getImages().get(0))
.into(holder.mCardImageView);
holder.mCardName.setText(mCardList.get(position).getName());
holder.mCardYear.setText(String.valueOf(mCardList.get(position).getYear()));
return convertView;
}
class ViewHolder {
TextView mCardTitle;
TextView mCardName;
TextView mCardYear;
TextView mCardImageNum;
ImageView mCardImageView;
}
}
继续
package com.example.accc.flingswipe;
import java.util.List;
public class CardMode {
private String name;
private int year;
private List<String> images;
public CardMode(String name, int year, List<String> images) {
this.name = name;
this.year = year;
this.images = images;
}
public String getName() {
return name;
}
public int getYear() {
return year;
}
public void setName(String name) {
this.name = name;
}
public void setYear(int year) {
this.year = year;
}
public void setImages(List<String> images) {
this.images = images;
}
public List<String> getImages() {
return images;
}
}
继续
package com.example.accc.flingswipe;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.OvershootInterpolator;
/**
* Created by dionysis_lorentzos on 5/8/14
* for package com.lorentzos.swipecards
* and project Swipe cards.
* Use with caution dinausaurs might appear!
*/
public class FlingCardListener implements View.OnTouchListener {
private final float objectX;
private final float objectY;
private final int objectH;
private final int objectW;
private final int parentWidth;
private final FlingListener mFlingListener;
private final Object dataObject;
private final float halfWidth;
private float BASE_ROTATION_DEGREES;
private float aPosX;
private float aPosY;
private float aDownTouchX;
private float aDownTouchY;
private static final int INVALID_POINTER_ID = -1;
// The active pointer is the one currently moving our object.
private int mActivePointerId = INVALID_POINTER_ID;
private View frame = null;
private final int TOUCH_ABOVE = 0;
private final int TOUCH_BELOW = 1;
private int touchPosition;
private final Object obj = new Object();
private boolean isAnimationRunning = false;
private float MAX_COS = (float) Math.cos(Math.toRadians(45));
public FlingCardListener(View frame, Object itemAtPosition, FlingListener flingListener) {
this(frame,itemAtPosition, 15f, flingListener);
}
public FlingCardListener(View frame, Object itemAtPosition, float rotation_degrees, FlingListener flingListener) {
super();
this.frame = frame;
this.objectX = frame.getX();
this.objectY = frame.getY();
this.objectH = frame.getHeight();
this.objectW = frame.getWidth();
this.halfWidth = objectW/2f;
this.dataObject = itemAtPosition;
this.parentWidth = ((ViewGroup) frame.getParent()).getWidth();
this.BASE_ROTATION_DEGREES = rotation_degrees;
this.mFlingListener = flingListener;
}
public boolean onTouch(View view, MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
//from http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html
// Save the ID of this pointer
mActivePointerId = event.getPointerId(0);
final float x = event.getX(mActivePointerId);
final float y = event.getY(mActivePointerId);
// Remember where we started
aDownTouchX = x;
aDownTouchY = y;
//to prevent an initial jump of the magnifier, aposX and aPosY must
//have the values from the magnifier frame
if (aPosX == 0) {
aPosX = frame.getX();
}
if (aPosY == 0) {
aPosY = frame.getY();
}
if (y < objectH/2) {
touchPosition = TOUCH_ABOVE;
} else {
touchPosition = TOUCH_BELOW;
}
break;
case MotionEvent.ACTION_UP:
mActivePointerId = INVALID_POINTER_ID;
resetCardViewOnStack();
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
// Extract the index of the pointer that left the touch sensor
final int pointerIndex = (event.getAction() &
MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = event.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mActivePointerId = event.getPointerId(newPointerIndex);
}
break;
case MotionEvent.ACTION_MOVE:
// Find the index of the active pointer and fetch its position
final int pointerIndexMove = event.findPointerIndex(mActivePointerId);
final float xMove = event.getX(pointerIndexMove);
final float yMove = event.getY(pointerIndexMove);
//from http://android-developers.blogspot.com/2010/06/making-sense-of-multitouch.html
// Calculate the distance moved
final float dx = xMove - aDownTouchX;
final float dy = yMove - aDownTouchY;
// Move the frame
aPosX += dx;
aPosY += dy;
// calculate the rotation degrees
float distobjectX = aPosX - objectX;
float rotation = BASE_ROTATION_DEGREES * 2.f * distobjectX / parentWidth;
if (touchPosition == TOUCH_BELOW) {
rotation = -rotation;
}
//in this area would be code for doing something with the view as the frame moves.
frame.setX(aPosX);
frame.setY(aPosY);
frame.setRotation(rotation);
mFlingListener.onScroll(getScrollProgressPercent());
break;
case MotionEvent.ACTION_CANCEL: {
mActivePointerId = INVALID_POINTER_ID;
break;
}
}
return true;
}
private float getScrollProgressPercent() {
if (movedBeyondLeftBorder()) {
return -1f;
} else if (movedBeyondRightBorder()) {
return 1f;
} else {
float zeroToOneValue = (aPosX + halfWidth - leftBorder()) / (rightBorder() - leftBorder());
return zeroToOneValue * 2f - 1f;
}
}
private boolean resetCardViewOnStack() {
if(movedBeyondLeftBorder()){
// Left Swipe
onSelected(true, getExitPoint(-objectW), 100 );
mFlingListener.onScroll(-1.0f);
}else if(movedBeyondRightBorder()) {
// Right Swipe
onSelected(false, getExitPoint(parentWidth), 100 );
mFlingListener.onScroll(1.0f);
}else {
float abslMoveDistance = Math.abs(aPosX-objectX);
aPosX = 0;
aPosY = 0;
aDownTouchX = 0;
aDownTouchY = 0;
frame.animate()
.setDuration(200)
.setInterpolator(new OvershootInterpolator(1.5f))
.x(objectX)
.y(objectY)
.rotation(0);
mFlingListener.onScroll(0.0f);
if(abslMoveDistance<4.0){
mFlingListener.onClick(dataObject);
}
}
return false;
}
private boolean movedBeyondLeftBorder() {
return aPosX+halfWidth < leftBorder();
}
private boolean movedBeyondRightBorder() {
return aPosX+halfWidth > rightBorder();
}
public float leftBorder(){
return parentWidth/4.f;
}
public float rightBorder(){
return 3*parentWidth/4.f;
}
public void onSelected(final boolean isLeft,
float exitY, long duration){
isAnimationRunning = true;
float exitX;
if(isLeft) {
exitX = -objectW-getRotationWidthOffset();
}else {
exitX = parentWidth+getRotationWidthOffset();
}
this.frame.animate()
.setDuration(duration)
.setInterpolator(new AccelerateInterpolator())
.x(exitX)
.y(exitY)
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (isLeft) {
mFlingListener.onCardExited();
mFlingListener.leftExit(dataObject);
} else {
mFlingListener.onCardExited();
mFlingListener.rightExit(dataObject);
}
isAnimationRunning = false;
}
})
.rotation(getExitRotation(isLeft));
}
/**
* Starts a default left exit animation.
*/
public void selectLeft(){
if(!isAnimationRunning)
onSelected(true, objectY, 200);
}
/**
* Starts a default right exit animation.
*/
public void selectRight(){
if(!isAnimationRunning)
onSelected(false, objectY, 200);
}
private float getExitPoint(int exitXPoint) {
float[] x = new float[2];
x[0] = objectX;
x[1] = aPosX;
float[] y = new float[2];
y[0] = objectY;
y[1] = aPosY;
LinearRegression regression =new LinearRegression(x,y);
//Your typical y = ax+b linear regression
return (float) regression.slope() * exitXPoint + (float) regression.intercept();
}
private float getExitRotation(boolean isLeft){
float rotation= BASE_ROTATION_DEGREES * 2.f * (parentWidth - objectX)/parentWidth;
if (touchPosition == TOUCH_BELOW) {
rotation = -rotation;
}
if(isLeft){
rotation = -rotation;
}
return rotation;
}
/**
* When the object rotates it's width becomes bigger.
* The maximum width is at 45 degrees.
*
* The below method calculates the width offset of the rotation.
*
*/
private float getRotationWidthOffset() {
return objectW/MAX_COS - objectW;
}
public void setRotationDegrees(float degrees) {
this.BASE_ROTATION_DEGREES = degrees;
}
protected interface FlingListener {
public void onCardExited();
public void leftExit(Object dataObject);
public void rightExit(Object dataObject);
public void onClick(Object dataObject);
public void onScroll(float scrollProgressPercent);
}
}
继续
package com.example.accc.flingswipe;
/*************************************************************************
* Compilation: javac LinearRegression.java
* Execution: java LinearRegression
*
* Compute least squares solution to y = beta * x + alpha.
* Simple linear regression.
*
*************************************************************************/
/**
* The <tt>LinearRegression</tt> class performs a simple linear regression
* on an set of <em>N</em> data points (<em>y<sub>i</sub></em>, <em>x<sub>i</sub></em>).
* That is, it fits a straight line <em>y</em> = α + β <em>x</em>,
* (where <em>y</em> is the response variable, <em>x</em> is the predictor variable,
* α is the <em>y-intercept</em>, and β is the <em>slope</em>)
* that minimizes the sum of squared residuals of the linear regression model.
* It also computes associated statistics, including the coefficient of
* determination <em>R</em><sup>2</sup> and the standard deviation of the
* estimates for the slope and <em>y</em>-intercept.
*
* @author Robert Sedgewick
* @author Kevin Wayne
*/
public class LinearRegression {
private final int N;
private final double alpha, beta;
private final double R2;
private final double svar, svar0, svar1;
/**
* Performs a linear regression on the data points <tt>(y[i], x[i])</tt>.
* @param x the values of the predictor variable
* @param y the corresponding values of the response variable
* @throws IllegalArgumentException if the lengths of the two arrays are not equal
*/
public LinearRegression(float[] x, float[] y) {
if (x.length != y.length) {
throw new IllegalArgumentException("array lengths are not equal");
}
N = x.length;
// first pass
double sumx = 0.0, sumy = 0.0, sumx2 = 0.0;
for (int i = 0; i < N; i++) sumx += x[i];
for (int i = 0; i < N; i++) sumx2 += x[i]*x[i];
for (int i = 0; i < N; i++) sumy += y[i];
double xbar = sumx / N;
double ybar = sumy / N;
// second pass: compute summary statistics
double xxbar = 0.0, yybar = 0.0, xybar = 0.0;
for (int i = 0; i < N; i++) {
xxbar += (x[i] - xbar) * (x[i] - xbar);
yybar += (y[i] - ybar) * (y[i] - ybar);
xybar += (x[i] - xbar) * (y[i] - ybar);
}
beta = xybar / xxbar;
alpha = ybar - beta * xbar;
// more statistical analysis
double rss = 0.0; // residual sum of squares
double ssr = 0.0; // regression sum of squares
for (int i = 0; i < N; i++) {
double fit = beta*x[i] + alpha;
rss += (fit - y[i]) * (fit - y[i]);
ssr += (fit - ybar) * (fit - ybar);
}
int degreesOfFreedom = N-2;
R2 = ssr / yybar;
svar = rss / degreesOfFreedom;
svar1 = svar / xxbar;
svar0 = svar/N + xbar*xbar*svar1;
}
/**
* Returns the <em>y</em>-intercept α of the best of the best-fit line <em>y</em> = α + β <em>x</em>.
* @return the <em>y</em>-intercept α of the best-fit line <em>y = α + β x</em>
*/
public double intercept() {
return alpha;
}
/**
* Returns the slope β of the best of the best-fit line <em>y</em> = α + β <em>x</em>.
* @return the slope β of the best-fit line <em>y</em> = α + β <em>x</em>
*/
public double slope() {
return beta;
}
/**
* Returns the coefficient of determination <em>R</em><sup>2</sup>.
* @return the coefficient of determination <em>R</em><sup>2</sup>, which is a real number between 0 and 1
*/
public double R2() {
return R2;
}
/**
* Returns the standard error of the estimate for the intercept.
* @return the standard error of the estimate for the intercept
*/
public double interceptStdErr() {
return Math.sqrt(svar0);
}
/**
* Returns the standard error of the estimate for the slope.
* @return the standard error of the estimate for the slope
*/
public double slopeStdErr() {
return Math.sqrt(svar1);
}
/**
* Returns the expected response <tt>y</tt> given the value of the predictor
* variable <tt>x</tt>.
* @param x the value of the predictor variable
* @return the expected response <tt>y</tt> given the value of the predictor
* variable <tt>x</tt>
*/
public double predict(double x) {
return beta*x + alpha;
}
/**
* Returns a string representation of the simple linear regression model.
* @return a string representation of the simple linear regression model,
* including the best-fit line and the coefficient of determination <em>R</em><sup>2</sup>
*/
public String toString() {
String s = "";
s += String.format("%.2f N + %.2f", slope(), intercept());
return s + " (R^2 = " + String.format("%.3f", R2()) + ")";
}
}
继续
package com.example.accc.flingswipe;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.os.Build;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.widget.Adapter;
import android.widget.FrameLayout;
import com.example.accc.R;
/**
* Created by dionysis_lorentzos on 5/8/14
* for package com.lorentzos.swipecards
* and project Swipe cards.
* Use with caution dinosaurs might appear!
*/
public class SwipeFlingAdapterView extends BaseFlingAdapterView {
private int MAX_VISIBLE = 4;
private int MIN_ADAPTER_STACK = 6;
private float ROTATION_DEGREES = 15.f;
private Adapter mAdapter;
private int LAST_OBJECT_IN_STACK = 0;
private onFlingListener mFlingListener;
private AdapterDataSetObserver mDataSetObserver;
private boolean mInLayout = false;
private View mActiveCard = null;
private OnItemClickListener mOnItemClickListener;
private FlingCardListener flingCardListener;
public SwipeFlingAdapterView(Context context) {
this(context, null);
}
public SwipeFlingAdapterView(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.SwipeFlingStyle);
}
public SwipeFlingAdapterView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SwipeFlingAdapterView, defStyle, 0);
MAX_VISIBLE = a.getInt(R.styleable.SwipeFlingAdapterView_max_visible, MAX_VISIBLE);
MIN_ADAPTER_STACK = a.getInt(R.styleable.SwipeFlingAdapterView_min_adapter_stack, MIN_ADAPTER_STACK);
ROTATION_DEGREES = a.getFloat(R.styleable.SwipeFlingAdapterView_rotation_degrees, ROTATION_DEGREES);
a.recycle();
}
/**
* A shortcut method to set both the listeners and the adapter.
*
* @param context The activity context which extends onFlingListener, OnItemClickListener or both
* @param mAdapter The adapter you have to set.
*/
public void init(final Context context, Adapter mAdapter) {
if (context instanceof onFlingListener) {
mFlingListener = (onFlingListener) context;
} else {
throw new RuntimeException("Activity does not implement SwipeFlingAdapterView.onFlingListener");
}
if (context instanceof OnItemClickListener) {
mOnItemClickListener = (OnItemClickListener) context;
}
setAdapter(mAdapter);
}
@Override
public View getSelectedView() {
return mActiveCard;
}
@Override
public void requestLayout() {
if (!mInLayout) {
super.requestLayout();
}
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// if we don't have an adapter, we don't need to do anything
if (mAdapter == null) {
return;
}
mInLayout = true;
final int adapterCount = mAdapter.getCount();
if (adapterCount == 0) {
removeAllViewsInLayout();
} else {
View topCard = getChildAt(LAST_OBJECT_IN_STACK);
if (mActiveCard != null && topCard != null && topCard == mActiveCard) {
removeViewsInLayout(0, LAST_OBJECT_IN_STACK);
layoutChildren(1, adapterCount);
} else {
// Reset the UI and set top view listener
removeAllViewsInLayout();
layoutChildren(0, adapterCount);
setTopView();
}
}
mInLayout = false;
if (adapterCount < MAX_VISIBLE) mFlingListener.onAdapterAboutToEmpty(adapterCount);
}
private void layoutChildren(int startingIndex, int adapterCount) {
while (startingIndex < Math.min(adapterCount, MAX_VISIBLE)) {
View newUnderChild = mAdapter.getView(startingIndex, null, this);
if (newUnderChild.getVisibility() != GONE) {
makeAndAddView(newUnderChild);
LAST_OBJECT_IN_STACK = startingIndex;
}
startingIndex++;
}
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
private void makeAndAddView(View child) {
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) child.getLayoutParams();
addViewInLayout(child, 0, lp, true);
final boolean needToMeasure = child.isLayoutRequested();
if (needToMeasure && lp != null) {
int childWidthSpec = getChildMeasureSpec(getWidthMeasureSpec(),
getPaddingLeft() + getPaddingRight() + lp.leftMargin + lp.rightMargin,
lp.width);
int childHeightSpec = getChildMeasureSpec(getHeightMeasureSpec(),
getPaddingTop() + getPaddingBottom() + lp.topMargin + lp.bottomMargin,
lp.height);
child.measure(childWidthSpec, childHeightSpec);
} else {
cleanupLayoutState(child);
}
int w = child.getMeasuredWidth();
int h = child.getMeasuredHeight();
int gravity = -1;
if (lp != null) {
gravity = lp.gravity;
}
if (gravity == -1) {
gravity = Gravity.TOP | Gravity.START;
}
int layoutDirection = getLayoutDirection();
final int absoluteGravity = Gravity.getAbsoluteGravity(gravity, layoutDirection);
final int verticalGravity = gravity & Gravity.VERTICAL_GRAVITY_MASK;
int childLeft;
int childTop;
switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
case Gravity.CENTER_HORIZONTAL:
childLeft = (getWidth() + getPaddingLeft() - getPaddingRight() - w) / 2 +
lp.leftMargin - lp.rightMargin;
break;
case Gravity.END:
childLeft = getWidth() + getPaddingRight() - w - lp.rightMargin;
break;
case Gravity.START:
default:
childLeft = getPaddingLeft() + lp.leftMargin;
break;
}
switch (verticalGravity) {
case Gravity.CENTER_VERTICAL:
childTop = (getHeight() + getPaddingTop() - getPaddingBottom() - h) / 2 +
lp.topMargin - lp.bottomMargin;
break;
case Gravity.BOTTOM:
childTop = getHeight() - getPaddingBottom() - h - lp.bottomMargin;
break;
case Gravity.TOP:
default:
childTop = getPaddingTop() + lp.topMargin;
break;
}
child.layout(childLeft, childTop, childLeft + w, childTop + h);
}
/**
* Set the top view and add the fling listener
*/
private void setTopView() {
if (getChildCount() > 0) {
mActiveCard = getChildAt(LAST_OBJECT_IN_STACK);
if (mActiveCard != null) {
flingCardListener = new FlingCardListener(mActiveCard, mAdapter.getItem(0),
ROTATION_DEGREES, new FlingCardListener.FlingListener() {
@Override
public void onCardExited() {
mActiveCard = null;
mFlingListener.removeFirstObjectInAdapter();
}
@Override
public void leftExit(Object dataObject) {
mFlingListener.onLeftCardExit(dataObject);
}
@Override
public void rightExit(Object dataObject) {
mFlingListener.onRightCardExit(dataObject);
}
@Override
public void onClick(Object dataObject) {
if (mOnItemClickListener != null)
mOnItemClickListener.onItemClicked(0, dataObject);
}
@Override
public void onScroll(float scrollProgressPercent) {
mFlingListener.onScroll(scrollProgressPercent);
}
});
mActiveCard.setOnTouchListener(flingCardListener);
}
}
}
public FlingCardListener getTopCardListener() throws NullPointerException {
if (flingCardListener == null) {
throw new NullPointerException();
}
return flingCardListener;
}
public void setMaxVisible(int MAX_VISIBLE) {
this.MAX_VISIBLE = MAX_VISIBLE;
}
public void setMinStackInAdapter(int MIN_ADAPTER_STACK) {
this.MIN_ADAPTER_STACK = MIN_ADAPTER_STACK;
}
@Override
public Adapter getAdapter() {
return mAdapter;
}
@Override
public void setAdapter(Adapter adapter) {
if (mAdapter != null && mDataSetObserver != null) {
mAdapter.unregisterDataSetObserver(mDataSetObserver);
mDataSetObserver = null;
}
mAdapter = adapter;
if (mAdapter != null && mDataSetObserver == null) {
mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver);
}
}
public void setFlingListener(onFlingListener onFlingListener) {
this.mFlingListener = onFlingListener;
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.mOnItemClickListener = onItemClickListener;
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new FrameLayout.LayoutParams(getContext(), attrs);
}
private class AdapterDataSetObserver extends DataSetObserver {
@Override
public void onChanged() {
requestLayout();
}
@Override
public void onInvalidated() {
requestLayout();
}
}
public interface OnItemClickListener {
public void onItemClicked(int itemPosition, Object dataObject);
}
public interface onFlingListener {
public void removeFirstObjectInAdapter();
public void onLeftCardExit(Object dataObject);
public void onRightCardExit(Object dataObject);
public void onAdapterAboutToEmpty(int itemsInAdapter);
public void onScroll(float scrollProgressPercent);
}
}
继续
package com.example.accc;
import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.Toast;
import com.example.accc.flingswipe.CardAdapter;
import com.example.accc.flingswipe.CardMode;
import com.example.accc.flingswipe.SwipeFlingAdapterView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ArrayList<CardMode> al;
private CardAdapter adapter;
private int i;
private SwipeFlingAdapterView flingContainer;
private List<List<String>> list = new ArrayList<>();
private ImageView left, right;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
left = (ImageView) findViewById(R.id.left);
right = (ImageView) findViewById(R.id.right);
left.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
left();
}
});
right.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
right();
}
});
al = new ArrayList<>();
for (int i = 0; i < imageUrls.length; i++) {
List<String> s = new ArrayList<>();
s.add(imageUrls[i]);
list.add(s);
}
List<String> yi;
al.add(new CardMode("胡欣语", 21, list.get(0)));
al.add(new CardMode("Norway", 21, list.get(1)));
al.add(new CardMode("王清玉", 18, list.get(2)));
al.add(new CardMode("测试1", 21, list.get(3)));
al.add(new CardMode("测试2", 21, list.get(4)));
al.add(new CardMode("测试3", 21, list.get(5)));
al.add(new CardMode("测试4", 21, list.get(6)));
al.add(new CardMode("测试5", 21, list.get(7)));
al.add(new CardMode("测试6", 21, list.get(8)));
al.add(new CardMode("测试7", 21, list.get(9)));
al.add(new CardMode("测试8", 21, list.get(10)));
al.add(new CardMode("测试9", 21, list.get(11)));
al.add(new CardMode("测试10", 21, list.get(12)));
al.add(new CardMode("测试11", 21, list.get(13)));
al.add(new CardMode("测试12", 21, list.get(14)));
ArrayAdapter arrayAdapter = new ArrayAdapter<>(this, R.layout.item, R.id.helloText, al);
adapter = new CardAdapter(this, al);
flingContainer = (SwipeFlingAdapterView) findViewById(R.id.frame);
flingContainer.setAdapter(adapter);
flingContainer.setFlingListener(new SwipeFlingAdapterView.onFlingListener() {
@Override
public void removeFirstObjectInAdapter() {
al.remove(0);
adapter.notifyDataSetChanged();
}
@Override
public void onLeftCardExit(Object dataObject) {
makeToast(MainActivity.this, "不喜欢");
}
@Override
public void onRightCardExit(Object dataObject) {
makeToast(MainActivity.this, "喜欢");
}
@Override
public void onAdapterAboutToEmpty(int itemsInAdapter) {
al.add(new CardMode("循环测试", 18, list.get(itemsInAdapter % imageUrls.length - 1)));
adapter.notifyDataSetChanged();
i++;
}
@Override
public void onScroll(float scrollProgressPercent) {
View view = flingContainer.getSelectedView();
view.findViewById(R.id.item_swipe_right_indicator).setAlpha(scrollProgressPercent < 0 ? -scrollProgressPercent : 0);
view.findViewById(R.id.item_swipe_left_indicator).setAlpha(scrollProgressPercent > 0 ? scrollProgressPercent : 0);
}
});
flingContainer.setOnItemClickListener(new SwipeFlingAdapterView.OnItemClickListener() {
@Override
public void onItemClicked(int itemPosition, Object dataObject) {
makeToast(MainActivity.this, "点击图片");
}
});
}
static void makeToast(Context ctx, String s) {
Toast.makeText(ctx, s, Toast.LENGTH_SHORT).show();
}
public void right() {
flingContainer.getTopCardListener().selectRight();
}
public void left() {
flingContainer.getTopCardListener().selectLeft();
}
public final String[] imageUrls = new String[]{
"https://img-my.csdn.net/uploads/201309/01/1378037235_3453.jpg",
"https://img-my.csdn.net/uploads/201309/01/1378037235_7476.jpg",
"https://img-my.csdn.net/uploads/201309/01/1378037235_9280.jpg",
"https://img-my.csdn.net/uploads/201309/01/1378037234_3539.jpg",
"https://img-my.csdn.net/uploads/201309/01/1378037234_6318.jpg",
"https://img-my.csdn.net/uploads/201309/01/1378037194_2965.jpg",
"https://img-my.csdn.net/uploads/201309/01/1378037193_1687.jpg",
"https://img-my.csdn.net/uploads/201309/01/1378037193_1286.jpg",
"https://img-my.csdn.net/uploads/201309/01/1378037192_8379.jpg",
"https://img-my.csdn.net/uploads/201309/01/1378037178_9374.jpg",
"https://img-my.csdn.net/uploads/201309/01/1378037177_1254.jpg",
"https://img-my.csdn.net/uploads/201309/01/1378037177_6203.jpg",
"https://img-my.csdn.net/uploads/201309/01/1378037152_6352.jpg",
"https://img-my.csdn.net/uploads/201309/01/1378037151_9565.jpg",
"https://img-my.csdn.net/uploads/201309/01/1378037151_7904.jpg",
"https://img-my.csdn.net/uploads/201309/01/1378037148_7104.jpg",
"https://img-my.csdn.net/uploads/201309/01/1378037129_8825.jpg",
"https://img-my.csdn.net/uploads/201309/01/1378037128_5291.jpg",
"https://img-my.csdn.net/uploads/201309/01/1378037128_3531.jpg",
"https://img-my.csdn.net/uploads/201309/01/1378037127_1085.jpg",
"https://img-my.csdn.net/uploads/201309/01/1378037095_7515.jpg",
"https://img-my.csdn.net/uploads/201309/01/1378037094_8001.jpg",
"https://img-my.csdn.net/uploads/201309/01/1378037093_7168.jpg",
"https://img-my.csdn.net/uploads/201309/01/1378037091_4950.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949643_6410.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949642_6939.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949630_4505.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949630_4593.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949629_7309.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949629_8247.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949615_1986.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949614_8482.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949614_3743.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949614_4199.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949599_3416.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949599_5269.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949598_7858.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949598_9982.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949578_2770.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949578_8744.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949577_5210.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949577_1998.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949482_8813.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949481_6577.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949480_4490.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949455_6792.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949455_6345.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949442_4553.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949441_8987.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949441_5454.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949454_6367.jpg",
"https://img-my.csdn.net/uploads/201308/31/1377949442_4562.jpg"};
}
继续布局
Main的布局
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<include layout="@layout/buttons" />
<com.example.accc.flingswipe.SwipeFlingAdapterView
android:id="@+id/frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:rotation_degrees="15.5"
tools:context=".MyActivity" />
</FrameLayout>
其他的
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal|bottom"
android:layout_marginBottom="20dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="10dp"
android:background="@drawable/home_buttons_dislike"
android:onClick="left" />
<ImageView
android:id="@+id/info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="10dp"
android:background="@drawable/home_buttons_info" />
<ImageView
android:id="@+id/right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="@drawable/home_buttons_like"
/>
</LinearLayout>
还有一个
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_marginBottom="150dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp">
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/material_card"
android:orientation="vertical">
<ImageView
android:id="@+id/helloText"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:layout_marginBottom="50dp"
android:gravity="center"
android:scaleType="centerCrop"
android:src="@drawable/card_bg"
android:textColor="@android:color/white"
android:textSize="40sp" />
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true">
<TextView
android:id="@+id/card_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="18dp"
android:text="兔兔"
android:textColor="#333"
android:textSize="20sp" />
<TextView
android:id="@+id/card_year"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="8dp"
android:layout_toRightOf="@id/card_name"
android:text="18"
android:textColor="#878787"
android:textSize="20sp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="15dp"
android:orientation="horizontal">
<ImageView
android:layout_width="25dp"
android:layout_height="25dp"
android:background="@drawable/card_pic" />
<TextView
android:id="@+id/card_image_num"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="4dp"
android:text="4"
android:textColor="#878787"
android:textSize="17sp" />
<ImageView
android:layout_width="25dp"
android:layout_height="25dp"
android:layout_marginLeft="8dp"
android:background="@drawable/card_des" />
</LinearLayout>
</RelativeLayout>
</RelativeLayout>
<View
android:id="@+id/item_swipe_left_indicator"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_margin="10dp"
android:alpha="0"
android:background="@drawable/home_card_like" />
<View
android:id="@+id/item_swipe_right_indicator"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_gravity="right"
android:layout_margin="10dp"
android:alpha="0"
android:background="@drawable/home_card_dislike" />
</FrameLayout>
还有在drawable下面
home_buttons_dislike.xml
里面
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/home_buttons_dislike_pressed" android:state_pressed="true"></item>
<item android:drawable="@drawable/home_buttons_dislike_normal" android:state_pressed="false"></item>
</selector>
home_buttons_info.xml
里面
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/home_buttons_info_pressed" android:state_pressed="true"></item>
<item android:drawable="@drawable/home_buttons_info_normal" android:state_pressed="false"></item>
</selector>
home_buttons_like.xml
里面
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/home_buttons_like_pressed" android:state_pressed="true"></item>
<item android:drawable="@drawable/home_buttons_like_normal" android:state_pressed="false"></item>
</selector>
material_card.xml
里面
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<solid android:color="@color/card_shadow" />
<corners android:radius="2dp" />
</shape>
</item>
<item android:bottom="2dp">
<shape android:shape="rectangle">
<solid android:color="@color/card_background" />
<corners android:radius="3dp" />
</shape>
</item>
</layer-list>
然后建立一个menu文件夹里面有俩个xml
global.xml
里面是
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/action_settings" android:title="@string/action_settings"
android:orderInCategory="100" app:showAsAction="never" />
</menu>
main.xml
里面是
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity">
<item android:id="@+id/action_example" android:title="@string/action_example"
app:showAsAction="withText|ifRoom" />
<item android:id="@+id/action_settings" android:title="@string/action_settings"
android:orderInCategory="100" app:showAsAction="never" />
</menu>
values里面呢改变
strings.xml下面写填写
<string name="title_section1">Section 1</string>
<string name="title_section2">Section 2</string>
<string name="title_section3">Section 3</string>
<string name="navigation_drawer_open">Open navigation drawer</string>
<string name="navigation_drawer_close">Close navigation drawer</string>
<string name="action_example">Example action</string>
<string name="action_settings">Settings</string>
<declare-styleable name="SwipeFlingAdapterView">
<attr name="SwipeFlingStyle" format="reference" />
<attr name="rotation_degrees" format="float" />
<attr name="min_adapter_stack" format="integer" />
<attr name="max_visible" format="integer" />
</declare-styleable>
<color name="card_background">#ffffff</color>
<color name="card_shadow">#10000000</color>
还有填写一个XML
dimens.xml
里面是
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<!-- Per the design guidelines, navigation drawers should be between 240dp and 320dp:
https://developer.android.com/design/patterns/navigation-drawer.html -->
<dimen name="navigation_drawer_width">240dp</dimen>
</resources>
最后还有values-w820dp名字的文件夹里面有一个Xml
dimens.xml
里面是
<resources>
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
(such as screen margins) for screens with more than 820dp of available width. This
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
<dimen name="activity_horizontal_margin">64dp</dimen>
</resources>
还有一些图片啊
这些最后的没法上传.都是杂杂的 兄弟们大概都写了 自己整把 、