仿腾讯QQ拍照 背景图片滑动获取图片

1.首先我们来看一下效果图片

2.再看一下项目结构

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,此处使用二进制数组传递
			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-6-18 下午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);
	}

下面贴一下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-8"?>
<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>

主要的代码就是这些:

下面看一下最后的效果图:

需要源码的可以给我留言,或者加QQ群

    96843339    我会及时给你回复。
时间: 2024-09-29 09:58:27

仿腾讯QQ拍照 背景图片滑动获取图片的相关文章

【学习笔记】&quot;ListView滑动删除 ,仿腾讯QQ&quot;(二)

今天继续学习"鸿祥_"大神的写的"ListView滑动删除,仿腾讯QQ" . 1.关于dispatchTouchEvent 之前,只用过onTouchEvent,现在才知道一个Touch事件居然如此复杂.OK,集中精力,且看下文(本段内容主要参考Android dispatchTouchEvent介绍): 一个最简单的屏幕触摸动作触发了一系列Touch事件:ACTION_DOWN->ACTION_MOVE->ACTION_MOVE->ACTION_

【学习笔记】&quot;ListView滑动删除 ,仿腾讯QQ&quot;(一)

今天看了"鸿祥_"大神的写的"ListView滑动删除,仿腾讯QQ" .大神果然是大神,第一篇文章,我就看不懂,好多知识需要学习. 1.  文中的一个声明:private LayoutInflater mInflater; 什么是LayoutInflater? 答:主要参考了这篇文章 Android LayoutInflater详解 在实际开发中LayoutInflater这个类还是非常有用的,它的作用类似于findViewById().不同点是LayoutInfl

【学习笔记】&quot;ListView滑动删除 ,仿腾讯QQ&quot;(三)

今天继续学习"鸿祥_"大神的写的"ListView滑动删除,仿腾讯QQ" . 今天,我准备学习并理清QQListView的逻辑. 1.自定义ListView 先看看布局文件activity_main.xml: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.c

添加资源图片,获取图片实例并绘制到窗体

项目右键属性——资源——添加资源展开——添加现有文件 paint方法中: private void Form1_Paint(object sender, PaintEventArgs e) { using (Graphics g = e.Graphics) { g.DrawImage((Image)zhbImgConvert.Properties.Resources.ResourceManager.GetObject("_001"), 10, 70); } } 添加资源图片,获取图片实

.net 根据图片网络地址获取图片二进制字节数据流

/// <summary> ///根据html路径获取图片的字节 /// </summary> /// <param name="picSize">图片尺寸,原图:1,大图:2,中图:3,小图:4</param> /// <param name="serverPath">图片服务器地址</param> /// <returns></returns> public stat

Qt 打开安卓相册选择图片并获取图片的本地路径

Qt 打开安卓相册选择图片并获取图片的本地路径 步骤如下: 通过 Intent 打开安卓的系统相册. 推荐使用 QAndroidJniObject::getStaticObjectField 获取静态字段. QAndroidJniObject action = QAndroidJniObject::getStaticObjectField( "android/content/Intent", "ACTION_GET_CONTENT", "Ljava/lan

Android 拍照或者从相册获取图片的实现

我们常常会用到上传头像,或者发帖子的时候选择本地图片上传的功能.这个很常见 今天因为app的需求我研究了下.现在分享下. 其实不论是通过拍照还是从相册选取都会用到Intent 这是系统提供给我们用来调用系统方法的好用工具! 首先,需要设计下我们想怎么调用系统的拍照或者选取图片的方法 我们可以点击头像或者一个按钮然后弹出一个对话框,让用户自己 选择是拍照还是选择图片(如下图) . 那这个对话框怎么写呢.通过AlertDialog来实现(我们就给这个方法起名叫dialog): //对头像操作 pri

android 根据图片名字获取图片id

public int getResource(String imageName){ Context ctx=getBaseContext(); int resId = getResources().getIdentifier(imageName, "drawable" , ctx.getPackageName()); return resId } 获取的是drawable文件夹下的图片,而且图片文件名不要带后缀.比如想要获取drawable文件夹下的home.jpg,只需调用getRe

iOS获取相册/相机图片-------自定义获取图片小控件

一.功能简介 1.封装了一个按钮,点击按钮,会提示从何处获取图片:如果设备支持相机,可以从相机获取,同时还可以从手机相册获取图片. 2.选择图片后,有一个block回调,根据需求,将获得的图片拿来使用. 3.提供了初始化方法,可以灵活定义按钮,包括把返回的图片设置给按钮自己. 二.核心原理 1.UIAlertController 提示框 2.UIImagePickerController 图片拾取控制器 3.isSourceTypeAvailable:UIImagePickerControlle