先看看圖片的效果,左邊是原圖,右邊是旋轉之后的圖;
之所以把這個寫出來是因為在一個項目中需要用到這樣的效果,我試過用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);