package com.anthony.rvhelper.adapter;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.Build;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.TranslateAnimation;
import android.widget.RelativeLayout;
import java.util.List;
/**
* Create By Anthony on 2016/1/15
* Class Note:
* 实现视差效果的recyclerView
* https://github.com/kanytu/android-parallax-recyclerview
*
*
*/
public abstract class ParallaxRecyclerAdapter<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private float mScrollMultiplier = 0.5f;
public static class VIEW_TYPES {
public static final int NORMAL = 1;
public static final int HEADER = 2;
public static final int FIRST_VIEW = 3;
}
public abstract void onBindViewHolderImpl(RecyclerView.ViewHolder viewHolder, ParallaxRecyclerAdapter<T> adapter, int i);
public abstract RecyclerView.ViewHolder onCreateViewHolderImpl(ViewGroup viewGroup, ParallaxRecyclerAdapter<T> adapter, int i);
public abstract int getItemCountImpl(ParallaxRecyclerAdapter<T> adapter);
public interface OnClickEvent {
/**
* Event triggered when you click on a item of the adapter
*
* @param v view
* @param position position on the array
*/
void onClick(View v, int position);
}
public interface OnParallaxScroll {
/**
* Event triggered when the parallax is being scrolled.
*/
void onParallaxScroll(float percentage, float offset, View parallax);
}
private List<T> mData;
private CustomRelativeWrapper mHeader;
private OnClickEvent mOnClickEvent;
private OnParallaxScroll mParallaxScroll;
private RecyclerView mRecyclerView;
private boolean mShouldClipView = true;
/**
* Translates the adapter in Y
*
* @param of offset in px
*/
public void translateHeader(float of) {
float ofCalculated = of * mScrollMultiplier;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB && of < mHeader.getHeight()) {
mHeader.setTranslationY(ofCalculated);
} else if (of < mHeader.getHeight()) {
TranslateAnimation anim = new TranslateAnimation(0, 0, ofCalculated, ofCalculated);
anim.setFillAfter(true);
anim.setDuration(0);
mHeader.startAnimation(anim);
}
mHeader.setClipY(Math.round(ofCalculated));
if (mParallaxScroll != null) {
final RecyclerView.ViewHolder holder = mRecyclerView.findViewHolderForAdapterPosition(0);
float left;
if (holder != null) {
left = Math.min(1, ((ofCalculated) / (mHeader.getHeight() * mScrollMultiplier)));
}else {
left = 1;
}
mParallaxScroll.onParallaxScroll(left, of, mHeader);
}
}
/**
* Set the view as header.
*
* @param header The inflated header
* @param view The RecyclerView to set scroll listeners
*/
public void setParallaxHeader(View header, final RecyclerView view) {
mRecyclerView = view;
mHeader = new CustomRelativeWrapper(header.getContext(), mShouldClipView);
mHeader.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
mHeader.addView(header, new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
view.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (mHeader != null) {
translateHeader(mRecyclerView.getLayoutManager().getChildAt(0) == mHeader ?
mRecyclerView.computeVerticalScrollOffset() : mHeader.getHeight());
}
}
});
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, final int i) {
if (mHeader != null) {
if (i == 0) {
return;
}
onBindViewHolderImpl(viewHolder, this, i - 1);
} else {
onBindViewHolderImpl(viewHolder, this, i);
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup viewGroup, final int i) {
if (i == VIEW_TYPES.HEADER && mHeader != null) {
return new ViewHolder(mHeader);
}
if (i == VIEW_TYPES.FIRST_VIEW && mHeader != null && mRecyclerView != null) {
final RecyclerView.ViewHolder holder = mRecyclerView.findViewHolderForAdapterPosition(0);
if (holder != null) {
translateHeader(-holder.itemView.getTop());
}
}
final RecyclerView.ViewHolder holder = onCreateViewHolderImpl(viewGroup, this, i);
if (mOnClickEvent != null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mOnClickEvent.onClick(v, holder.getAdapterPosition() - (mHeader == null ? 0 : 1));
}
});
}
return holder;
}
/**
* @return true if there is a header on this adapter, false otherwise
*/
public boolean hasHeader() {
return mHeader != null;
}
public void setOnClickEvent(OnClickEvent onClickEvent) {
mOnClickEvent = onClickEvent;
}
public boolean isShouldClipView() {
return mShouldClipView;
}
/**
* Defines if we will clip the layout or not. MUST BE CALLED BEFORE {@link
* #setParallaxHeader(View, RecyclerView)}
*/
public void setShouldClipView(boolean shouldClickView) {
mShouldClipView = shouldClickView;
}
public void setOnParallaxScroll(OnParallaxScroll parallaxScroll) {
mParallaxScroll = parallaxScroll;
mParallaxScroll.onParallaxScroll(0, 0, mHeader);
}
public ParallaxRecyclerAdapter(List<T> data) {
mData = data;
}
public List<T> getData() {
return mData;
}
public void setData(List<T> data) {
mData = data;
notifyDataSetChanged();
}
public void addItem(T item, int position) {
mData.add(position, item);
notifyItemInserted(position + (mHeader == null ? 0 : 1));
}
public void removeItem(T item) {
int position = mData.indexOf(item);
if (position < 0)
return;
mData.remove(item);
notifyItemRemoved(position + (mHeader == null ? 0 : 1));
}
public int getItemCount() {
return getItemCountImpl(this) + (mHeader == null ? 0 : 1);
}
@Override
public int getItemViewType(int position) {
if (position == 1)
return VIEW_TYPES.FIRST_VIEW;
return position == 0 && mHeader != null ? VIEW_TYPES.HEADER : VIEW_TYPES.NORMAL;
}
static class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
}
}
static class CustomRelativeWrapper extends RelativeLayout {
private int mOffset;
private boolean mShouldClip;
public CustomRelativeWrapper(Context context, boolean shouldClick) {
super(context);
mShouldClip = shouldClick;
}
@Override
protected void dispatchDraw(Canvas canvas) {
if (mShouldClip) {
canvas.clipRect(new Rect(getLeft(), getTop(), getRight(), getBottom() + mOffset));
}
super.dispatchDraw(canvas);
}
public void setClipY(int offset) {
mOffset = offset;
invalidate();
}
}
/**
* Set parallax scroll multiplier.
*
* @param mul The multiplier
*/
public void setScrollMultiplier(float mul) {
this.mScrollMultiplier = mul;
}
/**
* Get the current parallax scroll multiplier.
*
*/
public float getScrollMultiplier() {
return this.mScrollMultiplier;
}
}
/**
* Sample here
*/
/*
private void createAdapter(RecyclerView recyclerView) {
final List<String> content = new ArrayList<>();
for (int i = 0; i < 50; i++) {
content.add("item " + i);
}
final ParallaxRecyclerAdapter<String> adapter = new ParallaxRecyclerAdapter<String>(content) {
@Override
public void onBindViewHolderImpl(RecyclerView.ViewHolder viewHolder, ParallaxRecyclerAdapter<String> adapter, int i) {
((ViewHolder) viewHolder).textView.setText(adapter.getData().get(i));
}
@Override
public RecyclerView.ViewHolder onCreateViewHolderImpl(ViewGroup viewGroup, final ParallaxRecyclerAdapter<String> adapter, int i) {
return new ViewHolder(getLayoutInflater().inflate(R.layout.row_recyclerview, viewGroup, false));
}
@Override
public int getItemCountImpl(ParallaxRecyclerAdapter<String> adapter) {
return content.size();
}
};
adapter.setOnClickEvent(new ParallaxRecyclerAdapter.OnClickEvent() {
@Override
public void onClick(View v, int position) {
Toast.makeText(PersonalInfoActivity.this, "You clicked '" + position + "'", Toast.LENGTH_SHORT).show();
}
});
//alpha effect in TopBar
adapter.setOnParallaxScroll(new ParallaxRecyclerAdapter.OnParallaxScroll() {
@Override
public void onParallaxScroll(float percentage, float offset, View parallax) {
Drawable c = personalTopBar.getBackground();
c.setAlpha(Math.round(percentage * 255));
personalTopBar.setBackground(c);
}
});
recyclerView.setLayoutManager(new LinearLayoutManager(this));
View header = getLayoutInflater().inflate(R.layout.header, recyclerView, false);
adapter.setParallaxHeader(header, recyclerView);
adapter.setData(content);
recyclerView.setAdapter(adapter);
}*/