自定義視圖view使用Canvas實(shí)現(xiàn)手寫板和涂鴉功能
預(yù)覽圖
一、xml布局
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:id="@+id/main_linlayout" android:layout_width="match_parent" android:layout_height="300dp" android:orientation="vertical"> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <Button android:id="@+id/bt" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:text="確定"/> <Button android:id="@+id/bt_clear" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:text="清空"/> </LinearLayout> <ImageView android:id="@+id/img" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:layout_gravity="center"/> </LinearLayout>
布局預(yù)覽圖
二、MainActivity代碼
package tester.ermu.com.handdrawdemo; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BlurMaskFilter; import android.graphics.EmbossMaskFilter; import android.os.Bundle; import android.util.DisplayMetrics; import android.view.View; import android.widget.Button; import android.widget.ImageView; import android.widget.LinearLayout; public class MainActivity extends Activity implements View.OnClickListener{ EmbossMaskFilter emboss; BlurMaskFilter blur; DrawView drawView; private LinearLayout main_linlayout; private Button bt,bt_clear; private ImageView img; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); //初始化組件 getWH();//獲取我們xml布局中view的寬高 } //獲取我們xml布局中view的寬高 private void getWH() { // 獲取創(chuàng)建的寬度和高度 DisplayMetrics displayMetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getRealMetrics(displayMetrics); // 創(chuàng)建一個(gè)DrawView,該DrawView的寬度、高度與該Activity保持相同 main_linlayout = (LinearLayout)findViewById(R.id.main_linlayout); drawView = new DrawView(this, displayMetrics.widthPixels, displayMetrics.heightPixels); main_linlayout.addView(drawView); drawView.requestFocus(); } private void init() { bt = (Button)findViewById(R.id.bt); bt.setOnClickListener(this); bt_clear = (Button)findViewById(R.id.bt_clear); bt_clear.setOnClickListener(this); img = (ImageView) findViewById(R.id.img); } @Override public void onClick(View v) { switch (v.getId()){ case R.id.bt: Bitmap bit = drawView.getPaintBitmap(); img .setImageBitmap(bit); break; case R.id.bt_clear: drawView.clear(); break; } } }
三、我們自定義view的類
package tester.ermu.com.handdrawdemo; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; public class DrawView extends View { // 定義記錄前一個(gè)拖動(dòng)事件發(fā)生點(diǎn)的坐標(biāo) float preX; float preY; private Path path; public Paint paint = null; // 定義一個(gè)內(nèi)存中的圖片,該圖片將作為緩沖區(qū) Bitmap cacheBitmap = null; // 定義cacheBitmap上的Canvas對(duì)象 Canvas cacheCanvas = null; public DrawView(Context context) { super(context); } public DrawView(Context context, AttributeSet attrs) { super(context, attrs); } public DrawView(Context context, int width , int height) { super(context); // 創(chuàng)建一個(gè)與該View相同大小的緩存區(qū) cacheBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); cacheCanvas = new Canvas(); path = new Path(); // 設(shè)置cacheCanvas將會(huì)繪制到內(nèi)存中的cacheBitmap上 cacheCanvas.setBitmap(cacheBitmap); // 設(shè)置畫筆的顏色 paint = new Paint(Paint.DITHER_FLAG); paint.setColor(Color.RED); // 設(shè)置畫筆風(fēng)格 paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(3); // 反鋸齒 paint.setAntiAlias(true); paint.setDither(true); } @Override public boolean onTouchEvent(MotionEvent event) { // 獲取拖動(dòng)事件的發(fā)生位置 float x = event.getX(); float y = event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // 從前一個(gè)點(diǎn)繪制到當(dāng)前點(diǎn)之后,把當(dāng)前點(diǎn)定義成下次繪制的前一個(gè)點(diǎn) path.moveTo(x, y); preX = x; preY = y; break; case MotionEvent.ACTION_MOVE: // 從前一個(gè)點(diǎn)繪制到當(dāng)前點(diǎn)之后,把當(dāng)前點(diǎn)定義成下次繪制的前一個(gè)點(diǎn) path.quadTo(preX, preY, x, y); preX = x; preY = y; break; case MotionEvent.ACTION_UP: cacheCanvas.drawPath(path, paint); // ① path.reset(); break; } invalidate(); // 返回true表明處理方法已經(jīng)處理該事件 return true; } @Override public void onDraw(Canvas canvas) { Paint bmpPaint = new Paint(); // 將cacheBitmap繪制到該View組件上 canvas.drawBitmap(cacheBitmap, 0, 0, bmpPaint); // ② // 沿著path繪制 canvas.drawPath(path, paint); } //獲取我們繪制成功后的圖片 public Bitmap getPaintBitmap() { return resizeImage(cacheBitmap, 620, 780); } // 縮放 public static Bitmap resizeImage(Bitmap bitmap, int width, int height) { //獲取圖片的寬高 int originWidth = bitmap.getWidth(); int originHeight = bitmap.getHeight(); //這里縮放我們的尺寸,縮放多少自己去定義 float scaleWidth = ((float) width) / originWidth; float scaleHeight = ((float) height) / originHeight; //進(jìn)行縮放 Matrix matrix = new Matrix(); matrix.postScale(scaleWidth, scaleHeight); Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, originWidth, originHeight, matrix, true); return resizedBitmap; } //清除畫板 public void clear() { if (cacheBitmap != null) { path.reset(); cacheCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); invalidate(); } } }
到此這篇關(guān)于自定義視圖view使用Canvas實(shí)現(xiàn)手寫板和涂鴉功能的文章就介紹到這了,更多相關(guān)自定義視圖Canvas手寫板涂鴉內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android RecyclerView詳解之實(shí)現(xiàn) ListView GridView瀑布流效果
RecyclerView 是Android L版本中新添加的一個(gè)用來取代ListView的SDK,它的靈活性與可替代性比listview更好2016-07-07Android編程實(shí)現(xiàn)TextView垂直自動(dòng)滾動(dòng)功能【附demo源碼下載】
這篇文章主要介紹了Android編程實(shí)現(xiàn)TextView垂直自動(dòng)滾動(dòng)功能,詳細(xì)分析了Android TextView垂直自動(dòng)滾動(dòng)功能的實(shí)現(xiàn)步驟與布局、功能相關(guān)技巧,并附帶了demo源碼供讀者下載,需要的朋友可以參考下2017-02-02Compose?動(dòng)畫藝術(shù)之屬性動(dòng)畫探索
這篇文章主要介紹了Compose動(dòng)畫藝術(shù)之屬性動(dòng)畫探索,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-09-09Android開發(fā)之BroadcastReceiver用法實(shí)例分析
這篇文章主要介紹了Android開發(fā)之BroadcastReceiver用法,實(shí)例分析了Android中廣播的相關(guān)使用技巧,需要的朋友可以參考下2015-05-05Android Spinner與適配器模式詳解及實(shí)例代碼
這篇文章主要介紹了Android Spinner與適配器模式詳解相關(guān)資料,并附代碼實(shí)例,需要的朋友可以參考下2016-10-10Android在線更新SDK的方法(使用國內(nèi)鏡像)
這篇文章主要介紹了Android在線更新SDK的方法,分別介紹了修改hosts文件使用谷歌官方鏡像更新及使用國內(nèi)鏡像更新SDK的方法,非常簡單實(shí)用,需要的朋友可以參考下2015-12-12Android自定義控件實(shí)現(xiàn)通用驗(yàn)證碼輸入框(二)
這篇文章主要為大家詳細(xì)介紹了Android自定義控件實(shí)現(xiàn)通用驗(yàn)證碼輸入框的第二篇,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-01-01Android仿百度谷歌搜索自動(dòng)提示框AutoCompleteTextView簡單應(yīng)用示例
這篇文章主要介紹了Android仿百度谷歌搜索自動(dòng)提示框AutoCompleteTextView簡單應(yīng)用,結(jié)合實(shí)例形式分析了AutoCompleteTextView Widget使用步驟與相關(guān)操作技巧,需要的朋友可以參考下2016-10-10Android開發(fā)之拖動(dòng)條/滑動(dòng)條控件、星級(jí)評(píng)分控件功能的實(shí)例代碼
這篇文章主要介紹了Android開發(fā)之拖動(dòng)條/滑動(dòng)條控件、星級(jí)評(píng)分控件功能的實(shí)例代碼,需要的朋友可以參考下2019-05-05