仿腾讯QQ拍照 背景图片滑动获取图片
来源:程序员人生 发布时间:2015-07-28 07:52:39 阅读次数:3146次
1.首先我们来看1下效果图片
2.再看1下项目结构
3.里面注释很多我就不仔细讲了,大家仔细看吧
首先是MainActivity:
public class MainActivity extends Activity {
private ClipImageView imageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
imageView = (ClipImageView) findViewById(R.id.src_pic);
// 设置需要裁剪的图片
imageView.setImageResource(R.drawable.test_pic);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId() == R.id.action_clip){
// 此处获得剪裁后的bitmap
Bitmap bitmap = imageView.clip();
// 由于Intent传递bitmap不能超过40k,此处使用2进制数组传递
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] bitmapByte = baos.toByteArray();
Intent intent = new Intent(this, PreviewActivity.class);
intent.putExtra("bitmap", bitmapByte);
startActivity(intent);
}
return super.onOptionsItemSelected(item);
}
}
再来看看:
PreviewActivity:
public class PreviewActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.preview);
setTitle("预览");
ImageView imageView = (ImageView) findViewById(R.id.preview);
byte[] bis = getIntent().getByteArrayExtra("bitmap");
Bitmap bitmap = BitmapFactory.decodeByteArray(bis, 0, bis.length);
if(bitmap != null){
imageView.setImageBitmap(bitmap);
}
}
}
自定义控件类:ClipImageView
public class ClipImageView extends ImageView implements View.OnTouchListener, ViewTreeObserver.OnGlobalLayoutListener{
private static final int BORDERDISTANCE = ClipView.BORDERDISTANCE;
public static final float DEFAULT_MAX_SCALE = 4.0f;
public static final float DEFAULT_MID_SCALE = 2.0f;
public static final float DEFAULT_MIN_SCALE = 1.0f;
private float minScale = DEFAULT_MIN_SCALE;
private float midScale = DEFAULT_MID_SCALE;
private float maxScale = DEFAULT_MAX_SCALE;
private MultiGestureDetector multiGestureDetector;
private int borderlength;
private boolean isJusted;
private final Matrix baseMatrix = new Matrix();
private final Matrix drawMatrix = new Matrix();
private final Matrix suppMatrix = new Matrix();
private final RectF displayRect = new RectF();
private final float[] matrixValues = new float[9];
public ClipImageView(Context context) {
this(context, null);
}
public ClipImageView(Context context, AttributeSet attr) {
this(context, attr, 0);
}
public ClipImageView(Context context, AttributeSet attr, int defStyle) {
super(context, attr, defStyle);
super.setScaleType(ScaleType.MATRIX);
setOnTouchListener(this);
multiGestureDetector = new MultiGestureDetector(context);
}
/**
* 根据图片宽高比例,设置图象初始缩放等级和位置
*/
private void configPosition(){
super.setScaleType(ScaleType.MATRIX);
Drawable d = getDrawable();
if(d == null){
return;
}
final float viewWidth = getWidth();
final float viewHeight = getHeight();
final int drawableWidth = d.getIntrinsicWidth();
final int drawableHeight = d.getIntrinsicHeight();
borderlength = (int) (viewWidth - BORDERDISTANCE *2);
float scale = 1.0f;
/**
* 判断图片宽高比例,调剂显示位置和缩放大小
*/
// 图片宽度小于等于高度
if(drawableWidth <= drawableHeight){
// 判断图片宽度是不是小于边框, 缩放铺满裁剪边框
if(drawableWidth < borderlength){
baseMatrix.reset();
scale = (float)borderlength / drawableWidth;
// 缩放
baseMatrix.postScale(scale, scale);
}
// 图片宽度大于高度
}else{
if(drawableHeight < borderlength){
baseMatrix.reset();
scale = (float)borderlength / drawableHeight;
// 缩放
baseMatrix.postScale(scale, scale);
}
}
// 移动居中
baseMatrix.postTranslate((viewWidth - drawableWidth * scale) / 2, (viewHeight - drawableHeight * scale)/2);
resetMatrix();
isJusted = true;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
return multiGestureDetector.onTouchEvent(event);
}
private class MultiGestureDetector extends GestureDetector.SimpleOnGestureListener implements
OnScaleGestureListener {
private final ScaleGestureDetector scaleGestureDetector;
private final GestureDetector gestureDetector;
private final float scaledTouchSlop;
private VelocityTracker velocityTracker;
private boolean isDragging;
private float lastTouchX;
private float lastTouchY;
private float lastPointerCount;
public MultiGestureDetector(Context context) {
scaleGestureDetector = new ScaleGestureDetector(context, this);
gestureDetector = new GestureDetector(context, this);
gestureDetector.setOnDoubleTapListener(this);
final ViewConfiguration configuration = ViewConfiguration.get(context);
scaledTouchSlop = configuration.getScaledTouchSlop();
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
float scale = getScale();
float scaleFactor = detector.getScaleFactor();
if(getDrawable() != null && ((scale < maxScale && scaleFactor > 1.0f) || (scale > minScale && scaleFactor < 1.0f))){
if(scaleFactor * scale < minScale){
scaleFactor = minScale / scale;
}
if(scaleFactor * scale > maxScale){
scaleFactor = maxScale / scale;
}
suppMatrix.postScale(scaleFactor, scaleFactor, getWidth()/2, getHeight()/2);
checkAndDisplayMatrix();
}
return true;
}
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
}
public boolean onTouchEvent(MotionEvent event) {
if (gestureDetector.onTouchEvent(event)) {
return true;
}
scaleGestureDetector.onTouchEvent(event);
/*
* Get the center x, y of all the pointers
*/
float x = 0, y = 0;
final int pointerCount = event.getPointerCount();
for (int i = 0; i < pointerCount; i++) {
x += event.getX(i);
y += event.getY(i);
}
x = x / pointerCount;
y = y / pointerCount;
/*
* If the pointer count has changed cancel the drag
*/
if (pointerCount != lastPointerCount) {
isDragging = false;
if (velocityTracker != null) {
velocityTracker.clear();
}
lastTouchX = x;
lastTouchY = y;
}
lastPointerCount = pointerCount;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
if (velocityTracker == null) {
velocityTracker = VelocityTracker.obtain();
} else {
velocityTracker.clear();
}
velocityTracker.addMovement(event);
lastTouchX = x;
lastTouchY = y;
isDragging = false;
break;
case MotionEvent.ACTION_MOVE: {
final float dx = x - lastTouchX, dy = y - lastTouchY;
if (isDragging == false) {
// Use Pythagoras to see if drag length is larger than
// touch slop
isDragging = Math.sqrt((dx * dx) + (dy * dy)) >= scaledTouchSlop;
}
if (isDragging) {
if (getDrawable() != null) {
suppMatrix.postTranslate(dx, dy);
checkAndDisplayMatrix();
}
lastTouchX = x;
lastTouchY = y;
if (velocityTracker != null) {
velocityTracker.addMovement(event);
}
}
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
lastPointerCount = 0;
if (velocityTracker != null) {
velocityTracker.recycle();
velocityTracker = null;
}
break;
}
return true;
}
@Override
public boolean onDoubleTap(MotionEvent event) {
try {
float scale = getScale();
float x = getWidth() / 2;
float y = getHeight() / 2;
if (scale < midScale) {
post(new AnimatedZoomRunnable(scale, midScale, x, y));
} else if ((scale >= midScale) && (scale < maxScale)) {
post(new AnimatedZoomRunnable(scale, maxScale, x, y));
} else {
post(new AnimatedZoomRunnable(scale, minScale, x, y));
}
} catch (Exception e) {
// Can sometimes happen when getX() and getY() is called
}
return true;
}
}
private class AnimatedZoomRunnable implements Runnable {
// These are 'postScale' values, means they're compounded each iteration
static final float ANIMATION_SCALE_PER_ITERATION_IN = 1.07f;
static final float ANIMATION_SCALE_PER_ITERATION_OUT = 0.93f;
private final float focalX, focalY;
private final float targetZoom;
private final float deltaScale;
public AnimatedZoomRunnable(final float currentZoom, final float targetZoom,
final float focalX, final float focalY) {
this.targetZoom = targetZoom;
this.focalX = focalX;
this.focalY = focalY;
if (currentZoom < targetZoom) {
deltaScale = ANIMATION_SCALE_PER_ITERATION_IN;
} else {
deltaScale = ANIMATION_SCALE_PER_ITERATION_OUT;
}
}
public void run() {
suppMatrix.postScale(deltaScale, deltaScale, focalX, focalY);
checkAndDisplayMatrix();
final float currentScale = getScale();
if (((deltaScale > 1f) && (currentScale < targetZoom))
|| ((deltaScale < 1f) && (targetZoom < currentScale))) {
// We haven't hit our target scale yet, so post ourselves
// again
postOnAnimation(ClipImageView.this, this);
} else {
// We've scaled past our target zoom, so calculate the
// necessary scale so we're back at target zoom
final float delta = targetZoom / currentScale;
suppMatrix.postScale(delta, delta, focalX, focalY);
checkAndDisplayMatrix();
}
}
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
private void postOnAnimation(View view, Runnable runnable) {
if (VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {
view.postOnAnimation(runnable);
} else {
view.postDelayed(runnable, 16);
}
}
/**
* Returns the current scale value
*
* @return float - current scale value
*/
public final float getScale() {
suppMatrix.getValues(matrixValues);
return matrixValues[Matrix.MSCALE_X];
}
@Override
public void onGlobalLayout() {
if(isJusted){
return;
}
// 调剂视图位置
configPosition();
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
getViewTreeObserver().addOnGlobalLayoutListener(this);
}
@SuppressWarnings("deprecation")
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
/**
* Helper method that simply checks the Matrix, and then displays the result
*/
private void checkAndDisplayMatrix() {
checkMatrixBounds();
setImageMatrix(getDisplayMatrix());
}
private void checkMatrixBounds() {
final RectF rect = getDisplayRect(getDisplayMatrix());
if (null == rect) {
return;
}
float deltaX = 0, deltaY = 0;
final float viewWidth = getWidth();
final float viewHeight = getHeight();
// 判断移动或缩放后,图片显示是不是超越裁剪框边界
if(rect.top > (viewHeight - borderlength) / 2){
deltaY = (viewHeight - borderlength) / 2 - rect.top;
}
if(rect.bottom < (viewHeight + borderlength) / 2){
deltaY = (viewHeight + borderlength) / 2 - rect.bottom;
}
if(rect.left > (viewWidth - borderlength) / 2){
deltaX = (viewWidth - borderlength) / 2 - rect.left;
}
if(rect.right < (viewWidth + borderlength) / 2){
deltaX = (viewWidth + borderlength) / 2 - rect.right;
}
// Finally actually translate the matrix
suppMatrix.postTranslate(deltaX, deltaY);
}
/**
* Helper method that maps the supplied Matrix to the current Drawable
*
* @param matrix
* - Matrix to map Drawable against
* @return RectF - Displayed Rectangle
*/
private RectF getDisplayRect(Matrix matrix) {
Drawable d = getDrawable();
if (null != d) {
displayRect.set(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
matrix.mapRect(displayRect);
return displayRect;
}
return null;
}
/**
* Resets the Matrix back to FIT_CENTER, and then displays it.s
*/
private void resetMatrix() {
if(suppMatrix == null){
return;
}
suppMatrix.reset();
setImageMatrix(getDisplayMatrix());
}
protected Matrix getDisplayMatrix() {
drawMatrix.set(baseMatrix);
drawMatrix.postConcat(suppMatrix);
return drawMatrix;
}
/**
* 剪切图片,返回剪切后的bitmap对象
*
* @return
*/
public Bitmap clip(){
Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
draw(canvas);
return Bitmap.createBitmap(bitmap, (getWidth() - borderlength) / 2, (getHeight() - borderlength) / 2, borderlength, borderlength);
}
}
ClipView类
/**
* 裁剪边框
*
* @author king
* @time 2014⑹⑴8 下午3:53:00
*/
public class ClipView extends View {
/**
* 边框距左右侧界距离,用于调剂边框长度
*/
public static final int BORDERDISTANCE = 50;
private Paint mPaint;
public ClipView(Context context) {
this(context, null);
}
public ClipView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ClipView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mPaint = new Paint();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int width = this.getWidth();
int height = this.getHeight();
// 边框长度,据屏幕左右侧缘50px
int borderlength = width - BORDERDISTANCE *2;
mPaint.setColor(0xaa000000);
// 以下绘制透明暗色区域
// top
canvas.drawRect(0, 0, width, (height - borderlength) / 2, mPaint);
// bottom
canvas.drawRect(0, (height + borderlength) / 2, width, height, mPaint);
// left
canvas.drawRect(0, (height - borderlength) / 2, BORDERDISTANCE,
(height + borderlength) / 2, mPaint);
// right
canvas.drawRect(borderlength + BORDERDISTANCE, (height - borderlength) / 2, width,
(height + borderlength) / 2, mPaint);
// 以下绘制边框线
mPaint.setColor(Color.WHITE);
mPaint.setStrokeWidth(2.0f);
// top
canvas.drawLine(BORDERDISTANCE, (height - borderlength) / 2, width - BORDERDISTANCE, (height - borderlength) / 2, mPaint);
// bottom
canvas.drawLine(BORDERDISTANCE, (height + borderlength) / 2, width - BORDERDISTANCE, (height + borderlength) / 2, mPaint);
// left
canvas.drawLine(BORDERDISTANCE, (height - borderlength) / 2, BORDERDISTANCE, (height + borderlength) / 2, mPaint);
// right
canvas.drawLine(width - BORDERDISTANCE, (height - borderlength) / 2, width - BORDERDISTANCE, (height + borderlength) / 2, mPaint);
}
下面贴1下xml:
activiti_main:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black"
tools:context=".MainActivity" >
<com.example.test.widget.ClipImageView
android:id="@+id/src_pic"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
<com.example.test.widget.ClipView
android:id="@+id/clipview"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</RelativeLayout>
preview.xml:
<?xml version="1.0" encoding="utf⑻"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:background="@android:color/black" >
<ImageView
android:id="@+id/preview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/app_name" />
</LinearLayout>
主要的代码就是这些:
下面看1下最后的效果图:
需要源码的可以给我留言,或加QQ群
生活不易,码农辛苦
如果您觉得本网站对您的学习有所帮助,可以手机扫描二维码进行捐赠