Android:自定义imageview实现两条线裁剪图片,不在区域内显示阴影

MainActivity

package com.example.customimageview;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.ScrollView;

public class MainActivity extends Activity {

    private static final String TAG = "customimageview";
    private MyImageView img;
    private ScrollView sv;
    private static final String CROP_IMAGE_PATH = "/storage/emulated/0/3.png";


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

        Bitmap bmp = BitmapFactory.decodeFile(CROP_IMAGE_PATH);
        img = (MyImageView) findViewById(R.id.long_pic);
        img.setImageBitmap(bmp);
        Button btn = (Button) findViewById(R.id.btn);
        Log.i(TAG, "onCreate ");
        sv = (ScrollView) findViewById(R.id.scrollView);
        btn.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                Log.i(TAG, "onClick(View v) enter");
                savedBitmap(img.getClippedBitmap());
            }
        });

        sv.setOnTouchListener(new View.OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                // TODO Auto-generated method stub
                img.getParent().requestDisallowInterceptTouchEvent(false);
                return false;
            }
        });
    }

    private void savedBitmap(Bitmap bitmap) {
        Log.i(TAG, "savedBitmap(Bitmap bitmap)");
        if (bitmap != null) {
            Log.i(TAG, "bitmap != null");
            try {
                long current = System.currentTimeMillis();
                Date date = new Date(current);
                SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
                String filename = format.format(date);
                StringBuilder builder = new StringBuilder();
                builder.append(filename);
                builder.append(".png");
                filename = builder.toString();
                File fileImage = new File("/sdcard/", filename);
                if (!fileImage.exists()) {
                    fileImage.createNewFile();
                    Log.i(TAG, "image file created");
                }
                FileOutputStream out = new FileOutputStream(fileImage);
                if (out != null) {
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
                    out.flush();
                    out.close();
                    Intent media = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
                    Uri contentUri = Uri.fromFile(fileImage);
                    media.setData(contentUri);
                    this.sendBroadcast(media);
                    Log.i(TAG, "screen image saved");
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            Log.i(TAG, "savedBitmap(Bitmap bitmap) = null");
        }
    }
}

activity_mainxml文件

<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"
    tools:context="${relativePackage}.${activityClass}" >

    <Button
        android:id="@+id/btn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:text="save" />

    <ScrollView
        android:id="@+id/scrollView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/btn"
        android:layout_centerHorizontal="true" >

        <LinearLayout
            android:id="@+id/Linear"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentEnd="true"
            android:layout_below="@+id/top_text"
            android:layout_marginLeft="10dp"
            android:layout_marginRight="10dp"
            android:orientation="vertical" >

            <com.example.customimageview.MyImageView
                android:id="@+id/long_pic"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal" />
        </LinearLayout>
    </ScrollView>

</RelativeLayout>

自定义ImageView实现裁剪图片

package com.example.customimageview;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
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.MotionEvent;
import android.widget.ImageView;

/**
 * 图片剪裁控件; 注意事项: 1.在为ClipImageView设置图片时(调用setImageResource(),
 * setImageDrawable(), setImageBitmap()),要注意图片的大小,即注意Bitmap可能导致 程序出现oom的问题。
 * 2.如对剪裁图片质量无过高要求,建议调用setImageResourceSecure(), setImageDrawableSecure(),
 * setImageBitmapSecure()设置图片。
 * 
 */
public class MyImageView extends ImageView {

    private static final String TAG = "customimageview";

    /**
     * mClipFrameBorderWidth:剪裁框的边框宽度;TOUCH_FIELD:触摸范围;UP_DOWN_LENGTH:剪裁最小高度
     */
    private final float density = getResources().getDisplayMetrics().density; // 密度
    private float mClipFrameBorderWidth = 1 * density; // 剪裁框的边框宽度
    private static final float TOUCH_FIELD = 20f;
    private static final float UP_DOWN_LENGTH = 50f;

    /**
     * 初始图片大小
     */
    private int imWidth;
    private int imHeight;

    private boolean showClipFrame = true; // 是否显示剪裁框

    private String mClipFrameColor = "#FFFFFFFF"; // 剪裁框的边框颜色
    private String mShadowColor = "#99000000"; // 阴影颜色

    private Paint mShadowPaint;
    private Paint mClipFramePaint;
    /**
     * 剪裁框外的阴影
     */
    private Rect mRectTopShadow;
    private Rect mRectBottomShadow;
    /**
     * 剪裁框:顶部条和底部条
     */
    private int mTopLineY = 100; // 默认顶部条Y坐标
    private int mBottomLineY = 200; // 默认底部条Y坐标
    private int mLineWidth;

    private PointF mLastPoint = new PointF();

    private int mShadowUpY; // 顶部阴影高度
    private int mShadowDownY; // 底部阴影高度
    /**
     * 设置在ImageView中的Bitmap
     */
    private Bitmap source;

    /**
     * 触摸事件位置
     */
    private int touchPos;
    private static final int POS_TOP = 1;
    private static final int POS_BOTTOM = 2;
    private static final int POS_CENTER = 3;
    private boolean mInterceptTouchEvent;

    public MyImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        setAdjustViewBounds(true);

        initPaint();
        initRect();

        post(new Runnable() {

            @Override
            public void run() {
                imWidth = getWidth();
                imHeight = getHeight();

                Log.i(TAG, "imWidth: " + imWidth + " imHeight: " + imHeight);
                mLineWidth = imWidth;
                resolveClipFrameSize(); // 必要步骤,校正剪裁框大小,底部条不能超过图片大小

            }
        });
    }

    private void initPaint() {
        mShadowPaint = new Paint();
        mShadowPaint.setColor(Color.parseColor(mShadowColor));

        mClipFramePaint = new Paint();
        mClipFramePaint.setStyle(Paint.Style.STROKE); // 设置为空心
        mClipFramePaint.setStrokeWidth(mClipFrameBorderWidth); // 设置边框宽度
        setClipFrameColor(Color.BLUE); // 设置颜色
    }

    private void initRect() {
        /**
         * 阴影区域
         */
        mRectTopShadow = new Rect();
        mRectBottomShadow = new Rect();
    }

    /**
     * 设置剪裁框外的阴影
     * 
     * @param x
     *            剪裁框当前的左上角X坐标
     * @param y
     *            剪裁框当前的左上角Y坐标
     */

    /**
     * 方法已对resId指向的图片进行压缩处理, 用此方法设置图片,剪裁后的相片质量相对 较差,但可简单避免Bitmap的OOM;如需
     * 对原图进行裁剪,请直接调用setImageResource()
     * 
     * @param resId
     */
    public void setImageResourceSecure(int resId) {
        Bitmap bm = BitmapFactory.decodeResource(getResources(), resId);
        setImageBitmap(processBitmap(bm));
    }

    /**
     * 方法已对drawable指向的图片进行压缩处理, 用此方法设置图片,剪裁后的相片质量相对 较差,但可简单避免Bitmap的OOM;如需
     * 对原图进行裁剪,请直接调用setImageDrawable()
     * 
     * @param drawable
     */
    public void setImageDrawableSecure(Drawable drawable) {
        if (drawable == null)
            throw new IllegalArgumentException("drawable 不能为null");
        BitmapDrawable bd = (BitmapDrawable) drawable;
        setImageBitmap(processBitmap(bd.getBitmap()));
    }

    /**
     * 方法已对bm指向的图片进行压缩处理, 用此方法设置图片,剪裁后的相片质量相对 较差,但可简单避免Bitmap的OOM;如需
     * 对原图进行裁剪,请直接调用setImageBitmap()
     * 
     * @param bm
     */
    public void setImageBitmapSecure(Bitmap bm) {
        setImageBitmap(processBitmap(bm));
    }

    /**
     * 对Bitmap进行简单的处理,适当地压缩图片大小
     * 
     * @param bm
     * @return
     */
    private Bitmap processBitmap(Bitmap bm) {
        if (bm == null)
            throw new IllegalArgumentException("bitmap 不能为null");

        int screenWidth = getResources().getDisplayMetrics().widthPixels;
        int screenHeight = getResources().getDisplayMetrics().heightPixels;
        int bmWidth = bm.getWidth();
        int bmHeight = bm.getHeight();
        if (bmWidth < screenWidth || bmHeight < screenHeight)
            return bm;

        float scale = (float) screenWidth / bmWidth;
        Bitmap bitmap = Bitmap.createScaledBitmap(bm, screenWidth, (int) (bmHeight * scale), true);
        bm.recycle();
        return bitmap;
    }

    /**
     * 获取设置在ClipImageView中的Bitmap
     * 
     * @return
     */
    public Bitmap getSourceBitmap() {
        if (source != null)
            return source;

        Drawable d = getDrawable();
        if (d == null) {
            return null;
        }

        BitmapDrawable bd = (BitmapDrawable) d;
        source = bd.getBitmap();
        return source;
    }

    /**
     * 获取ImageView对原图的缩放比例
     * 
     * @return
     */
    public float getScale() {
        if (getSourceBitmap() == null)
            return 0f;

        int bmWidth = source.getWidth();
        int bmHeight = source.getHeight();
        float scale = Math.min((float) bmWidth / imWidth, (float) bmHeight / imHeight);
        return scale;
    }

    /**
     * 获取剪裁好的bitmap
     * 
     * @return
     */
    public Bitmap getClippedBitmap() {
        float scale = getScale();
        Log.i(TAG, "getClippedBitmap() scale: " + scale);
        if (scale > 0 && source != null) {
            /*
             * Log.i(TAG, "ClipImageUtils.clipImage() currX: "+currX+" currY: "+
             * currY+" mClipFrameWidth: "+mClipFrameWidth+" mClipFrameHeight: "
             * +mClipFrameHeight);
             */

            return ClipImageUtils.clipImage(source, 0, mTopLineY, // 剪裁图片
                    imWidth, mBottomLineY - mTopLineY, scale);
        }
        return null;
    }

    /**
     * 设置剪裁框边框的颜色,支持#RRGGBB #AARRGGBB 'red', 'blue', 'green', 'black', 'white',
     * 'gray', 'cyan', 'magenta', 'yellow', 'lightgray', 'darkgray', 'grey',
     * 'lightgrey', 'darkgrey', 'aqua', 'fuschia', 'lime', 'maroon', 'navy',
     * 'olive', 'purple', 'silver', 'teal'
     * 
     * @param color
     */
    public void setClipFrameColor(String color) {
        mClipFramePaint.setColor(Color.parseColor(color));
    }

    public void setClipFrameColor(int color) {
        mClipFramePaint.setColor(color);
    }

    /**
     * 校正裁剪框的高,使其不能超过View的高
     */
    private void resolveClipFrameSize() {
        mBottomLineY = mBottomLineY >= imHeight ? imHeight : mBottomLineY;
    }

    /**
     * 设置剪裁框的边框宽度
     * 
     * @param w
     */
    public void setClipFrameBorderWidth(float w) {
        w = w < 0 ? 0 : w;
        mClipFrameBorderWidth = w;
        mClipFramePaint.setStrokeWidth(mClipFrameBorderWidth);
    }

    /**
     * 顶部条的Y坐标
     * 
     * @return
     */
    public float getContentX() {
        return mTopLineY;
    }

    /**
     * 底部条的Y坐标
     * 
     * @return
     */
    public float getContentY() {
        return mBottomLineY;
    }

    /**
     * 获取剪裁内容的宽度
     * 
     * @return
     */
    public int getContentWidth() {
        return (mBottomLineY - mTopLineY);
    }

    public int getImWidth() {
        return imWidth;
    }

    public int getImHeight() {
        return imHeight;
    }

    /**
     * 设置是否显示剪裁框
     * 
     * @param f
     */
    public void setShowClipFrame(boolean f) {
        showClipFrame = f;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (showClipFrame) {
            drawShadowRegion(canvas);
            drawClipFrame(canvas);
        }
    }

    /**
     * 绘制剪裁框外的阴影
     * 
     * @param canvas
     */
    private void drawShadowRegion(Canvas canvas) {
        mRectTopShadow.set(0, 0, imWidth, mTopLineY);
        mRectBottomShadow.set(0, mBottomLineY, imWidth, imHeight);
        canvas.drawRect(mRectTopShadow, mShadowPaint);
        canvas.drawRect(mRectBottomShadow, mShadowPaint);
    }

    /**
     * 绘制剪裁框
     * 
     * @param canvas
     */
    private void drawClipFrame(Canvas canvas) {
        canvas.drawLine(0, mTopLineY, mLineWidth, mTopLineY, mClipFramePaint);
        canvas.drawLine(0, mBottomLineY, mLineWidth, mBottomLineY, mClipFramePaint);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            setLastPosition(event);

            touchPos = detectTouchPosition(event.getX(), event.getY());
            getParent().requestDisallowInterceptTouchEvent(mInterceptTouchEvent);

            break;
        case MotionEvent.ACTION_MOVE:
            onActionMove(event.getX(), event.getY());
            setLastPosition(event);
            break;
        case MotionEvent.ACTION_UP:
            break;
        }
        return true;
    }

    private void onActionMove(float x, float y) {
        // TODO Auto-generated method stub
        float deltaX = x - mLastPoint.x;
        float deltaY = y - mLastPoint.y;

        switch (touchPos) {
        case POS_CENTER:

            break;
        case POS_TOP:
            resetTop(deltaY);
            break;
        case POS_BOTTOM:
            resetBottom(deltaY);
            break;
        default:

            break;
        }

        invalidate();

    }

    private void resetBottom(float deltaY) {
        // TODO Auto-generated method stub
        mBottomLineY += deltaY;
        fixBottomLine();
    }

    private void fixBottomLine() {
        // TODO Auto-generated method stub
        if (mBottomLineY > imHeight) {
            mBottomLineY = imHeight;
        }

        if ((mBottomLineY - mTopLineY) < 2 * UP_DOWN_LENGTH) {
            mBottomLineY = (int) (mTopLineY + 2 * UP_DOWN_LENGTH);
        }
    }

    private void resetTop(float deltaY) {
        // TODO Auto-generated method stub
        mTopLineY += deltaY;
        fixTopLine();
    }

    private void fixTopLine() {
        // TODO Auto-generated method stub
        if (mTopLineY < 0) {
            mTopLineY = 0;
        }

        if ((mBottomLineY - mTopLineY) < 2 * UP_DOWN_LENGTH) {
            mTopLineY = (int) (mBottomLineY - 2 * UP_DOWN_LENGTH);
        }

    }

    private void setLastPosition(MotionEvent event) {
        mLastPoint.x = event.getX();
        mLastPoint.y = event.getY();
    }

    /**
     * 判断触摸位置
     * 
     * @param x
     * @param y
     * @return
     */
    private int detectTouchPosition(float x, float y) {
        if (x > TOUCH_FIELD && x < mLineWidth - TOUCH_FIELD && y > mTopLineY + TOUCH_FIELD
                && y < mBottomLineY - TOUCH_FIELD) {

            mInterceptTouchEvent = false;  //不处理该区域的事件;scrollview处理

            return POS_CENTER;
        }

        if (x > TOUCH_FIELD && x < mLineWidth - TOUCH_FIELD && y > mTopLineY - TOUCH_FIELD
                && y < mTopLineY + TOUCH_FIELD) {

            mInterceptTouchEvent = true;  //处理该区域的事件

            return POS_TOP;
        }
        if (x > TOUCH_FIELD && x < mLineWidth - TOUCH_FIELD && y > mBottomLineY - TOUCH_FIELD
                && y < mBottomLineY + TOUCH_FIELD) {

            mInterceptTouchEvent = true;  //处理该区域的事件

            return POS_BOTTOM;
        }
        return -1;

    }

}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值