Skip to content

Instantly share code, notes, and snippets.

@frogermcs
Last active August 29, 2015 14:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save frogermcs/178fee4ca5e368b732ec to your computer and use it in GitHub Desktop.
Save frogermcs/178fee4ca5e368b732ec to your computer and use it in GitHub Desktop.
InstaMaterial source files (user profile)
public class CircleTransformation implements Transformation {
private static final int STROKE_WIDTH = 6;
@Override
public Bitmap transform(Bitmap source) {
int size = Math.min(source.getWidth(), source.getHeight());
int x = (source.getWidth() - size) / 2;
int y = (source.getHeight() - size) / 2;
Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size);
if (squaredBitmap != source) {
source.recycle();
}
Bitmap bitmap = Bitmap.createBitmap(size, size, source.getConfig());
Canvas canvas = new Canvas(bitmap);
Paint avatarPaint = new Paint();
BitmapShader shader = new BitmapShader(squaredBitmap, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);
avatarPaint.setShader(shader);
Paint outlinePaint = new Paint();
outlinePaint.setColor(Color.WHITE);
outlinePaint.setStyle(Paint.Style.STROKE);
outlinePaint.setStrokeWidth(STROKE_WIDTH);
outlinePaint.setAntiAlias(true);
float r = size / 2f;
canvas.drawCircle(r, r, r, avatarPaint);
canvas.drawCircle(r, r, r - STROKE_WIDTH / 2, outlinePaint);
squaredBitmap.recycle();
return bitmap;
}
@Override
public String key() {
return "circleTransformation()";
}
}
@Override
public void onProfileClick(View v) {
int[] startingLocation = new int[2];
v.getLocationOnScreen(startingLocation);
startingLocation[0] += v.getWidth() / 2;
UserProfileActivity.startUserProfileFromLocation(startingLocation, this);
overridePendingTransition(0, 0);
}
public class RevealBackgroundView extends View {
public static final int STATE_NOT_STARTED = 0;
public static final int STATE_FILL_STARTED = 1;
public static final int STATE_FINISHED = 2;
private static final Interpolator INTERPOLATOR = new AccelerateInterpolator();
private static final int FILL_TIME = 400;
private int state = STATE_NOT_STARTED;
private Paint fillPaint;
private int currentRadius;
ObjectAnimator revealAnimator;
private int startLocationX;
private int startLocationY;
private OnStateChangeListener onStateChangeListener;
public RevealBackgroundView(Context context) {
super(context);
init();
}
public RevealBackgroundView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public RevealBackgroundView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public RevealBackgroundView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
fillPaint = new Paint();
fillPaint.setStyle(Paint.Style.FILL);
fillPaint.setColor(Color.WHITE);
}
public void startFromLocation(int[] tapLocationOnScreen) {
changeState(STATE_FILL_STARTED);
startLocationX = tapLocationOnScreen[0];
startLocationY = tapLocationOnScreen[1];
revealAnimator = ObjectAnimator.ofInt(this, "currentRadius", 0, getWidth() + getHeight()).setDuration(FILL_TIME);
revealAnimator.setInterpolator(INTERPOLATOR);
revealAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
changeState(STATE_FINISHED);
}
});
revealAnimator.start();
}
public void setToFinishedFrame() {
changeState(STATE_FINISHED);
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
if (state == STATE_FINISHED) {
canvas.drawRect(0, 0, getWidth(), getHeight(), fillPaint);
} else {
canvas.drawCircle(startLocationX, startLocationY, currentRadius, fillPaint);
}
}
private void changeState(int state) {
if (this.state == state) {
return;
}
this.state = state;
if (onStateChangeListener != null) {
onStateChangeListener.onStateChange(state);
}
}
public void setOnStateChangeListener(OnStateChangeListener onStateChangeListener) {
this.onStateChangeListener = onStateChangeListener;
}
public void setCurrentRadius(int radius) {
this.currentRadius = radius;
invalidate();
}
public static interface OnStateChangeListener {
void onStateChange(int state);
}
}
public class UserProfileActivity extends BaseActivity implements RevealBackgroundView.OnStateChangeListener {
public static final String ARG_REVEAL_START_LOCATION = "reveal_start_location";
@InjectView(R.id.vRevealBackground)
RevealBackgroundView vRevealBackground;
@InjectView(R.id.rvUserProfile)
RecyclerView rvUserProfile;
private UserProfileAdapter userPhotosAdapter;
public static void startUserProfileFromLocation(int[] startingLocation, Activity startingActivity) {
Intent intent = new Intent(startingActivity, UserProfileActivity.class);
intent.putExtra(ARG_REVEAL_START_LOCATION, startingLocation);
startingActivity.startActivity(intent);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user_profile);
setupUserProfileGrid();
setupRevealBackground(savedInstanceState);
}
private void setupRevealBackground(Bundle savedInstanceState) {
vRevealBackground.setOnStateChangeListener(this);
if (savedInstanceState == null) {
final int[] startingLocation = getIntent().getIntArrayExtra(ARG_REVEAL_START_LOCATION);
vRevealBackground.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
vRevealBackground.getViewTreeObserver().removeOnPreDrawListener(this);
vRevealBackground.startFromLocation(startingLocation);
return false;
}
});
} else {
userPhotosAdapter.setLockedAnimations(true);
vRevealBackground.setToFinishedFrame();
}
}
private void setupUserProfileGrid() {
final StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);
rvUserProfile.setLayoutManager(layoutManager);
rvUserProfile.setOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
userPhotosAdapter.setLockedAnimations(true);
}
});
}
@Override
public void onStateChange(int state) {
if (RevealBackgroundView.STATE_FINISHED == state) {
rvUserProfile.setVisibility(View.VISIBLE);
userPhotosAdapter = new UserProfileAdapter(this);
rvUserProfile.setAdapter(userPhotosAdapter);
} else {
rvUserProfile.setVisibility(View.INVISIBLE);
}
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
int viewType = getItemViewType(position);
if (TYPE_PROFILE_HEADER == viewType) {
bindProfileHeader((ProfileHeaderViewHolder) holder);
} else if (TYPE_PROFILE_OPTIONS == viewType) {
bindProfileOptions((ProfileOptionsViewHolder) holder);
} else if (TYPE_PHOTO == viewType) {
bindPhoto((PhotoViewHolder) holder, position);
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (TYPE_PROFILE_HEADER == viewType) {
final View view = LayoutInflater.from(context).inflate(R.layout.view_user_profile_header, parent, false);
StaggeredGridLayoutManager.LayoutParams layoutParams = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
layoutParams.setFullSpan(true);
view.setLayoutParams(layoutParams);
return new ProfileHeaderViewHolder(view);
} else if (TYPE_PROFILE_OPTIONS == viewType) {
final View view = LayoutInflater.from(context).inflate(R.layout.view_user_profile_options, parent, false);
StaggeredGridLayoutManager.LayoutParams layoutParams = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
layoutParams.setFullSpan(true);
view.setLayoutParams(layoutParams);
return new ProfileOptionsViewHolder(view);
} else if (TYPE_PHOTO == viewType) {
final View view = LayoutInflater.from(context).inflate(R.layout.item_photo, parent, false);
StaggeredGridLayoutManager.LayoutParams layoutParams = (StaggeredGridLayoutManager.LayoutParams) view.getLayoutParams();
layoutParams.height = cellSize;
layoutParams.width = cellSize;
layoutParams.setFullSpan(false);
view.setLayoutParams(layoutParams);
return new PhotoViewHolder(view);
}
return null;
}
private void animateUserProfileHeader(ProfileHeaderViewHolder viewHolder) {
if (!lockedAnimations) {
profileHeaderAnimationStartTime = System.currentTimeMillis();
viewHolder.vUserProfileRoot.setTranslationY(-viewHolder.vUserProfileRoot.getHeight());
viewHolder.ivUserProfilePhoto.setTranslationY(-viewHolder.ivUserProfilePhoto.getHeight());
viewHolder.vUserDetails.setTranslationY(-viewHolder.vUserDetails.getHeight());
viewHolder.vUserStats.setAlpha(0);
viewHolder.vUserProfileRoot.animate().translationY(0).setDuration(300).setInterpolator(INTERPOLATOR);
viewHolder.ivUserProfilePhoto.animate().translationY(0).setDuration(300).setStartDelay(100).setInterpolator(INTERPOLATOR);
viewHolder.vUserDetails.animate().translationY(0).setDuration(300).setStartDelay(200).setInterpolator(INTERPOLATOR);
viewHolder.vUserStats.animate().alpha(1).setDuration(200).setStartDelay(400).setInterpolator(INTERPOLATOR).start();
}
}
private void animateUserProfileOptions(ProfileOptionsViewHolder viewHolder) {
if (!lockedAnimations) {
viewHolder.vButtons.setTranslationY(-viewHolder.vButtons.getHeight());
viewHolder.vUnderline.setScaleX(0);
viewHolder.vButtons.animate().translationY(0).setDuration(300).setStartDelay(USER_OPTIONS_ANIMATION_DELAY).setInterpolator(INTERPOLATOR);
viewHolder.vUnderline.animate().scaleX(1).setDuration(200).setStartDelay(USER_OPTIONS_ANIMATION_DELAY + 300).setInterpolator(INTERPOLATOR).start();
}
}
static class ProfileHeaderViewHolder extends RecyclerView.ViewHolder {
@InjectView(R.id.ivUserProfilePhoto)
ImageView ivUserProfilePhoto;
@InjectView(R.id.vUserDetails)
View vUserDetails;
@InjectView(R.id.btnFollow)
Button btnFollow;
@InjectView(R.id.vUserStats)
View vUserStats;
@InjectView(R.id.vUserProfileRoot)
View vUserProfileRoot;
public ProfileHeaderViewHolder(View view) {
super(view);
ButterKnife.inject(this, view);
}
}
static class ProfileOptionsViewHolder extends RecyclerView.ViewHolder {
@InjectView(R.id.btnGrid)
ImageButton btnGrid;
@InjectView(R.id.btnList)
ImageButton btnList;
@InjectView(R.id.btnMap)
ImageButton btnMap;
@InjectView(R.id.btnTagged)
ImageButton btnComments;
@InjectView(R.id.vUnderline)
View vUnderline;
@InjectView(R.id.vButtons)
View vButtons;
public ProfileOptionsViewHolder(View view) {
super(view);
ButterKnife.inject(this, view);
}
}
static class PhotoViewHolder extends RecyclerView.ViewHolder {
@InjectView(R.id.flRoot)
FrameLayout flRoot;
@InjectView(R.id.ivPhoto)
ImageView ivPhoto;
public PhotoViewHolder(View view) {
super(view);
ButterKnife.inject(this, view);
}
}
private void bindPhoto(final PhotoViewHolder holder, int position) {
Picasso.with(context)
.load(photos.get(position - MIN_ITEMS_COUNT))
.resize(cellSize, cellSize)
.centerCrop()
.into(holder.ivPhoto, new Callback() {
@Override
public void onSuccess() {
animatePhoto(holder);
}
@Override
public void onError() {
}
});
if (lastAnimatedItem < position) lastAnimatedItem = position;
}
private void animatePhoto(PhotoViewHolder viewHolder) {
if (!lockedAnimations) {
if (lastAnimatedItem == viewHolder.getPosition()) {
setLockedAnimations(true);
}
long animationDelay = profileHeaderAnimationStartTime + MAX_PHOTO_ANIMATION_DELAY - System.currentTimeMillis();
if (profileHeaderAnimationStartTime == 0) {
animationDelay = viewHolder.getPosition() * 30 + MAX_PHOTO_ANIMATION_DELAY;
} else if (animationDelay < 0) {
animationDelay = viewHolder.getPosition() * 30;
} else {
animationDelay += viewHolder.getPosition() * 30;
}
viewHolder.flRoot.setScaleY(0);
viewHolder.flRoot.setScaleX(0);
viewHolder.flRoot.animate()
.scaleY(1)
.scaleX(1)
.setDuration(200)
.setInterpolator(INTERPOLATOR)
.setStartDelay(animationDelay)
.start();
}
}
public static final int TYPE_PROFILE_HEADER = 0;
public static final int TYPE_PROFILE_OPTIONS = 1;
public static final int TYPE_PHOTO = 2;
@Override
public int getItemViewType(int position) {
if (position == 0) {
return TYPE_PROFILE_HEADER;
} else if (position == 1) {
return TYPE_PROFILE_OPTIONS;
} else {
return TYPE_PHOTO;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment