Android簡(jiǎn)單實(shí)現(xiàn)畫(huà)圖功能
如何在圖片上畫(huà)畫(huà)呢?這里寫(xiě)了一個(gè)demo,供大家參考
一、先看一眼工程結(jié)構(gòu)
工程結(jié)構(gòu):

二、自定義view
這個(gè)自定義view實(shí)現(xiàn)了保留軌跡的功能,代碼如下
package picturegame.view;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import com.winton.picturegame.R;
public class GameView extends View{
private Paint paint = null; //
private Bitmap originalBitmap = null;//原始圖
private Bitmap new1Bitmap = null;
private Bitmap new2Bitmap = null;
private float clickX =0;
private float clickY=0;
private float startX=0;
private float startY=0;
private boolean isMove = true;
private boolean isClear = false;
private int color =Color.RED;//默認(rèn)畫(huà)筆顏色為紅色
private float strokeWidth =2.0f;//默認(rèn)畫(huà)筆粗度
public GameView(Context context) {
this(context,null);
// TODO Auto-generated constructor stub
}
public GameView(Context context,AttributeSet atts) {
this(context,atts,0);
// TODO Auto-generated constructor stub
}
public GameView(Context context,AttributeSet atts,int defStyle) {
super(context,atts,defStyle);
// TODO Auto-generated constructor stub
originalBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.default_pic).copy(Bitmap.Config.ARGB_8888, true);//加載一張背景
new1Bitmap=originalBitmap.createBitmap(originalBitmap);
}
//清除函數(shù)
public void clear(){
isClear =true;
new2Bitmap=originalBitmap.createBitmap(originalBitmap);
invalidate();//重載
}
public void setStrokeWidth(float width){
this.strokeWidth=width;
initPaint();
}
@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
canvas.drawBitmap(writer(new1Bitmap),0,0, null);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// TODO Auto-generated method stub
clickX =event.getX();
clickY=event.getY();
if(event.getAction()==MotionEvent.ACTION_DOWN){
isMove =false;
invalidate();
return true;
}
else if(event.getAction()==MotionEvent.ACTION_MOVE){
isMove =true;
invalidate();
return true;
}
return super.onTouchEvent(event);
}
/**
* @Title: writer
* @Description: TODO(生成bitmap)
* @param @param pic
* @param @return 設(shè)定文件
* @return Bitmap 返回類(lèi)型
* @throws
*/
public Bitmap writer(Bitmap pic){
initPaint();
Canvas canvas =null;
if(isClear){
canvas=new Canvas(new2Bitmap);
}else{
canvas=new Canvas(pic);
}
if(isMove){
canvas.drawLine(startX, startY, clickX, clickY, paint);//劃線
}
startX = clickX;
startY =clickY;
if(isClear){
return new2Bitmap;
}
return pic;
}
private void initPaint(){
paint = new Paint();//新建畫(huà)筆
paint.setStyle(Style.STROKE);//設(shè)置為畫(huà)線
paint.setAntiAlias(true);//可以讓線條圓滑一些
paint.setColor(color);//設(shè)置畫(huà)筆顏色
paint.setStrokeWidth(strokeWidth);//設(shè)置畫(huà)筆線條的粗細(xì)
}
/**
* @Title: setColor
* @Description: TODO(設(shè)置線條顏色的對(duì)外接口)
* @param @param color 設(shè)定文件
* @return void 返回類(lèi)型
* @throws
*/
public void setColor(int color){
this.color=color;
initPaint();
}
}
三、主頁(yè)面布局文件
主頁(yè)面布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_horizontal"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:orientation="horizontal"
>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
>
<TextView
android:id="@+id/tv_30"
android:layout_width="30dp"
android:layout_height="30dp"
android:background="@drawable/bg_notifaction"
/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
>
<TextView
android:id="@+id/tv_25"
android:layout_width="25dp"
android:layout_height="25dp"
android:background="@drawable/bg_notifaction"
/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
>
<TextView
android:id="@+id/tv_20"
android:layout_width="20dp"
android:layout_height="20dp"
android:background="@drawable/bg_notifaction"
/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
>
<TextView
android:id="@+id/tv_15"
android:layout_width="15dp"
android:layout_height="15dp"
android:background="@drawable/bg_notifaction"
/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
>
<TextView
android:id="@+id/tv_10"
android:layout_width="10dp"
android:layout_height="10dp"
android:background="@drawable/bg_notifaction"
/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
>
<TextView
android:id="@+id/tv_5"
android:layout_width="5dp"
android:layout_height="5dp"
android:background="@drawable/bg_notifaction"
/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
>
<TextView
android:id="@+id/tv_2"
android:layout_width="2dp"
android:layout_height="2dp"
android:background="@drawable/bg_notifaction"
/>
</LinearLayout>
</LinearLayout>
<picturegame.view.GameView
android:layout_width="match_parent"
android:layout_height="300dp"
android:id="@+id/gameview"
/>
<Button
android:layout_width="200dp"
android:layout_height="80dp"
android:text="clear"
android:textColor="@color/black"
android:id="@+id/btn_clear"
/>
</LinearLayout>
四、主Activity代碼
package com.winton.picturegame;
import picturegame.view.GameView;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import com.winton.basemodule.BaseActivity;
public class MainActivity extends BaseActivity implements OnClickListener {
private GameView gameview = null;
private Button clear = null;
private TextView tv30,tv25,tv20,tv15,tv10,tv5,tv2;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
}
@Override
public void initView() {
// TODO Auto-generated method stub
setContentView(R.layout.activity_main);
gameview=(GameView)findViewById(R.id.gameview);
clear =(Button)findViewById(R.id.btn_clear);
tv30=(TextView)findViewById(R.id.tv_30);
tv25=(TextView)findViewById(R.id.tv_25);
tv20=(TextView)findViewById(R.id.tv_20);
tv15=(TextView)findViewById(R.id.tv_15);
tv10=(TextView)findViewById(R.id.tv_10);
tv5=(TextView)findViewById(R.id.tv_5);
tv2=(TextView)findViewById(R.id.tv_2);
}
@Override
public void initListener() {
// TODO Auto-generated method stub
clear.setOnClickListener(this);
tv30.setOnClickListener(this);
tv25.setOnClickListener(this);
tv20.setOnClickListener(this);
tv15.setOnClickListener(this);
tv10.setOnClickListener(this);
tv5.setOnClickListener(this);
tv2.setOnClickListener(this);
}
@Override
public void initData() {
// TODO Auto-generated method stub
}
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(v==clear){
gameview.clear();
return;
}
if(v==tv30){
gameview.setStrokeWidth(30f);
return;
}
if(v==tv25){
gameview.setStrokeWidth(25f);
return;
}
if(v==tv20){
gameview.setStrokeWidth(20f);
return;
}
if(v==tv15){
gameview.setStrokeWidth(15f);
return;
}
if(v==tv10){
gameview.setStrokeWidth(10f);
return;
}
if(v==tv5){
gameview.setStrokeWidth(5f);
return;
}
if(v==tv2){
gameview.setStrokeWidth(2f);
return;
}
}
}
五、效果
運(yùn)行效果圖如下

六、疑問(wèn)
當(dāng)線條變粗時(shí),線條會(huì)出現(xiàn)如上圖中不連續(xù)的問(wèn)題。請(qǐng)問(wèn)高手這個(gè)怎么處理呢?我猜測(cè)應(yīng)該要運(yùn)行算法,但還不知道怎么運(yùn)行。
文章就為大家介紹到這,其實(shí)還有許多知識(shí)點(diǎn)小編也不是很清楚,希望大家可以進(jìn)行補(bǔ)充擴(kuò)展,共同進(jìn)步。
- Android實(shí)現(xiàn)簡(jiǎn)單畫(huà)圖畫(huà)板
- Android 自定義view之畫(huà)圖板實(shí)現(xiàn)方法
- Android畫(huà)圖之抗鋸齒paint和Canvas兩種方式實(shí)例
- Android canvas畫(huà)圖操作之切割畫(huà)布實(shí)現(xiàn)方法(clipRect)
- Android編程畫(huà)圖之抗鋸齒解決方法
- Android入門(mén)之畫(huà)圖詳解
- Android畫(huà)圖并保存圖片的具體實(shí)現(xiàn)代碼
- Android?Studio實(shí)現(xiàn)簡(jiǎn)單繪圖板
相關(guān)文章
Flutter實(shí)現(xiàn)簡(jiǎn)單的下載按鈕動(dòng)畫(huà)
我們?cè)赼pp的開(kāi)發(fā)過(guò)程中經(jīng)常會(huì)用到一些表示進(jìn)度類(lèi)的動(dòng)畫(huà)效果,比如一個(gè)下載按鈕,那么在flutter中一個(gè)下載按鈕的動(dòng)畫(huà)應(yīng)該如何制作呢,一起來(lái)看看吧2023-05-05
Flutter懸浮按鈕FloatingActionButton使用詳解
本文主要介紹了Flutter懸浮按鈕FloatingActionButton使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-07-07
Android SQLite數(shù)據(jù)庫(kù)操作代碼類(lèi)分享
這篇文章主要介紹了Android SQLite數(shù)據(jù)庫(kù)操作代碼類(lèi)分享,本文直接給出實(shí)現(xiàn)代碼和使用代碼,需要的朋友可以參考下2015-03-03
Android Dialog對(duì)話框用法實(shí)例詳解
這篇文章主要介紹了Android Dialog對(duì)話框用法,結(jié)合實(shí)例形式分析了Android使用Dialog對(duì)話框過(guò)程中所涉及的創(chuàng)建、保存、回復(fù)等操作相關(guān)技巧與注意事項(xiàng),需要的朋友可以參考下2016-07-07
制作獨(dú)立的Android模擬器實(shí)現(xiàn)方法
本文主要介紹如何制作獨(dú)立的Android模擬器,這里給大家提供詳細(xì)的制作流程,有需要的小伙伴可以參考下2016-08-08
Android 模仿iPhone列表數(shù)據(jù)View刷新動(dòng)畫(huà)詳解
本文主要介紹Android 模仿iPhone列表數(shù)據(jù)view 刷新動(dòng)畫(huà)的資料,這里整理詳細(xì)的資料,并附示例代碼及實(shí)現(xiàn)效果圖,有興趣的小伙伴可以參考下2016-09-09
Android UI設(shè)計(jì)系列之HTML標(biāo)簽實(shí)現(xiàn)TextView設(shè)置中文字體加粗效果(6)
這篇文章主要介紹了Android UI設(shè)計(jì)系列之使用HTML標(biāo)簽,實(shí)現(xiàn)在TextView中對(duì)中文字體加粗的效果,具有一定的實(shí)用性和參考價(jià)值,感興趣的小伙伴們可以參考一下2016-06-06
android當(dāng)前apn的狀態(tài)以及獲取方法
在絕大多數(shù)android機(jī)器etc路徑下存放一個(gè)的apns-conf.xml文件,表示當(dāng)前機(jī)器使用的apn信息通過(guò)root機(jī)器可以push出來(lái)看看,具體路徑可以上網(wǎng)搜下,接下來(lái)介紹獲取apn的狀態(tài)的方法2013-01-01

