您的位置:首页 > 移动开发 > 微信开发

Android 高仿微信头像截取 打造不一样的自定义控件

2016-11-26 13:15 357 查看
版权声明:本文为博主原创文章,未经博主允许不得转载。

目录(?)[+]
概述
效果分析
效果图
效果分析

ClipImageBorderView
ClipZoomImageView
不一样的自定义控件
ClipImageLayout

用法
布局文件
MainActivity
ShowImageActivity

转载请表明出处:http://blog.csdn.net/lmj623565791/article/details/39761281,本文出自:【张鸿洋的博客】

1、概述

前面已经写了关于检测手势识别的文章,如果不了解可以参考:Android
手势检测实战 打造支持缩放平移的图片预览效果(下)。首先本篇文章,将对之前博客的ZoomImageView代码进行些许的修改与改善,然后用到我们的本篇博客中去,实现仿微信的头像截取功能,当然了,个人觉得微信的截取头像功能貌似做得不太好,本篇博客准备去其糟粕,取其精华;最后还会见识到不一样的自定义控件的方式,也是在本人博客中首次出现,如果有兴趣可以读完本篇博客,希望可以启到抛砖引玉的效果。

2、效果分析

1、效果图:



我们来看看妹子的项链,嗯,妹子项链还是不错的~

2、效果分析

根据上面的效果,我们目测需要自定义两个控件,一个就是我们的可自由缩放移动的ImageView,一个就是那个白色的边框;然后一起放置到一个RelativeLayout中;最后对外公布一个裁剪的方法,返回一个Bitmap;

暂时的分析就这样,下面我们来写代码~

首先是白色框框那个自定义View,我们叫做ClipImageBorderView

3、ClipImageBorderView

分析下这个View,其实就是根据在屏幕中绘制一个正方形,正方形区域以外为半透明,绘制这个正方形需要与屏幕左右边距有个边距。

我们准备按如下图绘制:



按顺序在View的onDraw里面绘制上图中:1、2、3、4,四个半透明的区域,然后在中间正方形区域绘制一个正方形

下面看下代码:

[java]
view plain
copy

print?

package com.zhy.view;  
  
import android.content.Context;  
import android.graphics.Canvas;  
import android.graphics.Color;  
import android.graphics.Paint;  
import android.graphics.Paint.Style;  
import android.util.AttributeSet;  
import android.util.TypedValue;  
import android.view.View;  
/** 
 * @author zhy 
 * 
 */  
public class ClipImageBorderView extends View  
{  
    /** 
     * 水平方向与View的边距 
     */  
    private int mHorizontalPadding = 20;  
    /** 
     * 垂直方向与View的边距 
     */  
    private int mVerticalPadding;  
    /** 
     * 绘制的矩形的宽度 
     */  
    private int mWidth;  
    /** 
     * 边框的颜色,默认为白色 
     */  
    private int mBorderColor = Color.parseColor("#FFFFFF");  
    /** 
     * 边框的宽度 单位dp 
     */  
    private int mBorderWidth = 1;  
  
    private Paint mPaint;  
  
    public ClipImageBorderView(Context context)  
    {  
        this(context, null);  
    }  
  
    public ClipImageBorderView(Context context, AttributeSet attrs)  
    {  
        this(context, attrs, 0);  
    }  
  
    public ClipImageBorderView(Context context, AttributeSet attrs, int defStyle)  
    {  
        super(context, attrs, defStyle);  
        // 计算padding的px  
        mHorizontalPadding = (int) TypedValue.applyDimension(  
                TypedValue.COMPLEX_UNIT_DIP, mHorizontalPadding, getResources()  
                        .getDisplayMetrics());  
        mBorderWidth = (int) TypedValue.applyDimension(  
                TypedValue.COMPLEX_UNIT_DIP, mBorderWidth, getResources()  
                        .getDisplayMetrics());  
        mPaint = new Paint();  
        mPaint.setAntiAlias(true);  
    }  
  
    @Override  
    protected void onDraw(Canvas canvas)  
    {  
        super.onDraw(canvas);  
        //计算矩形区域的宽度  
        mWidth = getWidth() - 2 * mHorizontalPadding;  
        //计算距离屏幕垂直边界 的边距  
        mVerticalPadding = (getHeight() - mWidth) / 2;  
        mPaint.setColor(Color.parseColor("#aa000000"));  
        mPaint.setStyle(Style.FILL);  
        // 绘制左边1  
        canvas.drawRect(0, 0, mHorizontalPadding, getHeight(), mPaint);  
        // 绘制右边2  
        canvas.drawRect(getWidth() - mHorizontalPadding, 0, getWidth(),  
                getHeight(), mPaint);  
        // 绘制上边3  
        canvas.drawRect(mHorizontalPadding, 0, getWidth() - mHorizontalPadding,  
                mVerticalPadding, mPaint);  
        // 绘制下边4  
        canvas.drawRect(mHorizontalPadding, getHeight() - mVerticalPadding,  
                getWidth() - mHorizontalPadding, getHeight(), mPaint);  
        // 绘制外边框  
        mPaint.setColor(mBorderColor);  
        mPaint.setStrokeWidth(mBorderWidth);  
        mPaint.setStyle(Style.STROKE);  
        canvas.drawRect(mHorizontalPadding, mVerticalPadding, getWidth()  
                - mHorizontalPadding, getHeight() - mVerticalPadding, mPaint);  
  
    }  
  
}  



package com.zhy.view;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
/**
* @author zhy
*
*/
public class ClipImageBorderView extends View
{
/**
* 水平方向与View的边距
*/
private int mHorizontalPadding = 20;
/**
* 垂直方向与View的边距
*/
private int mVerticalPadding;
/**
* 绘制的矩形的宽度
*/
private int mWidth;
/**
* 边框的颜色,默认为白色
*/
private int mBorderColor = Color.parseColor("#FFFFFF");
/**
* 边框的宽度 单位dp
*/
private int mBorderWidth = 1;

private Paint mPaint;

public ClipImageBorderView(Context context)
{
this(context, null);
}

public ClipImageBorderView(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}

public ClipImageBorderView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
// 计算padding的px
mHorizontalPadding = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, mHorizontalPadding, getResources()
.getDisplayMetrics());
mBorderWidth = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, mBorderWidth, getResources()
.getDisplayMetrics());
mPaint = new Paint();
mPaint.setAntiAlias(true);
}

@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
//计算矩形区域的宽度
mWidth = getWidth() - 2 * mHorizontalPadding;
//计算距离屏幕垂直边界 的边距
mVerticalPadding = (getHeight() - mWidth) / 2;
mPaint.setColor(Color.parseColor("#aa000000"));
mPaint.setStyle(Style.FILL);
// 绘制左边1
canvas.drawRect(0, 0, mHorizontalPadding, getHeight(), mPaint);
// 绘制右边2
canvas.drawRect(getWidth() - mHorizontalPadding, 0, getWidth(),
getHeight(), mPaint);
// 绘制上边3
canvas.drawRect(mHorizontalPadding, 0, getWidth() - mHorizontalPadding,
mVerticalPadding, mPaint);
// 绘制下边4
canvas.drawRect(mHorizontalPadding, getHeight() - mVerticalPadding,
getWidth() - mHorizontalPadding, getHeight(), mPaint);
// 绘制外边框
mPaint.setColor(mBorderColor);
mPaint.setStrokeWidth(mBorderWidth);
mPaint.setStyle(Style.STROKE);
canvas.drawRect(mHorizontalPadding, mVerticalPadding, getWidth()
- mHorizontalPadding, getHeight() - mVerticalPadding, mPaint);

}

}
我们直接预设了一个水平方向的边距,根据边距计算出正方形的边长,接下来就是按照上图分别会1、2、3、4四个区域,最后就是绘制我们的正方形~~

代码还是很简单的~~我们的ClipImageBorderView就搞定了,我们决定来测试一下:

布局文件:

[html]
view plain
copy

print?

<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="@drawable/a"   >  
  
    <com.zhy.view.ClipImageBorderView  
        android:id="@+id/id_clipImageLayout"  
        android:layout_width="fill_parent"  
        android:layout_height="fill_parent" />  
  
</RelativeLayout>  



<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="@drawable/a"   >

<com.zhy.view.ClipImageBorderView
android:id="@+id/id_clipImageLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />

</RelativeLayout>


效果图:



故意放了个背景,没撒用,就是为了能看出效果,可以看到我们的框框绘制的还是蛮不错的~~嗯,这个框框距离屏幕左右两侧的距离应该抽取出来,嗯,后面再说~

4、ClipZoomImageView

我们准备对我们原先的ZoomImageView进行简单的修改,修改的地方:

1、在onGlobalLayout方法中,如果图片的宽或者高只要一个小于我们的正方形的边长,我们会直接把较小的尺寸放大至正方形的边长;如果图片的宽和高都大于我们的正方形的边长,我们仅仅把图片移动到我们屏幕的中央,不做缩放处理;

2、根据步骤1,我们会获得初始的缩放比例(默认为1.0f),然后SCALE_MID , 与 SCALE_MAX 分别为2倍和4倍的初始化缩放比例。

3、图片在移动过程中的边界检测完全根据正方形的区域,图片不会在移动过程中与正方形区域产生内边距

4、对外公布一个裁切的方法

部分代码:

[java]
view plain
copy

print?

/** 
     * 水平方向与View的边距 
     */  
    private int mHorizontalPadding = 20;  
    /** 
     * 垂直方向与View的边距 
     */  
    private int mVerticalPadding;  
  
    @Override  
    public void onGlobalLayout()  
    {  
        if (once)  
        {  
            Drawable d = getDrawable();  
            if (d == null)  
                return;  
            Log.e(TAG, d.getIntrinsicWidth() + " , " + d.getIntrinsicHeight());  
            // 计算padding的px  
            mHorizontalPadding = (int) TypedValue.applyDimension(  
                    TypedValue.COMPLEX_UNIT_DIP, mHorizontalPadding,  
                    getResources().getDisplayMetrics());  
            // 垂直方向的边距  
            mVerticalPadding = (getHeight() - (getWidth() - 2 * mHorizontalPadding)) / 2;  
  
            int width = getWidth();  
            int height = getHeight();  
            // 拿到图片的宽和高  
            int dw = d.getIntrinsicWidth();  
            int dh = d.getIntrinsicHeight();  
            float scale = 1.0f;  
            if (dw < getWidth() - mHorizontalPadding * 2  
                    && dh > getHeight() - mVerticalPadding * 2)  
            {  
                scale = (getWidth() * 1.0f - mHorizontalPadding * 2) / dw;  
            }  
  
            if (dh < getHeight() - mVerticalPadding * 2  
                    && dw > getWidth() - mHorizontalPadding * 2)  
            {  
                scale = (getHeight() * 1.0f - mVerticalPadding * 2) / dh;  
            }  
  
            if (dw < getWidth() - mHorizontalPadding * 2  
                    && dh < getHeight() - mVerticalPadding * 2)  
            {  
                float scaleW = (getWidth() * 1.0f - mHorizontalPadding * 2)  
                        / dw;  
                float scaleH = (getHeight() * 1.0f - mVerticalPadding * 2) / dh;  
                scale = Math.max(scaleW, scaleH);  
            }  
  
            initScale = scale;  
            SCALE_MID = initScale * 2;  
            SCALE_MAX = initScale * 4;  
            Log.e(TAG, "initScale = " + initScale);  
            mScaleMatrix.postTranslate((width - dw) / 2, (height - dh) / 2);  
            mScaleMatrix.postScale(scale, scale, getWidth() / 2,  
                    getHeight() / 2);  
            // 图片移动至屏幕中心  
            setImageMatrix(mScaleMatrix);  
            once = false;  
        }  
  
    }  
  
    /** 
     * 剪切图片,返回剪切后的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, mHorizontalPadding,  
                mVerticalPadding, getWidth() - 2 * mHorizontalPadding,  
                getWidth() - 2 * mHorizontalPadding);  
    }  
      
    /** 
     * 边界检测 
     */  
    private void checkBorder()  
    {  
  
        RectF rect = getMatrixRectF();  
        float deltaX = 0;  
        float deltaY = 0;  
  
        int width = getWidth();  
        int height = getHeight();  
  
        // 如果宽或高大于屏幕,则控制范围  
        if (rect.width() >= width - 2 * mHorizontalPadding)  
        {  
            if (rect.left > mHorizontalPadding)  
            {  
                deltaX = -rect.left + mHorizontalPadding;  
            }  
            if (rect.right < width - mHorizontalPadding)  
            {  
                deltaX = width - mHorizontalPadding - rect.right;  
            }  
        }  
        if (rect.height() >= height - 2 * mVerticalPadding)  
        {  
            if (rect.top > mVerticalPadding)  
            {  
                deltaY = -rect.top + mVerticalPadding;  
            }  
            if (rect.bottom < height - mVerticalPadding)  
            {  
                deltaY = height - mVerticalPadding - rect.bottom;  
            }  
        }  
        mScaleMatrix.postTranslate(deltaX, deltaY);  
  
    }  



/**
* 水平方向与View的边距
*/
private int mHorizontalPadding = 20;
/**
* 垂直方向与View的边距
*/
private int mVerticalPadding;

@Override
public void onGlobalLayout()
{
if (once)
{
Drawable d = getDrawable();
if (d == null)
return;
Log.e(TAG, d.getIntrinsicWidth() + " , " + d.getIntrinsicHeight());
// 计算padding的px
mHorizontalPadding = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, mHorizontalPadding,
getResources().getDisplayMetrics());
// 垂直方向的边距
mVerticalPadding = (getHeight() - (getWidth() - 2 * mHorizontalPadding)) / 2;

int width = getWidth();
int height = getHeight();
// 拿到图片的宽和高
int dw = d.getIntrinsicWidth();
int dh = d.getIntrinsicHeight();
float scale = 1.0f;
if (dw < getWidth() - mHorizontalPadding * 2
&& dh > getHeight() - mVerticalPadding * 2)
{
scale = (getWidth() * 1.0f - mHorizontalPadding * 2) / dw;
}

if (dh < getHeight() - mVerticalPadding * 2
&& dw > getWidth() - mHorizontalPadding * 2)
{
scale = (getHeight() * 1.0f - mVerticalPadding * 2) / dh;
}

if (dw < getWidth() - mHorizontalPadding * 2
&& dh < getHeight() - mVerticalPadding * 2)
{
float scaleW = (getWidth() * 1.0f - mHorizontalPadding * 2)
/ dw;
float scaleH = (getHeight() * 1.0f - mVerticalPadding * 2) / dh;
scale = Math.max(scaleW, scaleH);
}

initScale = scale;
SCALE_MID = initScale * 2;
SCALE_MAX = initScale * 4;
Log.e(TAG, "initScale = " + initScale);
mScaleMatrix.postTranslate((width - dw) / 2, (height - dh) / 2);
mScaleMatrix.postScale(scale, scale, getWidth() / 2,
getHeight() / 2);
// 图片移动至屏幕中心
setImageMatrix(mScaleMatrix);
once = false;
}

}

/**
* 剪切图片,返回剪切后的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, mHorizontalPadding,
mVerticalPadding, getWidth() - 2 * mHorizontalPadding,
getWidth() - 2 * mHorizontalPadding);
}

/**
* 边界检测
*/
private void checkBorder()
{

RectF rect = getMatrixRectF();
float deltaX = 0;
float deltaY = 0;

int width = getWidth();
int height = getHeight();

// 如果宽或高大于屏幕,则控制范围
if (rect.width() >= width - 2 * mHorizontalPadding)
{
if (rect.left > mHorizontalPadding)
{
deltaX = -rect.left + mHorizontalPadding;
}
if (rect.right < width - mHorizontalPadding)
{
deltaX = width - mHorizontalPadding - rect.right;
}
}
if (rect.height() >= height - 2 * mVerticalPadding)
{
if (rect.top > mVerticalPadding)
{
deltaY = -rect.top + mVerticalPadding;
}
if (rect.bottom < height - mVerticalPadding)
{
deltaY = height - mVerticalPadding - rect.bottom;
}
}
mScaleMatrix.postTranslate(deltaX, deltaY);

}


这里贴出了改变的代码,完整的代码就不贴了,太长了,如果大家学习过前面的博客应该也会比较熟悉,若没有也没事,后面会提供源码。

贴代码的目的,第一让大家看下我们改变了哪些;第二,我想暴露出我们代码中的问题,我们设置了一个这样的变量:mHorizontalPadding = 20;这个是手动和ClipImageBorderView里面的成员变量mHorizontalPadding 写的一致,也就是说这个变量,两个自定义的View都需要使用且需要相同的值,目前我们的做法,写死且每个View各自定义一个。这种做法不用说,肯定不好,即使抽取成自定义属性,两个View都需要进行抽取,且用户在使用的时候,还需要设置为一样的值,总觉得有点强人所难~~

5、不一样的自定义控件

现在我们考虑下:易用性。目前为止,其实我们的效果已经实现了,但是需要用户这么写布局文件:

[html]
view plain
copy

print?

<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="#aaaaaa" >  
  
    <com.zhy.view.ZoomImageView  
        android:id="@+id/id_zoomImageView"  
        android:layout_width="fill_parent"  
        android:layout_height="fill_parent"  
        android:scaleType="matrix"  
        android:src="@drawable/a" />  
  
    <com.zhy.view.ClipImageView  
        android:layout_width="fill_parent"  
        android:layout_height="fill_parent" />  
  
</RelativeLayout>  



<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="#aaaaaa" >

<com.zhy.view.ZoomImageView
android:id="@+id/id_zoomImageView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="matrix"
android:src="@drawable/a" />

<com.zhy.view.ClipImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent" />

</RelativeLayout>


然后这两个类中都有一个mHorizontalPadding变量,且值一样,上面也说过,即使抽取成自定义变量,也需要在布局文件中每个View中各写一次。so, we need change . 这样的耦合度太夸张了,且使用起来蹩脚。

于是乎,我决定把这两个控件想办法整到一起,用户使用时只需要声明一个控件:

怎么做呢,我们使用组合的思想来自定义控件,我们再声明一个控件,继承子RelativeLayout,然后在这个自定义RelativeLayout中通过代码添加这两个自定义的布局,并且设置一些公用的属性,具体我们就开始行动。

1、ClipImageLayout

我们自定义一个RelativeLayout叫做ClipImageLayout,用于放置我们的两个自定义View,并且由ClipImageLayout进行设置边距,然后传给它内部的两个View,这样的话,跟用户交互的就一个ClipImageLayout,用户只需要设置一次边距即可。

完整的ClipImageLayout代码:

[java]
view plain
copy

print?

package com.zhy.view;  
  
import android.content.Context;  
import android.graphics.Bitmap;  
import android.util.AttributeSet;  
import android.util.TypedValue;  
import android.widget.RelativeLayout;  
  
import com.zhy.clippic.R;  
/** 
 * zhy 
 * @author zhy 
 * 
 */  
public class ClipImageLayout extends RelativeLayout  
{  
  
    private ClipZoomImageView mZoomImageView;  
    private ClipImageBorderView mClipImageView;  
  
    /** 
     * 这里测试,直接写死了大小,真正使用过程中,可以提取为自定义属性 
     */  
    private int mHorizontalPadding = 20;  
  
    public ClipImageLayout(Context context, AttributeSet attrs)  
    {  
        super(context, attrs);  
  
        mZoomImageView = new ClipZoomImageView(context);  
        mClipImageView = new ClipImageBorderView(context);  
  
        android.view.ViewGroup.LayoutParams lp = new LayoutParams(  
                android.view.ViewGroup.LayoutParams.MATCH_PARENT,  
                android.view.ViewGroup.LayoutParams.MATCH_PARENT);  
          
        /** 
         * 这里测试,直接写死了图片,真正使用过程中,可以提取为自定义属性 
         */  
        mZoomImageView.setImageDrawable(getResources().getDrawable(  
                R.drawable.a));  
          
        this.addView(mZoomImageView, lp);  
        this.addView(mClipImageView, lp);  
  
          
        // 计算padding的px  
        mHorizontalPadding = (int) TypedValue.applyDimension(  
                TypedValue.COMPLEX_UNIT_DIP, mHorizontalPadding, getResources()  
                        .getDisplayMetrics());  
        mZoomImageView.setHorizontalPadding(mHorizontalPadding);  
        mClipImageView.setHorizontalPadding(mHorizontalPadding);  
    }  
  
    /** 
     * 对外公布设置边距的方法,单位为dp 
     *  
     * @param mHorizontalPadding 
     */  
    public void setHorizontalPadding(int mHorizontalPadding)  
    {  
        this.mHorizontalPadding = mHorizontalPadding;  
    }  
  
    /** 
     * 裁切图片 
     *  
     * @return 
     */  
    public Bitmap clip()  
    {  
        return mZoomImageView.clip();  
    }  
  
}  



package com.zhy.view;

import android.content.Context;
import android.graphics.Bitmap;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.RelativeLayout;

import com.zhy.clippic.R;
/**
* zhy
* @author zhy
*
*/
public class ClipImageLayout extends RelativeLayout
{

private ClipZoomImageView mZoomImageView;
private ClipImageBorderView mClipImageView;

/**
* 这里测试,直接写死了大小,真正使用过程中,可以提取为自定义属性
*/
private int mHorizontalPadding = 20;

public ClipImageLayout(Context context, AttributeSet attrs)
{
super(context, attrs);

mZoomImageView = new ClipZoomImageView(context);
mClipImageView = new ClipImageBorderView(context);

android.view.ViewGroup.LayoutParams lp = new LayoutParams(
android.view.ViewGroup.LayoutParams.MATCH_PARENT,
android.view.ViewGroup.LayoutParams.MATCH_PARENT);

/**
* 这里测试,直接写死了图片,真正使用过程中,可以提取为自定义属性
*/
mZoomImageView.setImageDrawable(getResources().getDrawable(
R.drawable.a));

this.addView(mZoomImageView, lp);
this.addView(mClipImageView, lp);

// 计算padding的px
mHorizontalPadding = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, mHorizontalPadding, getResources()
.getDisplayMetrics());
mZoomImageView.setHorizontalPadding(mHorizontalPadding);
mClipImageView.setHorizontalPadding(mHorizontalPadding);
}

/**
* 对外公布设置边距的方法,单位为dp
*
* @param mHorizontalPadding
*/
public void setHorizontalPadding(int mHorizontalPadding)
{
this.mHorizontalPadding = mHorizontalPadding;
}

/**
* 裁切图片
*
* @return
*/
public Bitmap clip()
{
return mZoomImageView.clip();
}

}


可以看到,现在用户需要使用头像裁切功能只需要声明下ClipImageLayout即可,完全避免了上述我们描述的问题,我们对用户屏蔽了两个真正实现的类。这个也是自定义控件的一种方式,希望可以借此抛砖引玉,大家能够更加合理的设计出自己的控件~~

好了,我们的ClipImageLayout搞定以后,下面看下如何使用~

6、用法

1、布局文件

[html]
view plain
copy

print?

<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="#aaaaaa"   >  
  
    <com.zhy.view.ClipImageLayout  
        android:id="@+id/id_clipImageLayout"  
        android:layout_width="fill_parent"  
        android:layout_height="fill_parent" />  
  
</RelativeLayout>  



<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="#aaaaaa"   >

<com.zhy.view.ClipImageLayout
android:id="@+id/id_clipImageLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />

</RelativeLayout>

2、MainActivity

[java]
view plain
copy

print?

package com.zhy.clippic;  
  
import java.io.ByteArrayOutputStream;  
  
import android.app.Activity;  
import android.content.Intent;  
import android.graphics.Bitmap;  
import android.os.Bundle;  
import android.view.Menu;  
import android.view.MenuItem;  
  
import com.zhy.view.ClipImageLayout;  
  
public class MainActivity extends Activity  
{  
    private ClipImageLayout mClipImageLayout;  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState)  
    {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
  
        mClipImageLayout = (ClipImageLayout) findViewById(R.id.id_clipImageLayout);  
  
    }  
  
    @Override  
    public boolean onCreateOptionsMenu(Menu menu)  
    {  
        getMenuInflater().inflate(R.menu.main, menu);  
        return true;  
    }  
  
    @Override  
    public boolean onOptionsItemSelected(MenuItem item)  
    {  
        switch (item.getItemId())  
        {  
        case R.id.id_action_clip:  
            Bitmap bitmap = mClipImageLayout.clip();  
              
            ByteArrayOutputStream baos = new ByteArrayOutputStream();  
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);  
            byte[] datas = baos.toByteArray();  
              
            Intent intent = new Intent(this, ShowImageActivity.class);  
            intent.putExtra("bitmap", datas);  
            startActivity(intent);  
  
            break;  
        }  
        return super.onOptionsItemSelected(item);  
    }  
}  



package com.zhy.clippic;

import java.io.ByteArrayOutputStream;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

import com.zhy.view.ClipImageLayout;

public class MainActivity extends Activity
{
private ClipImageLayout mClipImageLayout;

@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

mClipImageLayout = (ClipImageLayout) findViewById(R.id.id_clipImageLayout);

}

@Override
public boolean onCreateOptionsMenu(Menu menu)
{
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case R.id.id_action_clip:
Bitmap bitmap = mClipImageLayout.clip();

ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
byte[] datas = baos.toByteArray();

Intent intent = new Intent(this, ShowImageActivity.class);
intent.putExtra("bitmap", datas);
startActivity(intent);

break;
}
return super.onOptionsItemSelected(item);
}
}


我们在menu里面体检了一个裁切的按钮,点击后把裁切好的图片传递给我们的ShowImageActivity

看一下眼menu的xml

[html]
view plain
copy

print?

<menu xmlns:android="http://schemas.android.com/apk/res/android" >  
  
    <item  
        android:id="@+id/id_action_clip"  
        android:icon="@drawable/actionbar_clip_icon"  
        android:showAsAction="always|withText"  
        android:title="裁切"/>  
  
</menu>  



<menu xmlns:android="http://schemas.android.com/apk/res/android" >

<item
android:id="@+id/id_action_clip"
android:icon="@drawable/actionbar_clip_icon"
android:showAsAction="always|withText"
android:title="裁切"/>

</menu>

3、ShowImageActivity

[java]
view plain
copy

print?

package com.zhy.clippic;  
  
  
import android.app.Activity;  
import android.graphics.Bitmap;  
import android.graphics.BitmapFactory;  
import android.os.Bundle;  
import android.widget.ImageView;  
  
  
public class ShowImageActivity extends Activity  
{  
    private ImageView mImageView;  
  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState)  
    {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.show);  
  
  
        mImageView = (ImageView) findViewById(R.id.id_showImage);  
        byte[] b = getIntent().getByteArrayExtra("bitmap");  
        Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);  
        if (bitmap != null)  
        {  
            mImageView.setImageBitmap(bitmap);  
        }  
    }  
}  



package com.zhy.clippic;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.widget.ImageView;

public class ShowImageActivity extends Activity
{
private ImageView mImageView;

@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.show);

mImageView = (ImageView) findViewById(R.id.id_showImage);
byte[] b = getIntent().getByteArrayExtra("bitmap");
Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length);
if (bitmap != null)
{
mImageView.setImageBitmap(bitmap);
}
}
}


layout/show.xml

[html]
view plain
copy

print?

<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="#ffffff" >  
  
    <ImageView  
        android:id="@+id/id_showImage"  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:layout_centerInParent="true"  
        android:src="@drawable/tbug"  
         />  
  
</RelativeLayout>  



<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="#ffffff" >

<ImageView
android:id="@+id/id_showImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:src="@drawable/tbug"
/>

</RelativeLayout>


好了,到此我们的 高仿微信头像截取功能 就已经结束了~~希望大家可以从本篇博客中可以领悟到something~

最后我们把ClipImageLayout里面的mHorizontalPadding设置为50,贴个静态效果图~



ok ~~

源码点击下载

博主部分视频已经上线,如果你不喜欢枯燥的文本,请猛戳(初录,期待您的支持):

1、高仿微信5.2.1主界面及消息提醒

2、高仿QQ5.0侧滑
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: