`
Entesar
  • 浏览: 2002 次
文章分类
社区版块
存档分类
最新评论

second project in android ((paint app))

阅读更多

Finally I have made my second app in android -paint app- I was so interested in making this app because I like drawing ,  It’s one of my hobbies.

now let start going into the project.
This is the final result of the project .

 

Before drawing 

 

After drawing



  Change color

 

 Make new page, change the size of the brush ,use eraser change the size of it, save your drawing to the gallery.

 

Now I will start explaining the coding part

Firstly create new android project, exactly same as previous project.

And create user interface of the app add picture buttons insert background , add dimensions for brush/eraser sizes

 

<!-- Brush sizes -->
<dimen name="small_brush">10dp</dimen>
<integer name="small_size">10</integer>
<dimen name="medium_brush">20dp</dimen>
<integer name="medium_size">20</integer>
<dimen name="large_brush">30dp</dimen>
<integer name="large_size">30</integer>

   

 

,add strings for new page ,brush ,eraser,save, and paint.

<string name="start_new">New</string>
<string name="brush">Brush</string>
<string name="erase">Erase</string>
<string name="save">Save</string>
<string name="paint">Paint</string>

 

 

 

inside the activity_main.xml i had made LinearLayout as the main layout.and drag LinearLayout inside th main main layout and to make the rows of the color i have made this for first row

<LinearLayout
    android:id="@+id/paint_colors"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >
</LinearLayout>

  and second row

<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >
</LinearLayout>

 the first row has an id because use in java class when the app starts the first default color as selected so that the user can start drawing straight away.i added a new xml file and named it "paint.xml" inside the drawable file and wrote the following code

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
    <shape android:shape="rectangle" >
        <stroke
            android:width="4dp"
            android:color="#FF999999" />
        <solid android:color="#00000000" />
        <padding
            android:bottom="0dp"
            android:left="0dp"
            android:right="0dp"
            android:top="0dp" />
    </shape>
</item>
<item>
    <shape xmlns:android="http://schemas.android.com/apk/res/android" >
        <stroke
            android:width="4dp"
            android:color="#FF999999" />
        <solid android:color="#00000000" />
        <corners android:radius="10dp" />
    </shape>
</item>
</layer-list>

 it is a little complex than it looks at first glance. To create a rounded button appearance, we use two layered Shape drawables, one rectangle outline and theother a rounded stroke.The strokes have gray color , with transparency in the middle through which the background color for each button will be seen(the background color being the color represented by the button). 

 

so, now for each color, i used the following ImageButton structure:

inside the first row LinearLayout

 

<ImageButton
    android:layout_width="@dimen/large_brush"
    android:layout_height="@dimen/large_brush"
    android:layout_margin="2dp"
    android:background="#FF660000"
    android:contentDescription="@string/paint"
    android:onClick="paintClicked"
    android:src="@drawable/paint"
    android:tag="#FF660000" />
 
<ImageButton
    android:layout_width="@dimen/large_brush"
    android:layout_height="@dimen/large_brush"
    android:layout_margin="2dp"
    android:background="#FFFF0000"
    android:contentDescription="@string/paint"
    android:onClick="paintClicked"
    android:src="@drawable/paint"
    android:tag="#FFFF0000" />
 
<ImageButton
    android:layout_width="@dimen/large_brush"
    android:layout_height="@dimen/large_brush"
    android:layout_margin="2dp"
    android:background="#FFFF6600"
    android:contentDescription="@string/paint"
    android:onClick="paintClicked"
    android:src="@drawable/paint"
    android:tag="#FFFF6600" />
 
<ImageButton
    android:layout_width="@dimen/large_brush"
    android:layout_height="@dimen/large_brush"
    android:layout_margin="2dp"
    android:background="#FFFFCC00"
    android:contentDescription="@string/paint"
    android:onClick="paintClicked"
    android:src="@drawable/paint"
    android:tag="#FFFFCC00" />
 
<ImageButton
    android:layout_width="@dimen/large_brush"
    android:layout_height="@dimen/large_brush"
    android:layout_margin="2dp"
    android:background="#FF009900"
    android:contentDescription="@string/paint"
    android:onClick="paintClicked"
    android:src="@drawable/paint"
    android:tag="#FF009900" />
 
<ImageButton
    android:layout_width="@dimen/large_brush"
    android:layout_height="@dimen/large_brush"
    android:layout_margin="2dp"
    android:background="#FF009999"
    android:contentDescription="@string/paint"
    android:onClick="paintClicked"
    android:src="@drawable/paint"
    android:tag="#FF009999" />

 inside the second row LinearLayout

 

 

<ImageButton
    android:layout_width="@dimen/large_brush"
    android:layout_height="@dimen/large_brush"
    android:layout_margin="2dp"
    android:background="#FF0000FF"
    android:contentDescription="@string/paint"
    android:onClick="paintClicked"
    android:src="@drawable/paint"
    android:tag="#FF0000FF" />
 
<ImageButton
    android:layout_width="@dimen/large_brush"
    android:layout_height="@dimen/large_brush"
    android:layout_margin="2dp"
    android:background="#FF990099"
    android:contentDescription="@string/paint"
    android:onClick="paintClicked"
    android:src="@drawable/paint"
    android:tag="#FF990099" />
 
<ImageButton
    android:layout_width="@dimen/large_brush"
    android:layout_height="@dimen/large_brush"
    android:layout_margin="2dp"
    android:background="#FFFF6666"
    android:contentDescription="@string/paint"
    android:onClick="paintClicked"
    android:src="@drawable/paint"
    android:tag="#FFFF6666" />
 
<ImageButton
    android:layout_width="@dimen/large_brush"
    android:layout_height="@dimen/large_brush"
    android:layout_margin="2dp"
    android:background="#FFFFFFFF"
    android:contentDescription="@string/paint"
    android:onClick="paintClicked"
    android:src="@drawable/paint"
    android:tag="#FFFFFFFF" />
 
<ImageButton
    android:layout_width="@dimen/large_brush"
    android:layout_height="@dimen/large_brush"
    android:layout_margin="2dp"
    android:background="#FF787878"
    android:contentDescription="@string/paint"
    android:onClick="paintClicked"
    android:src="@drawable/paint"
    android:tag="#FF787878" />
 
<ImageButton
    android:layout_width="@dimen/large_brush"
    android:layout_height="@dimen/large_brush"
    android:layout_margin="2dp"
    android:background="#FF000000"
    android:contentDescription="@string/paint"
    android:onClick="paintClicked"
    android:src="@drawable/paint"
    android:tag="#FF000000" />

 i used one of the dimension values that i had defined for th color button.
  after finishing the user interface i started to implement drawing on the canvas and choosing  colors.

 

create new class named it DrawingView and extends View and then define all the variables that i will use:

       //drawing path       
        private Path drawPath;
	//drawing and canvas paint
	private Paint drawPaint, canvasPaint;
	//initial color
	private int paintColor = 0xFF660000;
	//canvas
	private Canvas drawCanvas;
	//canvas bitmap
	private Bitmap canvasBitmap;
	
	

when the user touches the screen and moves their finger to draw, I used a path to trace their drawing actin on the canvas.Both the canvas and the drawing on top of it are represented by paint objects. The initial paint color corresponds to the first color in the   palette i had created before , which will be initiallly selected when the app launches. Finally  i declared variables for the canvas and bitmap- the user paths drawn with drawPaint wil be drawn onto the canvas, which is drawn with canvasPaint.

added new method and named it setupDrawing and instantiate some of these variables to set set the class up for drawing .

first instantiate the drawing Path and Paint objects

next set the initial color 

and then set the initail path properties:

 

                drawPath = new Path();
		drawPaint = new Paint();
                //drawPaint.setColor(paintColor);
		drawPaint.setAntiAlias(true);
		drawPaint.setStrokeWidth(20);
		drawPaint.setStyle(Paint.Style.STROKE);
		drawPaint.setStrokeJoin(Paint.Join.ROUND);
		drawPaint.setStrokeCap(Paint.Cap.ROUND);

 

 

 

  complete the setupDrawing method by instantiating the canvas Paint object:

 

canvasPaint = new Paint(Paint.DITHER_FLAG);

 i set dithering by passing a parameter to constructor.

 

 

then override the couple of methods to make the custom view function as a drawing view.

@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
	//view given size
		super.onSizeChanged(w, h, oldw, oldh);
		canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
		drawCanvas = new Canvas(canvasBitmap);
	}
@Override
	protected void onDraw(Canvas canvas) {
	//draw view
		canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
		canvas.drawPath(drawPath, drawPaint);
	}

 when the drawing view is on the app screen, we want user touches on it to regester as drawing operations.

 

to do this we need to listen for touch events. 

		public boolean onTouchEvent(MotionEvent event) {
	//detect user touch     
		float touchX = event.getX();
		float touchY = event.getY();
		
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
		    drawPath.moveTo(touchX, touchY);
		    break;
		case MotionEvent.ACTION_MOVE:
		    drawPath.lineTo(touchX, touchY);
		    break;
		case MotionEvent.ACTION_UP:
		    drawCanvas.drawPath(drawPath, drawPaint);
		    drawPath.reset();
		    break;
		default:
		    return false;
		}
		invalidate();
		return true;//Calling invalidate will cause the onDraw method to execute.
	}

 The MotionEvent parameter to the onTouchEvent method will let us respond to particular touch events. the actions we are interesteed in to implement drawing are down,move and up. Added a switch statement in the method to respond .

 

when the user touches the view, we move to that position to start drawing. when they move thier finger on the View wedraw the path along with their touch. when they lift their finger up off the view , we draw the path and reset it for the next drawing operation.

Let's now talk about implementing the ability for the user to choose colors from the palette. 

inside main activity class inside onCreate methode i instantiated variables by retrieving a reference to it from the layout:

 

                drawView = (DrawingView)findViewById(R.id.drawing);
		LinearLayout paintLayout = (LinearLayout)findViewById(R.id.paint_colors);
		currPaint = (ImageButton)paintLayout.getChildAt(0);
		currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed));
		smallBrush = getResources().getInteger(R.integer.small_size);
		mediumBrush = getResources().getInteger(R.integer.medium_size);
		largeBrush = getResources().getInteger(R.integer.large_size);
		drawBtn = (ImageButton)findViewById(R.id.draw_btn);
		drawBtn.setOnClickListener(this);
		drawView.setBrushSize(mediumBrush);
		eraseBtn = (ImageButton)findViewById(R.id.erase_btn);
		eraseBtn.setOnClickListener(this);
		newBtn = (ImageButton)findViewById(R.id.new_btn);
		newBtn.setOnClickListener(this);
		saveBtn = (ImageButton)findViewById(R.id.save_btn);
		saveBtn.setOnClickListener(this);

get the fir button and store it as the instance varable and use different drawable image on the button to show that it is currently selected: 

currPaint = (ImageButton)paintLayout.getChildAt(0);
currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed));
		

 i added this new "paint_pressed.xml" file inside drawable file and wrote the following code

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item>
        <shape android:shape="rectangle" >
            <stroke
                android:width="4dp"
                android:color="#FF333333" />
 
            <solid android:color="#00000000" />
 
            <padding
                android:bottom="0dp"
                android:left="0dp"
                android:right="0dp"
                android:top="0dp" />
        </shape>
    </item>
    <item>
        <shape xmlns:android="http://schemas.android.com/apk/res/android" >
            <stroke
                android:width="4dp"
                android:color="#FF333333" />
 
            <solid android:color="#00000000" />
 
            <corners android:radius="10dp" />
        </shape>
    </item>
</layer-list>

 it is very similar to the"paint.xml"drawable we created last time, but with  darker color around the paint.

I went go back to main activity class and  added paintClicked method 

	public void paintClicked(View view){
		//use chosen color
		if(view!=currPaint){
			//update color
			ImageButton imgView = (ImageButton)view;
			String color = view.getTag().toString();
			drawView.setColor(color);
			imgView.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed));
			currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint));
			currPaint=(ImageButton)view;
			}
		
		
	
	}

  first check that the user has clicked a paint color that is not the currently selected one,then retrieve the tag we set for each button in the layout , representing the chosen color.

 

 

then i needed to use the custom View class to set the color , so i added set color in side Drawing View class 

public void setColor(String newColor){
		//set color
		invalidate();
		paintColor = Color.parseColor(newColor);
		drawPaint.setColor(paintColor);
		}

 start by invalidating th View , then set the color for drawing, now going back to the main activity, in paintClicked method after retriving the color tag , call the new method on the custom drawing View object and then update th user interface to reflect the new chosen paint and set the previouse one back to the normal.

 

now i will discuss the last part of my project. About the ability to erase to create new drawing page ,to save a drawing to the gallary of your device.

 in the previouse part i discussed about drawing on the canvas, then now i will discuss how to make the user choose a brush size. The brush size options will appear when the user presses the brush button  I added t the interface. To respond to this, extend the opening line of in main activity class declaration to the implement the OnClickListener interface:

public class MainActivity extends Activity implements OnClickListener
override onClick method and check for clicks on the drawing button using if statement

 

 

@Override
public void onClick(View view){
//respond to clicks    
 if(view.getId()==R.id.draw_btn){
    //draw button clicked
final Dialog brushDialog = new Dialog(this);
brushDialog.setTitle("Brush size:");
} 
}
 

 

 

 there are another coditional blocks i will speak about them later.When the  user clicks the button i already displayed a dialog presenting them with the three button sizes.Inside the if block, and create a dialog and set the titleThen i defined the dialog layout in "brush_chooser.xml" inside layout file and entering the following code and inside the Layout ,added a button for each size: 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical" >
 <ImageButton
    android:id="@+id/small_brush"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:contentDescription="@string/sml"
    android:src="@drawable/small" />
 
<ImageButton
    android:id="@+id/medium_brush"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:contentDescription="@string/med"
    android:src="@drawable/medium" />
 
<ImageButton
    android:id="@+id/large_brush"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_weight="1"
    android:contentDescription="@string/lrg"
    android:src="@drawable/large" />
</LinearLayout>

 

 then dd specified strings to "string.xml" Small ,Medium,Large then add three xml files for each of them 

 

 

"small.xml"
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:dither="true"
    android:shape="oval" >
 
    <size
        android:height="@dimen/small_brush"
        android:width="@dimen/small_brush" />
 
    <solid android:color="#FF666666" />
 
</shape>
 "medium.xml"
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:dither="true"
    android:shape="oval" >
 
    <size
        android:height="@dimen/medium_brush"
        android:width="@dimen/medium_brush" />
 
    <solid android:color="#FF666666" />
 
</shape>
 
"large.xml"
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:dither="true"
    android:shape="oval" >
 
    <size
        android:height="@dimen/large_brush"
        android:width="@dimen/large_brush" />
 
    <solid android:color="#FF666666" />
 
</shape>
created the dialog and set its title in main activity class in side onClick method. 
brushDialog.setContentView(R.layout.brush_chooser);
 i added two instance variables to the class:
private float brushSize, lastBrushSize;
 and used the first varriable for the brush size and the second to keep track of the last brush size used when the user switches to the user switches to the eraser, so that we can revert back  to the correct size when they decide to switch back to drawing. In the setupDrawing method . 
brushSize = getResources().getInteger(R.integer.medium_size);
lastBrushSize = brushSize;
 after that I used the dimension value for the medium sized brush to begin with. then I could update the line in the method where I set the stroke width with a hard coded value to use this varable value instead:
drawPaint.setStrokeWidth(brushSize);
 then Added th following method to the class to set the brush size and update the brush size:
public void setBrushSize(float newSize){
//update size
float pixelAmount = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 
    newSize, getResources().getDisplayMetrics());
brushSize=pixelAmount;
drawPaint.setStrokeWidth(brushSize);
}
 then passing the value from the dimensions file when I call this method, so I have to calculate it's dimension value.I update the variable and the paint object to use the new size .then ass methods to get and set the other size variable I created:
public void setLastBrushSize(float lastSize){
    lastBrushSize=lastSize;
}
public float getLastBrushSize(){
    return lastBrushSize;
}
 I called these methods from the main Activity class.
 went back to the main activity class, l complete the dialog code in the onClick method.After setting  the content view on then dialog object, listen for clicks on the three size buttons, starting with the small one :
ImageButton smallBtn = (ImageButton)brushDialog.findViewById(R.id.small_brush);
smallBtn.setOnClickListener(new OnClickListener(){
    @Override
    public void onClick(View v) {
        drawView.setBrushSize(smallBrush);
        drawView.setLastBrushSize(smallBrush);
        brushDialog.dismiss();
    }
});

 I set the size using the methods we added to the custom View class as soon as the user clicks a brush size button, then immediately dismiss the Dialog. next did the same for medium and large buttons:
 
ImageButton mediumBtn = (ImageButton)brushDialog.findViewById(R.id.medium_brush);
mediumBtn.setOnClickListener(new OnClickListener(){
    @Override
    public void onClick(View v) {
        drawView.setBrushSize(mediumBrush);
        drawView.setLastBrushSize(mediumBrush);
        brushDialog.dismiss();
    }
});
 
ImageButton largeBtn = (ImageButton)brushDialog.findViewById(R.id.large_brush);
largeBtn.setOnClickListener(new OnClickListener(){
    @Override
    public void onClick(View v) {
        drawView.setBrushSize(largeBrush);
        drawView.setLastBrushSize(largeBrush);
        brushDialog.dismiss();
    }
});
 then completed the draw button section of onClick by displaying the dialog:
brushDialog.show();
 The dialog will display until the user makes a selection or goes back to the Activity.

 then used the new method to set the initial brush size in onCreate:
drawView.setBrushSize(mediumBrush);
 for erasing , reset the drawing page (new drawings),saving  you understand by reading my code because little differences with the previouse one .I won't discuss about it .
This all my code:
//MainActivity.java
package com.example.paint;


public class MainActivity extends Activity implements OnClickListener {
	
	private DrawingView drawView;
	private ImageButton currPaint, drawBtn,eraseBtn,newBtn, saveBtn;
	private float smallBrush, mediumBrush, largeBrush;
	
	
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		drawView = (DrawingView)findViewById(R.id.drawing);
		LinearLayout paintLayout = (LinearLayout)findViewById(R.id.paint_colors);
		currPaint = (ImageButton)paintLayout.getChildAt(0);
		currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed));
		smallBrush = getResources().getInteger(R.integer.small_size);
		mediumBrush = getResources().getInteger(R.integer.medium_size);
		largeBrush = getResources().getInteger(R.integer.large_size);
		drawBtn = (ImageButton)findViewById(R.id.draw_btn);
		drawBtn.setOnClickListener(this);
		drawView.setBrushSize(mediumBrush);
		eraseBtn = (ImageButton)findViewById(R.id.erase_btn);
		eraseBtn.setOnClickListener(this);
		newBtn = (ImageButton)findViewById(R.id.new_btn);
		newBtn.setOnClickListener(this);
		saveBtn = (ImageButton)findViewById(R.id.save_btn);
		saveBtn.setOnClickListener(this);
	}

	public void paintClicked(View view){
		drawView.setErase(false);
		drawView.setBrushSize(drawView.getLastBrushSize());
		//use chosen color
		if(view!=currPaint){
			//update color
			ImageButton imgView = (ImageButton)view;
			String color = view.getTag().toString();
			drawView.setColor(color);
			imgView.setImageDrawable(getResources().getDrawable(R.drawable.paint_pressed));
			currPaint.setImageDrawable(getResources().getDrawable(R.drawable.paint));
			currPaint=(ImageButton)view;
			}
		
		
	
	}
	@Override
	public void onClick(View view){
	//respond to clicks
		if(view.getId()==R.id.draw_btn){
		    //draw button clicked
			final Dialog brushDialog = new Dialog(this);
			brushDialog.setTitle("Brush size:");
	        brushDialog.setContentView(R.layout.brush_chooser);
		
			ImageButton smallBtn = (ImageButton)brushDialog.findViewById(R.id.small_brush);
			smallBtn.setOnClickListener(new OnClickListener(){
			    @Override
			    public void onClick(View v) {
			        drawView.setBrushSize(smallBrush);
			        drawView.setLastBrushSize(smallBrush);
			        drawView.setErase(false);
			        brushDialog.dismiss();
			    }
			});
			ImageButton mediumBtn = (ImageButton)brushDialog.findViewById(R.id.medium_brush);
			mediumBtn.setOnClickListener(new OnClickListener(){
			    @Override
			    public void onClick(View v) {
			        drawView.setBrushSize(mediumBrush);
			        drawView.setLastBrushSize(mediumBrush);
			        drawView.setErase(false);
			        brushDialog.dismiss();
			    }
			});
			 
			ImageButton largeBtn = (ImageButton)brushDialog.findViewById(R.id.large_brush);
			largeBtn.setOnClickListener(new OnClickListener(){
			    @Override
			    public void onClick(View v) {
			        drawView.setBrushSize(largeBrush);
			        drawView.setLastBrushSize(largeBrush);
			        drawView.setErase(false);
			        brushDialog.dismiss();
			    }
			});
			brushDialog.show();
		}
		else if(view.getId()==R.id.erase_btn){
		    //switch to erase - choose size
			final Dialog brushDialog = new Dialog(this);
			brushDialog.setTitle("Eraser size:");
			brushDialog.setContentView(R.layout.brush_chooser);
			ImageButton smallBtn = (ImageButton)brushDialog.findViewById(R.id.small_brush);
			smallBtn.setOnClickListener(new OnClickListener(){
			    @Override
			    public void onClick(View v) {
			        drawView.setErase(true);
			        drawView.setBrushSize(smallBrush);
			        brushDialog.dismiss();
			    }
			});
			ImageButton mediumBtn = (ImageButton)brushDialog.findViewById(R.id.medium_brush);
			mediumBtn.setOnClickListener(new OnClickListener(){
			    @Override
			    public void onClick(View v) {
			        drawView.setErase(true);
			        drawView.setBrushSize(mediumBrush);
			        brushDialog.dismiss();
			    }
			});
			ImageButton largeBtn = (ImageButton)brushDialog.findViewById(R.id.large_brush);
			largeBtn.setOnClickListener(new OnClickListener(){
			    @Override
			    public void onClick(View v) {
			        drawView.setErase(true);
			        drawView.setBrushSize(largeBrush);
			        brushDialog.dismiss();
			    }
			});
			brushDialog.show();
			
		}
		else if(view.getId()==R.id.new_btn){
		    //new button
			AlertDialog.Builder newDialog = new AlertDialog.Builder(this);
			newDialog.setTitle("New drawing");
			newDialog.setMessage("Start new drawing (you will lose the current drawing)?");
			newDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener(){
			    public void onClick(DialogInterface dialog, int which){
			        drawView.startNew();
			        dialog.dismiss();
			    }
			});
			newDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener(){
			    public void onClick(DialogInterface dialog, int which){
			        dialog.cancel();
			    }
			});
			newDialog.show();
		}
		else if(view.getId()==R.id.save_btn){
            //save drawing
			AlertDialog.Builder saveDialog = new AlertDialog.Builder(this);
			saveDialog.setTitle("Save drawing");
			saveDialog.setMessage("Save drawing to device Gallery?");
			saveDialog.setPositiveButton("Yes", new DialogInterface.OnClickListener(){
			    public void onClick(DialogInterface dialog, int which){
			        //save drawing
			    }
			});
			saveDialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener(){
			    public void onClick(DialogInterface dialog, int which){
			        dialog.cancel();
			    }
			});
			saveDialog.show();
			drawView.setDrawingCacheEnabled(true);
			//write the image to a file:
			String imgSaved = MediaStore.Images.Media.insertImage(
				    getContentResolver(), drawView.getDrawingCache(),
				    UUID.randomUUID().toString()+".png", "drawing");
			if(imgSaved!=null){
			    Toast savedToast = Toast.makeText(getApplicationContext(), 
			        "Drawing saved to Gallery!", Toast.LENGTH_SHORT);
			    savedToast.show();
			}
			else{
			    Toast unsavedToast = Toast.makeText(getApplicationContext(), 
			        "Oops! Image could not be saved.", Toast.LENGTH_SHORT);
		    unsavedToast.show();

			}
			drawView.destroyDrawingCache();
      }
		
	}
	
	
}
 
//DrawingView.java
package com.example.paint;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.view.MotionEvent;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.View;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.TypedValue;
public class DrawingView extends View{
	//drawing path
	private Path drawPath;
	//drawing and canvas paint
	private Paint drawPaint, canvasPaint;
	//initial color
	private int paintColor = 0xFF660000;
	//canvas
	private Canvas drawCanvas;
	//canvas bitmap
	private Bitmap canvasBitmap;
	
	private DrawingView drawView;
	private float brushSize, lastBrushSize;
	private boolean erase=false;
	public DrawingView(Context context) {
		super(context);
		
	}
	public DrawingView(Context context, AttributeSet attrs) {
		super(context, attrs);
		 setupDrawing();
	}
	private void setupDrawing(){
		//get drawing area setup for interaction    
		brushSize = getResources().getInteger(R.integer.medium_size);
		lastBrushSize = brushSize;
		brushSize = getResources().getInteger(R.integer.medium_size);
		lastBrushSize = brushSize;
		drawPath = new Path();
		drawPaint = new Paint();
		drawPaint.setColor(paintColor);
		drawPaint.setAntiAlias(true);
		drawPaint.setStrokeWidth(20);
		drawPaint.setStyle(Paint.Style.STROKE);
		drawPaint.setStrokeJoin(Paint.Join.ROUND);
		drawPaint.setStrokeCap(Paint.Cap.ROUND);
		canvasPaint = new Paint(Paint.DITHER_FLAG);
		}
	@Override
	protected void onSizeChanged(int w, int h, int oldw, int oldh) {
	//view given size
		super.onSizeChanged(w, h, oldw, oldh);
		canvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
		drawCanvas = new Canvas(canvasBitmap);
	}
	@Override
	protected void onDraw(Canvas canvas) {
	//draw view
		canvas.drawBitmap(canvasBitmap, 0, 0, canvasPaint);
		canvas.drawPath(drawPath, drawPaint);
	}
	@Override
	public boolean onTouchEvent(MotionEvent event) {
	//detect user touch     
		float touchX = event.getX();
		float touchY = event.getY();
		
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
		    drawPath.moveTo(touchX, touchY);
		    break;
		case MotionEvent.ACTION_MOVE:
		    drawPath.lineTo(touchX, touchY);
		    break;
		case MotionEvent.ACTION_UP:
		    drawCanvas.drawPath(drawPath, drawPaint);
		    drawPath.reset();
		    break;
		default:
		    return false;
		}
		invalidate();
		return true;//Calling invalidate will cause the onDraw method to execute.
	}
	public void setColor(String newColor){
		//set color
		invalidate();
		paintColor = Color.parseColor(newColor);
		drawPaint.setColor(paintColor);
		}
	public void setBrushSize(float newSize){
		//update size
		float pixelAmount = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 
			    newSize, getResources().getDisplayMetrics());
			brushSize=pixelAmount;
			drawPaint.setStrokeWidth(brushSize);
		}
	public void setLastBrushSize(float lastSize){
	    lastBrushSize=lastSize;
	}
	public float getLastBrushSize(){
	    return lastBrushSize;
	}
	public void setErase(boolean isErase){
		//set erase true or false      
		erase=isErase;
		if(erase) drawPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
		else drawPaint.setXfermode(null);
		}
	public void startNew(){
	    drawCanvas.drawColor(0, PorterDuff.Mode.CLEAR);
	    invalidate();
	}
}

 
 It was awesome experience while doing this project .If there is any questions you can ask I will try to answer. 
 
  • 大小: 903.1 KB
  • 大小: 950 KB
  • 大小: 27.6 KB
  • 大小: 26.4 KB
  • 大小: 67.1 KB
分享到:
评论
1 楼 梳子不爱头发 2017-08-10  
很不错哩,加油

相关推荐

    A Second Course in Stochastic Process

    A Second Course in Stochastic Process A Second Course in Stochastic Process

    Robotium_Test Android Sample App.pdf

    本文将基于“Robotium_Test Android Sample App.pdf”这一文档,深入解析如何利用Robotium来测试Android应用,包括创建测试项目、编写测试用例、添加Robotium jar以及编写测试代码的具体步骤。 ### 一、创建测试...

    Coding project in python

    Perfect for kids ages 10 and over who are ready to take a second step after Scratch, Coding Projects in Python teaches kids how to build amazing graphics, fun games, and useful apps. All they need is ...

    A Second Course in Stochastic Processes

    根据提供的文件信息,“A Second Course in Stochastic Processes”是一本深入探讨随机过程理论与应用的专业书籍,由Samuel Karlin和Howard M. Taylor共同撰写。本书作为“Stochastic Processes”领域的进阶教材,...

    SecondProject:创建虚拟的Secondproject

    【标题】"SecondProject:创建虚拟的Secondproject" 涉及的知识点主要围绕着软件开发中的项目管理和版本控制工具Git。在这个项目中,我们关注的是如何使用Git来创建和管理一个名为"SecondProject"的虚拟项目。 首先...

    Beginning Android Games

    "Beginning Android Games, Second Edition offers everything you need to join the ranks of successful Android game developers, including Android tablet game app development considerations. You'll start...

    App.Inventor.2.Building.Android.Apps.B0193RHQG6

    App Inventor 2 Building Android Apps takes you step-by-step through the whole process of designing and creating your first two android apps using the free MIT App Inventor 2 software. The book is ...

    测试referrer的SecondApp的代码

    标题“测试referrer的SecondApp的代码”表明这是一个针对名为 "SecondApp" 的Android应用进行的测试,目的是验证 `getReferrer()` 方法的功能。这通常发生在开发者想要确保从其他应用跳转到 "SecondApp" 时,能够...

    Android Cookbook: Problems and Solutions for Android Developers

    Each recipe provides a clear solution and sample code you can use in your project right away. Among numerous topics, this cookbook helps you: Get started with the tooling you need for developing and...

    Reactive Android Programming

    Later in the second part the reader will learn RxJava 2.0 step-by-step by starting off with stock data processing and display. Together with this a developer will learn to choose appropriate ...

    Android 工程展示一个Activity 调用另一个app里的 Activity 和 Service

    这里包括两个 eclipse 工程, 在一个工程FirstAndroid里调用另一个工程SecondAndroid里的Activity 和 Service,SecondAndroid只能通过别的app 来启动,它自己不能启动,因为它没有 android.intent.action.MAIN这个...

    Android代码-WIFIADB

    The first one is an android project,and the second is an intellij plugin project. You can see more information in the respective project,and I hope you can tell me your suggestions. Developed By ...

    Android代码-android

    Sunshine is the companion Android app for the Udacity course Developing Android Apps: Android Fundamentals. Take the course to find out how to build this app a step at a time, and eventually create ...

    app-call:两个Android应用程序和Web应用程序之间的通信-Android应用程序

    应用调用应用程序调用是一个演示,用于显示Android和html页面中的...通过网络浏览器打开Android应用通过另一个应用程序打开Android应用程序申请者网页浏览器项目路径: app-call/web/ 发送带有查询参数的参数: href=...

Global site tag (gtag.js) - Google Analytics