‏إظهار الرسائل ذات التسميات Android code sample: detect touch. إظهار كافة الرسائل
‏إظهار الرسائل ذات التسميات Android code sample: detect touch. إظهار كافة الرسائل

الجمعة، 6 يونيو 2014

Change speed of Animation follow touch path

This exercise change the speed of the former example of "Animation follow touch path".


AnimationView.java
package com.example.androidanimationalongpath;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class AnimationView extends View {

Paint paint;

Bitmap bm;
int bm_offsetX, bm_offsetY;

Path animPath;
PathMeasure pathMeasure;
float pathLength;

float step; //distance each step
float distance; //distance moved
float curX, curY;

float curAngle; //current angle
float targetAngle; //target angle
float stepAngle; //angle each step

float[] pos;
float[] tan;

Matrix matrix;

Path touchPath;

public AnimationView(Context context) {
super(context);
initMyView();
}

public AnimationView(Context context, AttributeSet attrs) {
super(context, attrs);
initMyView();
}

public AnimationView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initMyView();
}

public void initMyView(){
paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(1);
paint.setStyle(Paint.Style.STROKE);

bm = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
bm_offsetX = bm.getWidth()/2;
bm_offsetY = bm.getHeight()/2;

animPath = new Path();

pos = new float[2];
tan = new float[2];

matrix = new Matrix();

touchPath = new Path();

step = 1; //default
stepAngle = 1; //default
}

@Override
protected void onDraw(Canvas canvas) {
if(animPath.isEmpty()){
return;
}

canvas.drawPath(animPath, paint);

matrix.reset();

if((targetAngle-curAngle)>stepAngle){
curAngle += stepAngle;
matrix.postRotate(curAngle, bm_offsetX, bm_offsetY);
matrix.postTranslate(curX, curY);
canvas.drawBitmap(bm, matrix, null);

invalidate();
}else if((curAngle-targetAngle)>stepAngle){
curAngle -= stepAngle;
matrix.postRotate(curAngle, bm_offsetX, bm_offsetY);
matrix.postTranslate(curX, curY);
canvas.drawBitmap(bm, matrix, null);

invalidate();
}else{
curAngle=targetAngle;
if(distance < pathLength){
pathMeasure.getPosTan(distance, pos, tan);

targetAngle = (float)(Math.atan2(tan[1], tan[0])*180.0/Math.PI);
matrix.postRotate(curAngle, bm_offsetX, bm_offsetY);

curX = pos[0]-bm_offsetX;
curY = pos[1]-bm_offsetY;
matrix.postTranslate(curX, curY);

canvas.drawBitmap(bm, matrix, null);

distance += step;

invalidate();
}else{
matrix.postRotate(curAngle, bm_offsetX, bm_offsetY);
matrix.postTranslate(curX, curY);
canvas.drawBitmap(bm, matrix, null);
}
}

}

@Override
public boolean onTouchEvent(MotionEvent event) {

int action = event.getAction();

switch(action){
case MotionEvent.ACTION_DOWN:
touchPath.reset();
touchPath.moveTo(event.getX(), event.getY());
break;
case MotionEvent.ACTION_MOVE:
touchPath.lineTo(event.getX(), event.getY());
break;
case MotionEvent.ACTION_UP:
touchPath.lineTo(event.getX(), event.getY());
animPath = new Path(touchPath);

pathMeasure = new PathMeasure(animPath, false);
pathLength = pathMeasure.getLength();

//step = 1;
distance = 0;
curX = 0;
curY = 0;

//stepAngle = 1;
curAngle = 0;
targetAngle = 0;

invalidate();

break;

}

return true;
}

public void setSpeed(int sp){
step = sp;
stepAngle = sp;
}

}

/res/layout/activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.androidanimationalongpath.MainActivity" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />

<SeekBar
android:id="@+id/speedbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="10"
android:progress="1"/>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >

<com.example.androidanimationalongpath.AnimationView
android:id="@+id/animationview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:background="@android:color/darker_gray" />

</LinearLayout>

</LinearLayout>

MainActivity.java
package com.example.androidanimationalongpath;

import android.support.v7.app.ActionBarActivity;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.os.Bundle;

public class MainActivity extends ActionBarActivity {

AnimationView animationView;
SeekBar speedBar;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

animationView = (AnimationView)findViewById(R.id.animationview);
speedBar = (SeekBar)findViewById(R.id.speedbar);
speedBar.setOnSeekBarChangeListener(speedBarOnSeekBarChangeListener);
animationView.setSpeed(speedBar.getProgress()); //set default speed
}

OnSeekBarChangeListener speedBarOnSeekBarChangeListener =
new OnSeekBarChangeListener(){

@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
//offset from SeekBar 0~19 to step 1~10
animationView.setSpeed(progress);
}

@Override
public void onStartTrackingTouch(SeekBar seekBar) {}

@Override
public void onStopTrackingTouch(SeekBar seekBar) {}};


}


download filesDownload the files.

More example of Drawing Path on canvas of custom View.

الثلاثاء، 27 مايو 2014

Animation follow touch path

This example show how to implement animation of moving bitmap follow the touch moving path.


AnimationView.java
package com.example.androidanimationalongpath;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class AnimationView extends View {

Paint paint;

Bitmap bm;
int bm_offsetX, bm_offsetY;

Path animPath;
PathMeasure pathMeasure;
float pathLength;

float step; //distance each step
float distance; //distance moved
float curX, curY;

float curAngle; //current angle
float targetAngle; //target angle
float stepAngle; //angle each step

float[] pos;
float[] tan;

Matrix matrix;

Path touchPath;

public AnimationView(Context context) {
super(context);
initMyView();
}

public AnimationView(Context context, AttributeSet attrs) {
super(context, attrs);
initMyView();
}

public AnimationView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initMyView();
}

public void initMyView(){
paint = new Paint();
paint.setColor(Color.BLUE);
paint.setStrokeWidth(1);
paint.setStyle(Paint.Style.STROKE);

bm = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
bm_offsetX = bm.getWidth()/2;
bm_offsetY = bm.getHeight()/2;

animPath = new Path();

pos = new float[2];
tan = new float[2];

matrix = new Matrix();

touchPath = new Path();
}

@Override
protected void onDraw(Canvas canvas) {

if(animPath.isEmpty()){
return;
}

canvas.drawPath(animPath, paint);

matrix.reset();

if((targetAngle-curAngle)>stepAngle){
curAngle += stepAngle;
matrix.postRotate(curAngle, bm_offsetX, bm_offsetY);
matrix.postTranslate(curX, curY);
canvas.drawBitmap(bm, matrix, null);

invalidate();
}else if((curAngle-targetAngle)>stepAngle){
curAngle -= stepAngle;
matrix.postRotate(curAngle, bm_offsetX, bm_offsetY);
matrix.postTranslate(curX, curY);
canvas.drawBitmap(bm, matrix, null);

invalidate();
}else{
curAngle=targetAngle;
if(distance < pathLength){
pathMeasure.getPosTan(distance, pos, tan);

targetAngle = (float)(Math.atan2(tan[1], tan[0])*180.0/Math.PI);
matrix.postRotate(curAngle, bm_offsetX, bm_offsetY);

curX = pos[0]-bm_offsetX;
curY = pos[1]-bm_offsetY;
matrix.postTranslate(curX, curY);

canvas.drawBitmap(bm, matrix, null);

distance += step;

invalidate();
}else{
matrix.postRotate(curAngle, bm_offsetX, bm_offsetY);
matrix.postTranslate(curX, curY);
canvas.drawBitmap(bm, matrix, null);
}
}

}

@Override
public boolean onTouchEvent(MotionEvent event) {

int action = event.getAction();

switch(action){
case MotionEvent.ACTION_DOWN:
touchPath.reset();
touchPath.moveTo(event.getX(), event.getY());
break;
case MotionEvent.ACTION_MOVE:
touchPath.lineTo(event.getX(), event.getY());
break;
case MotionEvent.ACTION_UP:
touchPath.lineTo(event.getX(), event.getY());
animPath = new Path(touchPath);

pathMeasure = new PathMeasure(animPath, false);
pathLength = pathMeasure.getLength();

step = 1;
distance = 0;
curX = 0;
curY = 0;

stepAngle = 1;
curAngle = 0;
targetAngle = 0;

invalidate();

break;

}

return true;
}

}

/res/layout/activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.androidanimationalongpath.MainActivity" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >

<com.example.androidanimationalongpath.AnimationView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:background="@android:color/darker_gray" />

<com.example.androidanimationalongpath.AnimationView
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:background="@android:color/darker_gray" />
</LinearLayout>

</LinearLayout>

No change on MainActivity.java, refer HERE.


download filesDownload the files.

More example of Drawing Path on canvas of custom View.


الاثنين، 19 مايو 2014

Detect touch and draw circle on Android WebView with Javascript

Last exercise show a simple WebView with touch detection on Android WebView, it's modify to draw circle when user touch and move on HTML canvas.


Modify /assets/mypage.html from last exercise.
<!DOCTYPE HTML>
<HTML>
<HEAD>
<script>

var p1;
var p2;
var canvas;
var context;
var cx;
var cy;
var x;
var y;
var canvasOffsetX;
var canvasOffsetY;

function init(){
p1 = document.getElementById('p1');
p2 = document.getElementById('p2');
p1.innerHTML=navigator.userAgent;

canvas = document.getElementById('myCanvas');
context = canvas.getContext('2d');
canvasOffsetX = canvas.getBoundingClientRect().left;
canvasOffsetY = canvas.getBoundingClientRect().top;

canvas.width = window.innerWidth - (2 * canvasOffsetX);
canvas.height = window.innerHeight - canvasOffsetY - 100;
canvas.fillStyle="#a0a0a0";

canvas.addEventListener('touchstart', touchstartListener, false);
canvas.addEventListener('touchmove', touchmoveListener, false);
canvas.addEventListener('touchend', touchendListener, false);
canvas.addEventListener('touchenter', touchenterListener, false);
canvas.addEventListener('touchleave', touchleaveListener, false);
canvas.addEventListener('touchcancel', touchcancelListener, false);

}

function touchstartListener(event){
cx = event.changedTouches[0].pageX - canvasOffsetX;
cy = event.changedTouches[0].pageY - canvasOffsetY;
p2.innerHTML= "touchstart - <br/>"
+ cx + ":" + cy;
event.preventDefault();

context.rect(0, 0, canvas.width, canvas.height);
context.fillStyle="white";
context.fill();
}

function touchmoveListener(event){

x = event.changedTouches[0].pageX - canvasOffsetX;
y = event.changedTouches[0].pageY - canvasOffsetY;
var deltax = x-cx;
var deltay = y-cy;
var radius = Math.sqrt(deltax*deltax + deltay*deltay);
context.beginPath();
context.arc(cx, cy, radius, 0, 2 * Math.PI, false);
context.fillStyle = 'green';
context.fill();
context.lineWidth = 1;
context.strokeStyle = '#003300';
context.stroke();

p2.innerHTML= "touchmove - <br/>"
+ x + ":" + y;
event.preventDefault();
}

function touchendListener(event){
p2.innerHTML= "touchend - <br/>"
+ event.changedTouches[0].pageX + ":" + event.changedTouches[0].pageY;
event.preventDefault();
}

function touchenterListener(event){
p2.innerHTML= "touchenter - <br/>"
+ event.changedTouches[0].pageX + ":" + event.changedTouches[0].pageY;
event.preventDefault();
}

function touchleaveListener(event){
p2.innerHTML= "touchleave - <br/>"
+ event.changedTouches[0].pageX + ":" + event.changedTouches[0].pageY;
event.preventDefault();
}

function touchcancelListener(event){
p2.innerHTML= "touchcancel - <br/>"
+ event.changedTouches[0].pageX + ":" + event.changedTouches[0].pageY;
event.preventDefault();
}

</script>
</HEAD>
<BODY onload="init()" style="border:5px solid #000000;">

<p id='p1'>un-init</p>

<canvas id='myCanvas' style="border:1px solid #FF0000;">
Canvas not support!
</canvas>

<p id='p2'></p>

</BODY>
</HTML>

الأحد، 18 مايو 2014

Android WebView, detect touch events with Javascript.

This example show how to create hybrid web-app, using WebView. And detect the touch events with Javascript.


/assets/mypage.html, it will be loaded in our WebView, to perform the main function.
<!DOCTYPE HTML>
<HTML>
<HEAD>
<script>

var p1;
var p2;

function init(){
p1 = document.getElementById('p1');
p2 = document.getElementById('p2');
p1.innerHTML=navigator.userAgent;
var canvas = document.getElementById('myCanvas');
var canvasOffsetX = canvas.getBoundingClientRect().left;
var canvasOffsetY = canvas.getBoundingClientRect().top;

canvas.width = window.innerWidth - (2 * canvasOffsetX);
canvas.height = window.innerHeight - canvasOffsetY - 100;
canvas.fillStyle="#a0a0a0";

canvas.addEventListener('touchstart', touchstartListener, false);
canvas.addEventListener('touchmove', touchmoveListener, false);
canvas.addEventListener('touchend', touchendListener, false);
canvas.addEventListener('touchenter', touchenterListener, false);
canvas.addEventListener('touchleave', touchleaveListener, false);
canvas.addEventListener('touchcancel', touchcancelListener, false);

}

function touchstartListener(event){
p2.innerHTML= "touchstart - <br/>"
+ event.changedTouches[0].pageX + ":" + event.changedTouches[0].pageY;
event.preventDefault();
}

function touchmoveListener(event){
p2.innerHTML= "touchmove - <br/>"
+ event.changedTouches[0].pageX + ":" + event.changedTouches[0].pageY;
event.preventDefault();
}

function touchendListener(event){
p2.innerHTML= "touchend - <br/>"
+ event.changedTouches[0].pageX + ":" + event.changedTouches[0].pageY;
event.preventDefault();
}

function touchenterListener(event){
p2.innerHTML= "touchenter - <br/>"
+ event.changedTouches[0].pageX + ":" + event.changedTouches[0].pageY;
event.preventDefault();
}

function touchleaveListener(event){
p2.innerHTML= "touchleave - <br/>"
+ event.changedTouches[0].pageX + ":" + event.changedTouches[0].pageY;
event.preventDefault();
}

function touchcancelListener(event){
p2.innerHTML= "touchcancel - <br/>"
+ event.changedTouches[0].pageX + ":" + event.changedTouches[0].pageY;
event.preventDefault();
}

</script>
</HEAD>
<BODY onload="init()" style="border:5px solid #000000;">

<p id='p1'>un-init</p>

<canvas id='myCanvas' style="border:1px solid #FF0000;">
Canvas not support!
</canvas>

<p id='p2'></p>

</BODY>
</HTML>

/res/layout/activity_main.xml, with <WebView>.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:orientation="vertical"
android:background="@android:color/background_dark"
tools:context="com.example.androidhybridwebview.MainActivity" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />

<WebView
android:id="@+id/mybrowser"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>

</LinearLayout>

package com.example.androidhybridwebview;

import android.app.Activity;
import android.os.Bundle;
import android.webkit.WebView;

public class MainActivity extends Activity {

WebView myBrowser;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

myBrowser = (WebView) findViewById(R.id.mybrowser);
myBrowser.getSettings().setJavaScriptEnabled(true);
myBrowser.loadUrl("file:///android_asset/mypage.html");
}

}

Next:
- Detect touch and draw circle on Android WebView with Javascript

الجمعة، 16 مايو 2014

Get touch pressure

MotionEvent provide getPressure() and getPressure(int pointerIndex) to get the touch pressure.

Example:

MyView.java
package com.example.androiddrawinview;

import java.util.ArrayList;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class MyView extends View {

private ArrayList<xy> drawList;
private boolean touching = false;

Paint paintTouchPointer_ONE;
Paint paintTouchPointer;

public MyView(Context context) {
super(context);
init();
}

public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(
MeasureSpec.getSize(widthMeasureSpec),
MeasureSpec.getSize(heightMeasureSpec));
}

private void init(){
paintTouchPointer = new Paint();
paintTouchPointer.setColor(Color.RED);
paintTouchPointer.setStyle(Paint.Style.FILL);

paintTouchPointer_ONE = new Paint();
paintTouchPointer_ONE.setColor(Color.BLUE);
paintTouchPointer_ONE.setStyle(Paint.Style.STROKE);
}

@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.GRAY);
if(touching){
for(xy pt : drawList){

float PRESSURE_ONE_RADIUS = 50;
float radius = pt.getPressure() * PRESSURE_ONE_RADIUS;

canvas.drawCircle(
pt.getX(),
pt.getY(),
radius,
paintTouchPointer);

canvas.drawCircle(
pt.getX(),
pt.getY(),
PRESSURE_ONE_RADIUS,
paintTouchPointer_ONE);
}
}
}

@Override
public boolean onTouchEvent(MotionEvent event) {

int action = event.getAction() & MotionEvent.ACTION_MASK;
switch(action){
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_DOWN:

ArrayList<xy> touchList = new ArrayList<xy>();
int pointerCount = event.getPointerCount();

for(int i=0; i < pointerCount; i++){
touchList.add(
new xy(
event.getX(i),
event.getY(i),
event.getPressure(i)));
}
drawList = touchList;
touching = true;
break;
default:
touching = false;
}

invalidate();
return true;
}

class xy{
float x;
float y;
float pressure;

public xy(float x, float y, float pressure){
this.x = x;
this.y = y;
this.pressure = pressure;
}

public float getX(){
return x;
}

public float getY(){
return y;
}

public float getPressure(){
return pressure;
}
}

}

/res/layout/fragment_main.xml, to include MyView in layout.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.androiddrawinview.MainActivity$PlaceholderFragment" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />

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

<com.example.androiddrawinview.MyView
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_margin="10dp" />
</LinearLayout>

</LinearLayout>

MainActivity.java, actually it is the default generated by Eclipse.
package com.example.androiddrawinview;

import android.support.v7.app.ActionBarActivity;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;

public class MainActivity extends ActionBarActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}

/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {

public PlaceholderFragment() {
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
return rootView;
}
}

}

/res/layout/activity_main.xml, auto generated by Eclipse.
<FrameLayout 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.androiddrawinview.MainActivity"
tools:ignore="MergeRootFrame" />

download filesDownload the files.

الثلاثاء، 13 مايو 2014

Cannot detect MotionEvent.ACTION_MOVE and ACTION_UP

Refer to former exercises, "Detect single touch on custom View to draw icon on canvas" and "Detect multi touch on custom View to draw icons on canvas"; true is return from onTouchEvent() method of the custom view, indicate that the event was handled.

If false is returned from onTouchEvent() method, indicate that your code will not handle the events, and the system will not pass you the subsequent events such as MotionEvent.ACTION_MOVE and MotionEvent.ACTION_UP.

This example show two custome View, MyView on left side and MyView2 on right side. MyView handle user touch and display icon in onTouchEvent() method and return true. MyView2 do the same job by extending MyView, but return false in onTouchEvent() method. It can be noticed that MyView2 on right side can detect MotionEvent.ACTION_DOWN only, not MotionEvent.ACTION_MOVE and MotionEvent.ACTION_UP.


Modify from last the exercise "Detect multi touch on custom View to draw icons on canvas", create MyView2.java extends MyView, override onTouchEvent() to return false.

package com.example.androiddrawinview;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;

public class MyView2 extends MyView {

public MyView2(Context context) {
super(context);
// TODO Auto-generated constructor stub
}

public MyView2(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}

public MyView2(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// TODO Auto-generated constructor stub
}

@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
return false;
}

}

Modify /res/layout/fragment_main.xml to replace the MyView on right hand side to MyView2.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.androiddrawinview.MainActivity$PlaceholderFragment" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />

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

<com.example.androiddrawinview.MyView
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_margin="10dp" />
<com.example.androiddrawinview.MyView2
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_margin="10dp" />
</LinearLayout>

</LinearLayout>


download filesDownload the files.

الجمعة، 9 مايو 2014

Detect multi touch on custom View to draw icons on canvas

Last exercise show how to "Detect single touch on custom View to draw icon on canvas". It is now modified to detect multi touch, to display multi icons.


MyView.java
package com.example.androiddrawinview;

import java.util.ArrayList;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class MyView extends View {

private ArrayList<xy> drawList;
private float offsetX, offsetY;
private boolean touching = false;
private Bitmap bm;

public MyView(Context context) {
super(context);
init();
}

public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(
MeasureSpec.getSize(widthMeasureSpec),
MeasureSpec.getSize(heightMeasureSpec));
}

private void init(){
bm = BitmapFactory.decodeResource(
getResources(),
R.drawable.ic_launcher);
offsetX = bm.getWidth()/2;
offsetY = bm.getHeight()/2;
}

@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.GRAY);
if(touching){
for(xy pt : drawList){
canvas.drawBitmap(bm,
pt.getX()-offsetX,
pt.getY()-offsetY,
null);
}
}
}

@Override
public boolean onTouchEvent(MotionEvent event) {

int action = event.getAction() & MotionEvent.ACTION_MASK;
switch(action){
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_DOWN:

ArrayList<xy> touchList = new ArrayList<xy>();
int pointerCount = event.getPointerCount();

for(int i=0; i < pointerCount; i++){
touchList.add(
new xy(
event.getX(i),
event.getY(i)));
}
drawList = touchList;
touching = true;
break;
default:
touching = false;
}

invalidate();
return true;
}

class xy{
float x;
float y;

public xy(float x, float y){
this.x = x;
this.y = y;
}

public float getX(){
return x;
}

public float getY(){
return y;
}
}

}

/res/layout/fragment_main.xml, MainActivity.java and /res/layout/activity_main.xml, refer to last exercise.

download filesDownload the files.

Related:
- Cannot detect MotionEvent.ACTION_MOVE and ACTION_UP

الخميس، 8 مايو 2014

Detect single touch on custom View to draw icon on canvas

This example implement custom View, override onTouchEvent() and onDraw() to draw bitmap on canvas when user touch. In this implementation, only one touch point is detected.


Our custom View, MyView.java
package com.example.androiddrawinview;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class MyView extends View {

private float x, y;
private float offsetX, offsetY;
private boolean touching = false;
private Bitmap bm;

public MyView(Context context) {
super(context);
init();
}

public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}

public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}

private void init(){
bm = BitmapFactory.decodeResource(
getResources(),
R.drawable.ic_launcher);
offsetX = bm.getWidth()/2;
offsetY = bm.getHeight()/2;
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(
MeasureSpec.getSize(widthMeasureSpec),
MeasureSpec.getSize(heightMeasureSpec));
}


@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.GRAY);
if(touching){
canvas.drawBitmap(bm, x-offsetX, y-offsetY, null);
}
}

@Override
public boolean onTouchEvent(MotionEvent event) {
int action = event.getAction();

switch(action){
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_DOWN:
x = event.getX();
y = event.getY();
touching = true;
break;
default:
touching = false;
}
invalidate();

return true;
}

}

Modify /res/layout/fragment_main.xml to add <com.example.androiddrawinview.MyView>.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.androiddrawinview.MainActivity$PlaceholderFragment" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />

<com.example.androiddrawinview.MyView
android:layout_width="fill_parent"
android:layout_height="fill_parent" />

</LinearLayout>

Keep using the auto generated MainActivity.java and /res/layout/activity_main.xml.

MainActivity.java
package com.example.androiddrawinview;

import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.os.Build;

public class MainActivity extends ActionBarActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}

/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {

public PlaceholderFragment() {
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
return rootView;
}
}

}

/res/layout/activity_main.xml
<FrameLayout 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.androiddrawinview.MainActivity"
tools:ignore="MergeRootFrame" />


download filesDownload the files.

Multi single touch View

Modify /res/layout/fragment_main.xml to have two <com.example.androiddrawinview.MyView>.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.androiddrawinview.MainActivity$PlaceholderFragment" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:autoLink="web"
android:text="http://android-er.blogspot.com/"
android:textStyle="bold" />

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

<com.example.androiddrawinview.MyView
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_margin="10dp" />
<com.example.androiddrawinview.MyView
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_margin="10dp" />
</LinearLayout>

</LinearLayout>

Now we have two single touch view together.


Next:
- Detect multi touch on custom View to draw icons on canvas
- Cannot detect MotionEvent.ACTION_MOVE and ACTION_UP