Skip to content

Instantly share code, notes, and snippets.

@toliuweijing
Created May 23, 2015 18:54
Show Gist options
  • Save toliuweijing/ed87005ec5f5e6276c96 to your computer and use it in GitHub Desktop.
Save toliuweijing/ed87005ec5f5e6276c96 to your computer and use it in GitHub Desktop.
FacepileView
package com.example.weijingliu.facepileview;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static java.lang.Math.max;
import static java.lang.Math.min;
public class FacepileView extends View {
private final List<Drawable> mFaceDrawables = new ArrayList<>();
private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
private int mFaceSize;
public FacepileView(Context context) {
this(context, null);
}
public FacepileView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FacepileView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setFaceSize(100);
}
public void setFaceSize(int dp) {
mFaceSize = (int) (getResources().getDisplayMetrics().density * dp);
}
public void setImages(final List<String> paths) {
final List<String> imagePaths = new ArrayList<>();
int limit = 2;
for (String path : paths) {
if (imagePaths.size() == limit) {
break;
}
imagePaths.add(path);
}
// load images into drawable.
mExecutor.submit(new Runnable() {
@Override
public void run() {
final List<Drawable> mDrawables = new ArrayList<>();
BitmapFactory.Options boundOptions = new BitmapFactory.Options();
boundOptions.inJustDecodeBounds = true;
for (String path : imagePaths) {
BitmapFactory.decodeFile(path, boundOptions);
int sampleSize = mFaceSize / max(boundOptions.outWidth, boundOptions.outHeight);
BitmapFactory.Options sampledOption = new BitmapFactory.Options();
sampledOption.inSampleSize = sampleSize;
Bitmap sampledBitmap = BitmapFactory.decodeFile(path, sampledOption);
Bitmap scaledBitmap = Bitmap.createScaledBitmap(
sampledBitmap,
mFaceSize,
mFaceSize,
false);
mDrawables.add(new BitmapDrawable(getResources(), scaledBitmap));
}
post(new Runnable() {
@Override
public void run() {
mFaceDrawables.clear();
mFaceDrawables.addAll(mDrawables);
for (Drawable drawable : mFaceDrawables) {
drawable.setCallback(FacepileView.this);
}
requestLayout();
}
});
}
});
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int intrinsicWidth = mFaceSize * mFaceDrawables.size() + getPaddingLeft() + getPaddingRight();
int intrinsicHeight = mFaceSize + getPaddingTop() + getPaddingBottom();
int faceWidth = mFaceSize;
int faceHeight = mFaceSize;
// optimistic about having enough space.
int measuredWidth = intrinsicWidth;
int measuredHeight = intrinsicHeight;
// address if needed
if (widthMode != MeasureSpec.UNSPECIFIED) {
if (intrinsicWidth > widthSize) {
measuredWidth = widthSize;
faceWidth = (widthSize - getPaddingLeft() - getPaddingRight()) / mFaceDrawables.size();
}
}
if (heightMode != MeasureSpec.UNSPECIFIED) {
if (intrinsicHeight > heightSize) {
measuredHeight = heightSize;
faceHeight = heightSize - getPaddingTop() - getPaddingBottom();
}
}
setMeasuredDimension(
resolveSize(measuredWidth, widthMeasureSpec),
resolveSize(measuredHeight, heightMeasureSpec));
mFaceSize = min(faceWidth, faceHeight);
refreshFaceBounds();
}
private int mGravity = Gravity.RIGHT;
public void setGravity(int gravity) {
mGravity = gravity;
}
private void refreshFaceBounds() {
Rect noPaddingBound = new Rect(
getPaddingLeft(),
getPaddingTop(),
getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
getMeasuredHeight() - getPaddingTop() - getPaddingBottom());
Rect outRect = new Rect();
Gravity.apply(
mGravity,
mFaceSize * mFaceDrawables.size(),
mFaceSize,
noPaddingBound,
outRect);
int left = outRect.left;
int top = outRect.top;
for (Drawable drawable : mFaceDrawables) {
drawable.setBounds(left, top, left + mFaceSize, top + mFaceSize);
invalidate();
left += mFaceSize;
}
Log.i("jing",
String.format(
"w:%d h:%d, noPaddingBount:%s, outBound:%s",
getMeasuredWidth(),
getMeasuredHeight(),
noPaddingBound.toString(),
outRect.toString()));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (Drawable drawable : mFaceDrawables) {
drawable.draw(canvas);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment