Last active
August 29, 2015 14:13
-
-
Save frogermcs/178fee4ca5e368b732ec to your computer and use it in GitHub Desktop.
InstaMaterial source files (user profile)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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()"; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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