Android 自定義View消除鋸齒實現圖片旋轉,添加邊框及文字說明


先看看圖片的效果,左邊是原圖,右邊是旋轉之后的圖;

 

之所以把這個寫出來是因為在一個項目中需要用到這樣的效果,我試過用FrameLayout布局如上的畫面,然后旋轉FrameLayout,隨之而來也就存在了一些問題——鋸齒!

在網上搜索之后,有兩種方法,一是利用Paint,二是利用Canvas;
(1)、paint.setAntiAlias(true);

   paint.setFlags(Paint.ANTI_ALIAS_FLAG);

(2)、DrawFilter pfdf = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG);

   canvas.setDrawFilter(pfdf);

而如果利用paint,或者canvas,需要從哪獲取paint/canvas,這也是一個問題;

在實現的過程中,嘗試過自定義FrameLayout下面的單個View{ImageView,TextView},但都以失敗告終,失敗的主要問題在於右圖下邊的文字描述無法和相片邊框相對齊,而且用Matrix旋轉背景之后背景大小改變,位置也不在最下邊,所以就采用了單獨實現一個View的方法,主要原因還是因為自身對Canvas繪圖及Paint畫筆不是很熟悉,所以導致的效率不高;

public class RotateTextImageView extends View {
    PaintFlagsDrawFilter pfdf;
    Paint paint;
    Matrix matrix;
    Bitmap bitmap;
    int index = -1;
    private int oriHeight;
    private int oriWidth;
    private int newHeight;
    private int newWidth;
    private int angle = 5;
    protected Path path = new Path();
    private float[] f = new float[8];
    private int shawHeight = 20;
    private int borderSize = 8;
    Bitmap oriBitmap;
    private String text = "";

    public RotateTextImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initCanvasInfo();
    }

    public RotateTextImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initCanvasInfo();
    }

    public RotateTextImageView(Context context) {
        super(context);
        initCanvasInfo();
    }

    /**
     * 初始化Paint
     */
    protected void initCanvasInfo() {
        pfdf = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG
                | Paint.FILTER_BITMAP_FLAG);
        paint = new Paint();
        paint.setAntiAlias(true);
        matrix = new Matrix();
        matrix.setRotate(5);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        paint.reset();
        // 消除鋸齒
        paint.setAntiAlias(true);
        paint.setFlags(Paint.ANTI_ALIAS_FLAG);
        canvas.setDrawFilter(pfdf);
        canvas.drawBitmap(bitmap, 0, 0, paint);
        newHeight = bitmap.getHeight();
        newWidth = bitmap.getWidth();
        calculatePoints();
        // 添加陰影
        path.reset();
        path.moveTo(f[0], f[1]);
        path.lineTo(f[2], f[3]);
        path.lineTo(f[4], f[5]);
        path.lineTo(f[6], f[7]);
        path.close();
        paint.setStyle(Paint.Style.FILL_AND_STROKE);
        paint.setColor(Color.parseColor("#96ffffff"));
        canvas.drawPath(path, paint);
        // 添加字符
        if (text != null && !text.equals("")) {
            path.reset();
            paint.setTextSize(18);
            float width = paint.measureText(text);
            path.moveTo((f[0] + f[2]) / 2, (f[1] + f[3]) / 2);
            path.lineTo((f[4] + f[6]) / 2, (f[5] + f[7]) / 2);
            paint.setColor(Color.parseColor("#2b2b2b"));
            canvas.drawTextOnPath(text, path, (oriWidth - width) / 2, 3, paint);
        }
        layout(0, 0, newWidth, newHeight);
    }

    /**
     * 計算坐標值
     */
    private void calculatePoints() {
        double a = angle * Math.PI / 180;
        BigDecimal height = new BigDecimal(oriHeight);
        BigDecimal width = new BigDecimal(oriWidth);
        BigDecimal cos = new BigDecimal(Math.cos(a));
        BigDecimal tan = new BigDecimal(Math.tan(a));
        f[0] = 0;
        f[1] = height.multiply(cos).floatValue();
        f[2] = tan.multiply(new BigDecimal(shawHeight)).floatValue();
        f[3] = (new BigDecimal(f[1])).subtract(new BigDecimal(shawHeight))
                .floatValue();
        f[4] = width.multiply(cos).add(new BigDecimal(f[2])).floatValue();
        f[5] = new BigDecimal(newHeight - shawHeight).floatValue();
        f[6] = width.multiply(cos).floatValue();
        f[7] = new BigDecimal(newHeight).floatValue();
    }

    /**
     * 設置圖片
     * 
     * @param bmp
     */
    public void setBitmap(Bitmap bmp) {
        oriBitmap = bmp;
        matrix.reset();
        matrix.setRotate(angle);
        Bitmap bitmapF = addFrame(bmp);
        oriHeight = bitmapF.getHeight();
        oriWidth = bitmapF.getWidth();
        bitmap = Bitmap.createBitmap(bitmapF, 0, 0, bitmapF.getWidth(),
                bitmapF.getHeight(), matrix, true);
        postInvalidate();
    }

    /**
     * 旋轉角度
     * 
     * @param angle
     */
    public void setAngle(int angle) {
        this.angle = angle;
        setBitmap(oriBitmap);
    }

    /**
     * 設置底部陰影高度
     * 
     * @param shawHeight
     */
    public void setShawHeight(int shawHeight) {
        this.shawHeight = shawHeight;
        postInvalidate();
    }

    /**
     * 生成添加了白色邊緣的圖
     * 
     * @param bmp
     * @return
     */
    protected Bitmap addFrame(Bitmap bmp) {
        Bitmap bmpWithBorder = Bitmap.createBitmap(bmp.getWidth() + borderSize
                * 2, bmp.getHeight() + borderSize * 2, bmp.getConfig());
        Canvas canvas = new Canvas(bmpWithBorder);
        canvas.drawColor(Color.WHITE);
        canvas.drawBitmap(bmp, borderSize, borderSize, null);
        return bmpWithBorder;
    }

    /**
     * 設置字符串
     * 
     * @param text
     */
    public void setText(String text) {
        this.text = text;
        postInvalidate();
    }

    /**
     * 獲取字體高度
     */
    protected int getFontHeight() {
        FontMetrics fm = paint.getFontMetrics();
        return (int) Math.ceil(fm.descent - fm.top) + 2;
    }
}

 

  代碼解釋:其實沒有什么難的東西,只是一些數學運算,代碼中每一個方法都有對應的功能注釋。浮點型數組代表陰影層四個坐標點的八個坐標值,分別是左下、左上、右上、右下四個點,陰影層坐標計算也比較簡單,但有點繁瑣,就是把原圖旋轉之后再根據幾何知識進行求解坐標!

  每次重新設置角度,設置圖片,都需要重新繪制圖形-->postInvalidate();

View的使用

一、xml配置文件

    <com.livingstone.RotateTextImageView
        android:id="@+id/myview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:minHeight="250dip"
        android:minWidth="200dip"
        android:paddingLeft="5dip" />

二、設置文字說明及角度、圖片

        RotateTextImageView myView = (RotateTextImageView) findViewById(R.id.myview);
        myView.setShawHeight(50);
        Bitmap bmp = BitmapFactory.decodeResource(getResources(),R.drawable.test1);
        myView.setBitmap(bmp);
        myView.setAngle(10);
        myView.setText("這是一個測試");

 

Ex:獲取字體寬度的兩種方法
<1>.通過paint獲取字體的Rect

Rect rect=newRect();
paint.getTextBounds("你好",0,1, rect);
Log.v("a:","height:"+rect.height()+"width:"+rect.width());

<2>.通過paint直接獲取字體寬度

intwidth=(int)paint.measureText("你好",0,1);
Log.v("width:","width:"+width);

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM