[Android] 触屏setOnTouchListener实现图片缩放、移动、绘制和添加水印
? ? 前一篇文章講述了Android實現圖片Matrix矩陣類縮放、旋轉、對比度、亮度、飽和度處理,但是真正的圖片軟件都是使用觸屏實現圖片縮放、移動、添加水印等功能,所以該篇文章主要通過setOnTouchListener監聽實現該功能.希望文章對大家有所幫助.
一.圖片縮放實現
??? 首先先簡單介紹Android如何實現觸屏縮放圖片和移動圖片,新建TouchImageViw工程.設計XML中activity_main.xml布局:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/container"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.example.touchimagetest.MainActivity"tools:ignore="MergeRootFrame" ><!-- 頂部路徑 --><RelativeLayout android:id="@+id/MyLayout_top"android:orientation="horizontal" android:layout_width="fill_parent"android:layout_height="40dp" android:layout_alignParentTop="true"android:gravity="center"><TextViewandroid:id="@+id/textView1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="15sp"android:text="顯示圖片路徑" /></RelativeLayout><!-- 底部按鈕 --><RelativeLayoutandroid:id="@+id/MyLayout_bottom"android:orientation="horizontal" android:layout_width="fill_parent"android:layout_height="50dp"android:layout_alignParentBottom="true"android:gravity="center"><LinearLayout android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="horizontal"android:layout_alignParentBottom="true" ><Buttonandroid:id="@+id/button1"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_weight="1"android:text="打開" /></LinearLayout></RelativeLayout><!-- 顯示圖片 --><RelativeLayoutandroid:id="@+id/Content_Layout" android:orientation="horizontal"android:layout_width="fill_parent" android:layout_height="fill_parent"android:layout_above="@id/MyLayout_bottom" android:layout_below="@id/MyLayout_top"android:background="#EFDFDF"android:gravity="center"><ImageViewandroid:id="@+id/imageView1"android:layout_width="fill_parent"android:layout_height="fill_parent"android:layout_gravity="center_horizontal"android:scaleType="matrix" /></RelativeLayout> </RelativeLayout>???需要注意的是按鈕中設置其android:layout_weight="1"屬性,因為后面會增加至4個按鈕,都設置為1表示每個寬度占水平布局的1/4比例.(圖見后)該布局是我非常喜歡的布局,通過相對布局RelativeLayout設置相應的上中下對應圖片路徑、圖片、按鈕.
??? 然后,在Mainctivity.java中public class MainActivity extends Activity函數添加代碼如下,添加點擊按鈕監聽事件:
??? 添加intent意圖startActivityForResult對應的onActivityResult函數實現打開圖片:
//打開圖片 protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(resultCode==RESULT_OK && requestCode==IMAGE_CODE) { Uri imageFileUri = data.getData();DisplayMetrics dm = new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(dm); int width = dm.widthPixels; //手機屏幕水平分辨率 int height = dm.heightPixels; //手機屏幕垂直分辨率try { //載入圖片尺寸大小沒載入圖片本身 trueBitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options(); bmpFactoryOptions.inJustDecodeBounds = true; bmp = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageFileUri), null, bmpFactoryOptions);//outHeight圖像高 outWidth圖像寬 int heightRatio = (int)Math.ceil(bmpFactoryOptions.outHeight/(float)height);int widthRatio = (int)Math.ceil(bmpFactoryOptions.outWidth/(float)width); //inSampleSize表示圖片占原圖比例 =1表示原圖if(heightRatio>1&&widthRatio>1) { if(heightRatio>widthRatio) { bmpFactoryOptions.inSampleSize = heightRatio; } else { bmpFactoryOptions.inSampleSize = widthRatio; } } //圖像真正解碼 falsebmpFactoryOptions.inJustDecodeBounds = false; bmp = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageFileUri), null, bmpFactoryOptions); imageShow.setImageBitmap(bmp);//顯示文件路徑String[] filePathColumn= {MediaStore.Images.Media.DATA};Cursor cursor = getContentResolver().query(imageFileUri, filePathColumn, null, null, null);cursor.moveToFirst(); //將光標移至開頭int columnIndex = cursor.getColumnIndex(filePathColumn[0]); //獲得用戶選擇圖片的索引path = cursor.getString(columnIndex);cursor.close();pathText.setText("path="+path);} catch(FileNotFoundException e) { e.printStackTrace(); } } //end if }??? 此時可以實現打開圖片,顯示的效果如下圖所示:
??????????????????????? ???? ???
??? 然后在onCreate()函數中openImageBn.setOnClickListener打開圖片后添加如下代碼,通過setOnTouchListener監聽實現圖片縮放移動功能.PS:這部分網上資料較多,也比較相似.作者參照《Android多媒體開發高級編程》.
??? 運行結果如下圖所示:
??????????????????????????????????????????????? ???????
??? 下面講講作者遇到的幾個問題及需要注意的幾個地方:
??? 1.如何使用RelativeLayout進行布局,上面布局非常優秀,是我參照了鄭海波學長一個代碼例子的布局,個人覺得比較喜歡.
??? 2.在圖像縮放的時候需要設置ImageView的屬性android:scaleType="matrix",這里涉及到前一篇講述的Matrix矩陣類的知識,但是使用該類后圖像如何居中呢?
??? 設置其父布局為android:gravity="center"是不行的,作者查閱很多資料,有兩種方法:一種是設置ImageView的scaleType屬性為center,在縮放時代碼設置為matrix,感覺不太好;另一種是通過下面的代碼可以實現居中顯示,但是在縮放時需要注意設置其圖片左上角顯示位置,否則會出現跳動到(0,0)現象.
??? 希望高手能提供更好的方法,因為跳動現象,我自己也會繼續去學習.
??? 3.圖片ImageView設置了setOnTouchListener監聽,能實現縮放圖片,那么如果還點擊一個按鈕"文字"后實現的是拖放文字框,點擊"繪制"是在圖像上繪制圖片,怎么實現呢?點擊一個按鈕怎樣實現一個觸摸監聽呢?
??? 由于這個很難查閱資料,像美圖秀秀哪樣的功能,所以我自己只能想到通過修改一個變量賦值判斷觸屏監聽執行那個方法,自定義函數private int flagOnTouch=0,當其1-顯示圖片,2-添加文字,3-縮放圖片,4-畫圖.在點擊按鈕事件中對其進行賦值,在setOnTouchListener中判斷.(希望提供更好的方法)
??? 4.縮放圖片時最好設置最小的邊界,當縮小當一定范圍尺寸固定不變,放大最好也有越界等處理.
二.原理介紹
???下面講述觸摸事件的一些基礎知識,方便鞏固上面的工程.
??? Android許多UI元素都繼承View類,該類支持觸摸,該方法是setOnTouchListener,其接受一個實現OnTouchListener接口對象作為參數.每當觸摸ImageView調用活動中的onTouch方法,再通過查看傳遞到onTouch方法中的MotionEvent對象,可以確定發生哪種類型的觸摸,可調用getAction方法:
??? MotionEvent.ACTION_DOWN:表明視圖已經接收一次觸摸,按下時觸發
??? MotionEvent.ACTION_UP:表明視圖停止接受一次觸摸,被放開時觸發
??? MotionEvent.ACTION_POINTER_DOWN:當屏幕上已經有一點被按住,再按下其他點時觸發
??? MotionEvent.ACTION_POINTER_UP:當屏幕上有多個點被按住,松開其中一個點時觸發(即非最后一個點被放開時)
??? MotionEvent.ACTION_MOVE:表明在發生一次觸摸之后,在ACTION_UP之前發生了某種移動
??? MotionEvent.ACTION_CANCEL:表明觸摸已經被取消,因此該忽略它
????同時可以調用MotionEvent對象上的getX和getY來確定觸摸事件發生的位置.
??? 如上面的代碼,當ACTION_DOWN手指第一次按下時設置mode=DRAG,當ACTION_POINTER_DOWN再按下一個手指時判斷距離大于10設置mode=ZOOM,當ACTION_MOVE移動時判斷兩指為縮放,一指為移動即可實現.在通過新坐標和老坐標設置圖像變換.參考《Android多媒體開發高級編程》
??? (PS:作者才接觸Android一個星期,說起來很簡單啊!但做起來還是非常難的~)
三.工程實現詳解
??? 上面簡單的縮放功能與基本原理(干貨)都講述了,讀者可以自己去實現功能,下面就如何實現觸摸setOnTouchListener圖片縮放、移動、繪制和添加水印.都是基于上面代碼修改實現的.需要注意的是在圖片修改時需要創建一個新的Bitmap alteredBitmap(bmp圖片)、Canvas canvas(畫布)、Paint paint(畫刷)實現.
??? 1.圖片縮放和圖片繪制
??? 首先,為XML布局中修改為4個新的按鈕,即"打開"、"文字"、"縮放"、"畫圖".
<Buttonandroid:id="@+id/button1"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_weight="1"android:text="打開" /> <Buttonandroid:id="@+id/button2"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_weight="1"android:text="文字" /> <Buttonandroid:id="@+id/button3"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_weight="1"android:text="縮放" /> <Buttonandroid:id="@+id/button4"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_weight="1"android:text="畫圖" />??? 在上面的自定義變量中添加新的變量,如下:
//新增按鈕 private Button wordAddBn; //添加文字 private Button changeImageBn; //縮放圖片 private Button drawImageBn; //繪制圖片 //圖片處理時顯示備份 private Bitmap alteredBitmap; //圖片 private Canvas canvas; //畫布 private Paint paint; //畫刷 private RelativeLayout layout; //標識變量 1-顯示圖片 2-添加文字 3-縮放圖片 4-畫圖 private int flagOnTouch = 0;??? 然后修改打開圖片函數,為其創建一個alteredBitmap圖像,后面的添加文字和繪制畫圖都是在此基礎上修改:
//打開圖片 protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if(resultCode==RESULT_OK && requestCode==IMAGE_CODE) { Uri imageFileUri = data.getData();DisplayMetrics dm = new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(dm); int width = dm.widthPixels; //手機屏幕水平分辨率 int height = dm.heightPixels; //手機屏幕垂直分辨率try {//標識變量=1 圖片顯示flagOnTouch = 1;? //載入圖片尺寸大小沒載入圖片本身 trueBitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options(); bmpFactoryOptions.inJustDecodeBounds = true; bmp = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageFileUri), null, bmpFactoryOptions); int heightRatio = (int)Math.ceil(bmpFactoryOptions.outHeight/(float)height); int widthRatio = (int)Math.ceil(bmpFactoryOptions.outWidth/(float)width); //inSampleSize表示圖片占原圖比例 =1表示原圖if(heightRatio>1&&widthRatio>1) { if(heightRatio>widthRatio) { bmpFactoryOptions.inSampleSize = heightRatio; } else { bmpFactoryOptions.inSampleSize = widthRatio; } } //圖像真正解碼 falsebmpFactoryOptions.inJustDecodeBounds = false; bmp = BitmapFactory.decodeStream(getContentResolver().openInputStream(imageFileUri), null, bmpFactoryOptions); //imageShow.setImageBitmap(bmp);//顯示文件路徑String[] filePathColumn= {MediaStore.Images.Media.DATA};Cursor cursor = getContentResolver().query(imageFileUri, filePathColumn, null, null, null);cursor.moveToFirst(); //將光標移至開頭int columnIndex = cursor.getColumnIndex(filePathColumn[0]); //獲得圖片索引值path = cursor.getString(columnIndex);cursor.close();pathText.setText("path="+path);//加載備份圖片alteredBitmap = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), bmp.getConfig());canvas = new Canvas(alteredBitmap); //畫布paint = new Paint(); //畫刷paint.setColor(Color.GREEN);paint.setStrokeWidth(5);paint.setTextSize(30);paint.setTypeface(Typeface.DEFAULT_BOLD); //無線粗體matrix = new Matrix();canvas.drawBitmap(bmp, matrix, paint);imageShow.setImageBitmap(alteredBitmap);} catch(FileNotFoundException e) { e.printStackTrace(); } } //end if }??? 然后在onCreate中添加圖片縮放和繪制圖片函數,代碼如下:
//縮放圖片 點擊按鈕"縮放" changeImageBn = (Button) findViewById(R.id.button3); changeImageBn.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {flagOnTouch = 3; //縮放} }); //繪制畫圖 點擊按鈕"繪制" drawImageBn = (Button) findViewById(R.id.button4); drawImageBn.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {flagOnTouch = 4; //繪圖//畫圖 圖片移動至(0,0) 否則繪圖線與手指存在誤差matrix = new Matrix();matrix.postTranslate(0, 0);imageShow.setImageMatrix(matrix);imageShow.setImageBitmap(alteredBitmap); canvas.drawBitmap(bmp, matrix, paint); }});??? 然后修改?imageShow.setOnTouchListener(new OnTouchListener())函數,實現點擊不同按鈕響應不同的觸摸事件:
//觸屏縮放圖片監聽 注:XML中修改android:scaleType="matrix" imageShow.setOnTouchListener(new OnTouchListener() { //設置兩個點 按下坐標(downx, downy)和抬起坐標(upx, upy)float downx = 0;float downy = 0;float upx = 0;float upy = 0;//觸摸事件@Overridepublic boolean onTouch(View v, MotionEvent event) {ImageView view = (ImageView) v;if(flagOnTouch == 1) { //顯示圖片return true;}else if(flagOnTouch == 3) { //圖片縮放switch (event.getAction() & MotionEvent.ACTION_MASK) {case MotionEvent.ACTION_DOWN: //手指按下savedMatrix.set(matrix);startPoint.set(event.getX(), event.getY());mode = DRAG;break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_POINTER_UP:mode = NONE;break;case MotionEvent.ACTION_POINTER_DOWN:oldDist = spacing(event); //如果兩點距離大于10 多點模式if (oldDist > 10f) {savedMatrix.set(matrix);midPoint(middlePoint, event);mode = ZOOM;}break;case MotionEvent.ACTION_MOVE:if (mode == DRAG) { //拖動matrix.set(savedMatrix);matrix.postTranslate(event.getX() - startPoint.x, event.getY() - startPoint.y);} else if (mode == ZOOM) { //縮放float newDist = spacing(event);if (newDist > 10f) {matrix.set(savedMatrix);float scale = newDist / oldDist;matrix.postScale(scale, scale, middlePoint.x, middlePoint.y);}}break;} //end switchview.setImageMatrix(matrix);return true;}else if(flagOnTouch == 2) { //圖片文字添加return true;}else if(flagOnTouch == 4) { //繪制圖像 switch (event.getAction()) {case MotionEvent.ACTION_DOWN:downx = event.getX();downy = event.getY();break;case MotionEvent.ACTION_MOVE:upx = event.getX();upy = event.getY();canvas.drawLine(downx, downy, upx, upy, paint);imageShow.invalidate();downx = upx;downy = upy;break;case MotionEvent.ACTION_UP:upx = event.getX();upy = event.getY();canvas.drawLine(downx, downy, upx, upy, paint);imageShow.invalidate();break;case MotionEvent.ACTION_CANCEL:break;default:break;}return true;}else {return false;}} //end onTouch//兩點距離private float spacing(MotionEvent event) {float x = event.getX(0) - event.getX(1);float y = event.getY(0) - event.getY(1);return FloatMath.sqrt(x * x + y * y);}//兩點中點private void midPoint(PointF point, MotionEvent event) {float x = event.getX(0) + event.getX(1);float y = event.getY(0) + event.getY(1);point.set(x / 2, y / 2);} });??? 此時圖像顯示的效果如下圖所示,點擊"打開"按鈕只能打開圖片,點擊"畫圖"按鈕能在原圖上繪制,在此點擊"畫圖"可以進行重繪.點擊"縮放"還能放大移動.但是點擊"畫圖"只能移動到(0,0)點,擔心坐標變換出現不一致現象.
??????????
??? 2.添加水印
??? 添加如下函數實現添加水印,主要是通過調用drawText繪制內容:
//添加水印文字 wordAddBn = (Button) findViewById(R.id.button2); layout = (RelativeLayout) findViewById(R.id.Content_Layout); wordAddBn.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {flagOnTouch = 2;//添加文字Bitmap bmpTemp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), bmp.getConfig()); Canvas cv = new Canvas(bmpTemp); Paint p = new Paint(); Typeface font = Typeface.create("宋體", Typeface.BOLD); p.setColor(Color.BLUE); p.setTypeface(font);p.setTextSize(40); cv.drawBitmap(bmp, 0, 0, p); imageShow.setImageBitmap(bmpTemp);cv.drawText("eastmount", 40, 40, p); cv.save(Canvas.ALL_SAVE_FLAG); cv.restore();} });??? 顯示效果如下圖所示:
???????????????????????????????????????? ????????????????
??? 我想實現的效果是點擊"文字"按鈕后彈出鍵盤輸入文字水印,并且可以拖動文字的效果.但效果不是很好如右圖,所以沒寫出來,只能添加固定的文字.下面的代碼是添加EditView代碼僅供參考:
??? 然后在觸摸事件onTouch中添加addWigdet(layout, x, y, createEditText())代碼即可實現,我的if(flagOnTouch==2)沒有填寫任何內容,就是因為預覽效果不是很好,讀者自己可以去嘗試完成~
??? 3.長按保存
??? 上面的代碼你可能覺得當添加文字或繪制后,在次點擊圖片為啥沒變化,那時因為我沒有保存.我想實現的功能是點擊圖片長按保存,在刷新下圖片即可完成修改.
??????最后希望該文章對大家有所幫助,尤其是Android初學者.該文章是講述Android使用監聽事件setOnTouchListener實現觸摸處理圖片的基礎文章,包括縮放移動圖片、添加水印、繪制圖片等.初學Android如果有不足或錯誤地方,請見諒~
??? 參考資料《Android多媒體開發高級編程 著:Shawn Van Every》
??? 下載地址:http://download.csdn.net/detail/eastmount/8091941
(By:Eastmount 2014-10-28 夜2點 ?http://blog.csdn.net/eastmount)?
參考資料和相關博文:
??? Android截圖以及加水印Demo By:tangcheng_ok
??? Android 自定義View消除鋸齒實現圖片旋轉,添加邊框及文字說明
??? Android圖片查看支持雙擊放大縮小、多點觸摸(邊界處理) By:TMajier
??? Android瀏覽圖片,點擊放大至全屏效果 By:roamer
??? 我的Android筆記(十三)Muilti-touch 雙指縮放的實現探索 By:barryhappy
總結
以上是生活随笔為你收集整理的[Android] 触屏setOnTouchListener实现图片缩放、移动、绘制和添加水印的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [Android] 使用Matrix矩阵
- 下一篇: [Android] 给图像添加相框、圆形