Created
May 23, 2015 18:54
-
-
Save toliuweijing/ed87005ec5f5e6276c96 to your computer and use it in GitHub Desktop.
FacepileView
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
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