Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 自定義控件 編輯和選取圓形頭像

自定義控件 編輯和選取圓形頭像

編輯:關於Android編程

android大家都有很多需要用戶上傳頭像的需求,有的是選方形,有的是圓角矩形,有的是圓形。 首先我們要做一個處理圖片的自定義控件,把傳入的圖片,經過用戶選擇區域,處理成一定的形狀。

有的app是通過在圖片上畫一個矩形區域表示選中的內容,有的則是通過雙指放大縮小,拖動圖片來選取圖片。圓形頭像,還是改變圖片比較好

這裡寫圖片描述

圓形區域可調節大小。

這個自定義View的圖像部分分為三個,背景圖片,半透明蒙層,和亮色區域……還是直接貼代碼得了

package com.example.jjj.widget;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

public class RoundEditImageView extends View {
    private Bitmap bitmap;
    RectF clipBounds, dst, src;
    Paint clearPaint;

    // 控件寬高
    private int w, h;
    // 選區半徑
    private float radius = 150f;

    // 圓形選區的邊界
    private RectF circleBounds;

    // 最大放大倍數
    private float max_scale = 2.0f;

    // 雙指的距離
    private float distance;
    private float x0, y0;
    private boolean doublePoint;

    public RoundEditImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    public RoundEditImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public RoundEditImageView(Context context) {
        super(context);
        init();
    }

    private void init() {
        clearPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        clearPaint.setColor(Color.GRAY);
        clearPaint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (bitmap != null) {
            canvas.drawBitmap(bitmap, null, dst, null);//每次invalidate通過改變dst達到縮放平移的目的
        }
        // 保存圖層,以免清除時清除了bitmap
        int count = canvas.saveLayer(clipBounds, null, Canvas.ALL_SAVE_FLAG);
        canvas.drawColor(0x80000000);
        canvas.drawCircle(w / 2, h / 2, radius, clearPaint);// 清除半透明黑色,留下一個透明圓
        canvas.restoreToCount(count);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        this.w = w;
        this.h = h;
        // 記錄view所占的矩形
        clipBounds = new RectF(0, 0, w, h);
        float l, r, t, b;
        if (bitmap != null) {
            // 判斷長寬比,當長寬比太長會太寬是,以fitCenter的方式初始化圖片
            if (w / (float) h > bitmap.getWidth() / (float) bitmap.getHeight()) {
                // 圖片太高
                float w_ = h * bitmap.getWidth() / (float) bitmap.getHeight();
                l = w / 2f - w_ / 2f;
                r = w / 2f + w_ / 2f;
                t = 0;
                b = h;
            } else {
                // 圖片太長,或跟view一樣長
                float h_ = w * bitmap.getHeight() / (float) bitmap.getWidth();
                l = 0;
                r = w;
                t = h / 2f - h_ / 2f;
                b = h / 2f + h_ / 2f;
            }
            dst = new RectF(l, t, r, b);// 這個矩形用來變換
            src = new RectF(l, t, r, b);// 這個矩形僅為保存第一次的狀態

            max_scale = Math.max(max_scale, bitmap.getWidth() / src.width());
        }
        circleBounds = new RectF(w / 2 - radius, h / 2 - radius, w / 2 + radius, h / 2 + radius);
    }

    public void setImageBitmap(Bitmap bitmap) {
        this.bitmap = bitmap;
        invalidate();
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent e) {
        if (e.getPointerCount() > 2) {// 不接受多於兩指的事件
            return false;
        } else if (e.getPointerCount() == 2) {
            doublePoint = true;// 標志位,記錄兩指事件處理後,抬起一只手也不處理拖動
            handleDoubleMove(e);
        } else {
            // 處理單指的拖動
            switch (e.getAction()) {
            case MotionEvent.ACTION_DOWN:
                x0 = e.getX();
                y0 = e.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                if (doublePoint) {
                    break;
                }
                float x = e.getX();
                float y = e.getY();
                float w = dst.width();
                float h = dst.height();

                // 不允許拖過圓形區域,不能使圓形區域內空白
                dst.left += x - x0;
                if (dst.left > circleBounds.left) {
                    dst.left = circleBounds.left;
                } else if (dst.left < circleBounds.right - w) {
                    dst.left = circleBounds.right - w;
                }
                dst.right = dst.left + w;

                // 不允許拖過圓形區域,不能使圓形區域內空白
                dst.top += y - y0;
                if (dst.top > circleBounds.top) {
                    dst.top = circleBounds.top;
                } else if (dst.top < circleBounds.bottom - h) {
                    dst.top = circleBounds.bottom - h;
                }
                dst.bottom = dst.top + h;

                x0 = x;
                y0 = y;
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                doublePoint = false;// 恢復標志位
                break;
            }
        }

        return true;
    }

    // 處理雙指事件
    private void handleDoubleMove(MotionEvent e) {
        switch (e.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_POINTER_DOWN:
            distance = sqrt(e);
            Log.d("px", "down:distance=" + distance);
            break;
        case MotionEvent.ACTION_MOVE:
            scale(e);
            break;
        case MotionEvent.ACTION_UP:
            break;
        default:
            break;
        }
    }

    private void scale(MotionEvent e) {
        float dis = sqrt(e);
        // 以雙指中心作為圖片縮放的支點
        float pX = e.getX(0) / 2f + e.getX(1) / 2f;
        float pY = e.getY(0) / 2f + e.getY(1) / 2f;
        float scale = dis / distance;
        Log.d("px", "move:distance=" + dis + ",scale to" + scale);
        float w = dst.width();
        float h = dst.height();

        if (w * scale < radius * 2 || h * scale < radius * 2 || w * scale > src.width() * max_scale) {
            // 無法縮小到比選區還小,或到達最大倍數
            return;
        }
        // 把dst區域放大scale倍
        dst.left = (dst.left - pX) * scale + pX;
        dst.right = (dst.right - pX) * scale + pX;
        dst.top = (dst.top - pY) * scale + pY;
        dst.bottom = (dst.bottom - pY) * scale + pY;

        // 縮放同樣不允許使圓形區域空白
        if (dst.left > circleBounds.left) {
            dst.left = circleBounds.left;
            dst.right = dst.left + w * scale;
        } else if (dst.right < circleBounds.right) {
            dst.right = circleBounds.right;
            dst.left = dst.right - w * scale;
        }

        if (dst.top > circleBounds.top) {
            dst.top = circleBounds.top;
            dst.bottom = dst.top + h * scale;
        } else if (dst.bottom < circleBounds.bottom) {
            dst.bottom = circleBounds.bottom;
            dst.top = dst.bottom - h * scale;
        }
        invalidate();

        distance = dis;
    }

    private float sqrt(MotionEvent e) {
        return (float) Math.sqrt((e.getX(0) - e.getX(1)) * (e.getX(0) - e.getX(1)) + (e.getY(0) - e.getY(1)) * (e.getY(0) - e.getY(1)));
    }

    // 生成目前選區指定大小的圓形bitmap
    public Bitmap extractBitmap(int width) {
        Bitmap outBitmap = Bitmap.createBitmap(width, width, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(outBitmap);
        Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
        p.setColor(Color.GRAY);
        canvas.drawCircle(width / 2, width / 2, width / 2, p);
        float scale = dst.width() / bitmap.getWidth();
        int w = (int) (circleBounds.width() / scale);
        int l = (int) ((circleBounds.left - dst.left) / scale);
        int r = l + w;
        int t = (int) ((circleBounds.top - dst.top) / scale);
        int b = t + w;
        Rect resRect = new Rect(l, t, r, b);
        Paint paint = new Paint();
        paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
        canvas.drawBitmap(bitmap, resRect, canvas.getClipBounds(), paint);
        return outBitmap;
    }
}

Activity中用法

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_select_header);
        RoundEditImageView imageView = (RoundEditImageView) findViewById(R.id.roundEditImageView1);
        bitmap = BitmapFactory.decodeFile(imagePath);
        imageView.setImageBitmap(bitmap);
    }

    @Override
    public void onClick(View v) {
            //生成一個300*300的當前亮圓形中的圖片
            Bitmap result = imageView.extractBitmap(300);
            //壓縮成png
            FileOutputStream out = new FileOutputStream(new File(filePath));
            result.compress(Bitmap.CompressFormat.PNG, 100, out);
            //上傳與顯示
            ...
    }

需求是模仿QQ的,本人不太會講解,做著玩玩。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved