May 13, 2014

ComposePathEffect vs SumPathEffect

This example show different effect of ComposePathEffect vs SumPathEffect, on CornerPathEffect and DashPathEffect.


/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.androidview.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="android-coding.blogspot.com" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="CornerPathEffect radius" />

    <SeekBar
        android:id="@+id/radius"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="500"
        android:progress="30" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="DashPathEffect phase" />

    <SeekBar
        android:id="@+id/phase"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="100"
        android:progress="30" />

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

        <ToggleButton
            android:id="@+id/combineffect"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textOff="SumPathEffect"
            android:textOn="ComposePathEffect" />

        <RadioGroup
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" >
            <RadioButton
                android:id="@+id/styleFill"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="FILL"
                android:checked="true" />
            <RadioButton
                android:id="@+id/styleStroke"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="STROKE" />
            <RadioButton
                android:id="@+id/styleFillAndStroke"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="FILL_AND_STROKE" />
        </RadioGroup>
    </LinearLayout>

    <com.example.androidview.MyView
        android:id="@+id/myview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

MyView.java
package com.example.androidview;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ComposePathEffect;
import android.graphics.CornerPathEffect;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.SumPathEffect;
import android.graphics.Path.Direction;
import android.graphics.PathEffect;
import android.util.AttributeSet;
import android.view.View;

public class MyView extends View {

 Paint paintBorder, paintCircle;
 Path pathBorder, pathCircle;
 
 Path pathShape;
 float cornerRadius;
 float dashPhase;
 float[] intervals = {50.0f, 50.0f};
 
 //true: ComposePathEffect
 //false: SumPathEffect
 boolean combinPathEffect; 
 
 Paint.Style style = Paint.Style.FILL;

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

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

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

 private void init() {
  paintBorder = new Paint();
  paintBorder.setColor(Color.BLUE);
  paintBorder.setStrokeWidth(5);
  
  paintCircle = new Paint();
  paintCircle.setColor(Color.RED);
  paintCircle.setStrokeWidth(5);

  pathBorder = new Path();
  pathCircle = new Path();
  
  pathShape = new Path();
  pathShape.moveTo(0, 0);
  pathShape.lineTo(10, 20);
  pathShape.lineTo(20, 0);
  pathShape.close();
  
  cornerRadius = 30.0f;
  dashPhase = 30.0f;
 }

 @SuppressLint("DrawAllocation")
 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  canvas.drawColor(Color.GRAY);

  pathBorder.reset();
  pathBorder.moveTo(50,  50);
  pathBorder.lineTo(50, getHeight()-50);
  pathBorder.lineTo(getWidth()-50, getHeight()-50);
  pathBorder.lineTo(getWidth()-50, 50);
  pathBorder.close();
  
  float radius;
  pathCircle.reset();
  if(getWidth()>getHeight()){
   radius = getHeight()/4;
  }else{
   radius = getWidth()/4;
  }
  pathCircle.addCircle(getWidth()/2, getHeight()/2, radius, Direction.CCW);

  CornerPathEffect cornerPathEffect = new CornerPathEffect(cornerRadius);
  DashPathEffect dashPathEffect = new DashPathEffect(intervals, dashPhase);
  
  PathEffect pathEffect;
  
  if(combinPathEffect){
   pathEffect = new ComposePathEffect(dashPathEffect, cornerPathEffect);
  }else{
   pathEffect = new SumPathEffect(dashPathEffect, cornerPathEffect);
  }
  
  paintBorder.setStyle(style);
  paintCircle.setStyle(style);
  
  paintBorder.setPathEffect(pathEffect);
  paintCircle.setPathEffect(pathEffect);
  
  canvas.drawPath(pathBorder, paintBorder);
  canvas.drawPath(pathCircle, paintCircle);
 }
 
 public void setCornerRadius(float r){
  cornerRadius = r;
  invalidate();
 }
 public void setDashPhase(float p){
  dashPhase = p;
  invalidate();
 }
 
 public void setCombinPathEffect(boolean e){
  combinPathEffect = e;
  invalidate();
 }
 
 public void setStyle(Paint.Style s){
  style = s;
  invalidate();
 }

}

MainActivity.java
package com.example.androidview;

import android.app.Activity;
import android.graphics.Paint;
import android.os.Bundle;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.RadioButton;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.ToggleButton;

public class MainActivity extends Activity {
 
 private MyView myView;
 private SeekBar seekBarRadius, seekBarPhase;
 ToggleButton buttonEffect;
 RadioButton radioFill, radioStroke, radioFillAndStroke;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  myView = (MyView)findViewById(R.id.myview);
  
  seekBarRadius = (SeekBar)findViewById(R.id.radius);
  seekBarRadius.setOnSeekBarChangeListener(seekBarRadiusChangeListener);
  seekBarPhase = (SeekBar)findViewById(R.id.phase);
  seekBarPhase.setOnSeekBarChangeListener(seekBarPhaseChangeListener);
  
  buttonEffect = (ToggleButton)findViewById(R.id.combineffect);
  buttonEffect.setOnCheckedChangeListener(buttonEffectCheckedChangeListener);
  
  radioFill = (RadioButton)findViewById(R.id.styleFill);
  radioStroke = (RadioButton)findViewById(R.id.styleStroke);
  radioFillAndStroke = (RadioButton)findViewById(R.id.styleFillAndStroke);
  radioFill.setOnCheckedChangeListener(radioOnCheckedChangeListener);
  radioStroke.setOnCheckedChangeListener(radioOnCheckedChangeListener);
  radioFillAndStroke.setOnCheckedChangeListener(radioOnCheckedChangeListener);
 }
 
 OnSeekBarChangeListener seekBarRadiusChangeListener =
  new OnSeekBarChangeListener(){

   @Override
   public void onProgressChanged(SeekBar seekBar, int progress,
     boolean fromUser) {
    myView.setCornerRadius(progress);
   }

   @Override
   public void onStartTrackingTouch(SeekBar seekBar) {}

   @Override
   public void onStopTrackingTouch(SeekBar seekBar) {}
  
 };
 
 OnSeekBarChangeListener seekBarPhaseChangeListener =
  new OnSeekBarChangeListener(){

   @Override
   public void onProgressChanged(SeekBar seekBar, int progress,
     boolean fromUser) {
    myView.setDashPhase(progress);
   }

   @Override
   public void onStartTrackingTouch(SeekBar seekBar) {}
    @Override
   public void onStopTrackingTouch(SeekBar seekBar) {}
   
 };
 
 OnCheckedChangeListener buttonEffectCheckedChangeListener =
  new OnCheckedChangeListener(){

   @Override
   public void onCheckedChanged(CompoundButton buttonView,
     boolean isChecked) {
    myView.setCombinPathEffect(isChecked);
   }};
   
 OnCheckedChangeListener radioOnCheckedChangeListener =
  new OnCheckedChangeListener(){

   @Override
   public void onCheckedChanged(CompoundButton buttonView,
     boolean isChecked) {
    if(radioFill.isChecked()){
     myView.setStyle(Paint.Style.FILL);
    }else if(radioStroke.isChecked()){
     myView.setStyle(Paint.Style.STROKE);
    }else{
     myView.setStyle(Paint.Style.FILL_AND_STROKE);
    }
   }
  
 };
 
}


- More examples of drawing path on custom View.

May 11, 2014

Fill path and stroke with different color

Check the demo video. The outter (deviated) rectangle drawn with Paint with style of Paint.Style.FILL_AND_STROKE, both the filled area and stroke have the same color. The inner (deviated) circle drawn in two times; first time drawn with Paint.Style.FILL to fill the inner area, the second time draw with Paint.Style.STROKE to draw the stroke with different color.


package com.example.androidview;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DiscretePathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.util.AttributeSet;
import android.view.View;

public class MyView extends View {

 Paint paintBorder, paintCircle;
 Path pathBorder, pathCircle;
 
 Path pathShape;
 float segmentLength;
 float deviation;

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

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

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

 private void init() {
  paintBorder = new Paint();
  paintBorder.setColor(Color.BLUE);
  paintBorder.setStrokeWidth(20);
  paintBorder.setStyle(Paint.Style.FILL_AND_STROKE);
  
  paintCircle = new Paint();
  paintCircle.setStrokeWidth(20);

  pathBorder = new Path();
  pathCircle = new Path();
  
  pathShape = new Path();
  pathShape.moveTo(0, 0);
  pathShape.lineTo(10, 20);
  pathShape.lineTo(20, 0);
  pathShape.close();
  
  segmentLength = 30.0f;
  deviation = 30.0f;
 }

 @SuppressLint("DrawAllocation")
 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  canvas.drawColor(Color.GRAY);

  pathBorder.reset();
  pathBorder.moveTo(50,  50);
  pathBorder.lineTo(50, getHeight()-50);
  pathBorder.lineTo(getWidth()-50, getHeight()-50);
  pathBorder.lineTo(getWidth()-50, 50);
  pathBorder.close();
  
  float radius;
  pathCircle.reset();
  if(getWidth()>getHeight()){
   radius = getHeight()/4;
  }else{
   radius = getWidth()/4;
  }
  pathCircle.addCircle(getWidth()/2, getHeight()/2, radius, Direction.CCW);

  DiscretePathEffect discretePathEffect =
    new DiscretePathEffect(segmentLength, deviation);
  paintBorder.setPathEffect(discretePathEffect);
  
  canvas.drawPath(pathBorder, paintBorder);
  
  //fill circle with color
  paintCircle.setColor(Color.RED);
  paintCircle.setStyle(Paint.Style.FILL);
  paintCircle.setPathEffect(discretePathEffect);
  canvas.drawPath(pathCircle, paintCircle);
  //draw stroke with different color
  paintCircle.setColor(Color.BLACK);
  paintCircle.setStyle(Paint.Style.STROKE);
  paintCircle.setPathEffect(discretePathEffect);
  canvas.drawPath(pathCircle, paintCircle);
  
 }
 
 public void setDeviation(int dev){
  deviation = (float)dev;
  invalidate();
 }
 
 public void setSegmentLength(int seglen){
  
  //force segmentLength not 0
  if (seglen==0){
   seglen = 1;
  }
   
  segmentLength = (float)seglen;
  invalidate();
 }
 
 public void setStrokeWidth(int strwidth){
  paintBorder.setStrokeWidth(strwidth);
  paintCircle.setStrokeWidth(strwidth);
  invalidate();
 }

}


Other files, /res/layout/activity_main.xml and MainActivity.java, refer to last post DiscretePathEffect example.

- More examples of drawing path on custom View.


May 10, 2014

DiscretePathEffect example

android.graphics.DiscretePathEffect chop the path into lines of segmentLength, randomly deviating from the original path by deviation.


Main layout, /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: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"
    tools:context="com.example.androidview.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="android-coding.blogspot.com" />
    
    <TextView 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="segmentLength"/>
    <SeekBar 
        android:id="@+id/segmentLength"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="100"
        android:progress="30"/>
    
    <TextView 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="deviation"/>
    <SeekBar 
        android:id="@+id/deviation"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="100"
        android:progress="30"/>
    
    <TextView 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="strokeWidth"/>
    <SeekBar 
        android:id="@+id/strokeWidth"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="100"
        android:progress="20"/>
    
    <com.example.androidview.MyView
        android:id="@+id/myview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

MainActivity.java
package com.example.androidview;

import android.app.Activity;
import android.graphics.PathDashPathEffect;
import android.graphics.PathDashPathEffect.Style;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.Spinner;

public class MainActivity extends Activity {
 
 private MyView myView;
 private SeekBar seekBarSegmentLength, seekBarDeviation;
 private SeekBar seekBarStrokeWidth;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  myView = (MyView)findViewById(R.id.myview);
  
  seekBarSegmentLength = (SeekBar)findViewById(R.id.segmentLength);
  seekBarSegmentLength.setOnSeekBarChangeListener(seekBarSegmentLengthChangeListener);
  seekBarDeviation = (SeekBar)findViewById(R.id.deviation);
  seekBarDeviation.setOnSeekBarChangeListener(seekBarDeviationChangeListener);
  
  seekBarStrokeWidth = (SeekBar)findViewById(R.id.strokeWidth);
  seekBarStrokeWidth.setOnSeekBarChangeListener(seekBarStrokeWidthChangeListener);
 }
 
 OnSeekBarChangeListener seekBarSegmentLengthChangeListener =
  new OnSeekBarChangeListener(){

   @Override
   public void onProgressChanged(SeekBar seekBar, int progress,
     boolean fromUser) {
    myView.setSegmentLength(progress);
   }

   @Override
   public void onStartTrackingTouch(SeekBar seekBar) {}

   @Override
   public void onStopTrackingTouch(SeekBar seekBar) {}
  
 };
 
 
 
 OnSeekBarChangeListener seekBarDeviationChangeListener =
  new OnSeekBarChangeListener(){

   @Override
   public void onProgressChanged(SeekBar seekBar, int progress,
     boolean fromUser) {
    myView.setDeviation(progress);
   }

   @Override
   public void onStartTrackingTouch(SeekBar seekBar) {}
    @Override
   public void onStopTrackingTouch(SeekBar seekBar) {}
   
 };
 
 OnSeekBarChangeListener seekBarStrokeWidthChangeListener =
  new OnSeekBarChangeListener(){

   @Override
   public void onProgressChanged(SeekBar seekBar, int progress,
     boolean fromUser) {
    myView.setStrokeWidth(progress);
   }

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

MyView.java
package com.example.androidview;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DiscretePathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.util.AttributeSet;
import android.view.View;

public class MyView extends View {

 Paint paintBorder, paintCircle;
 Path pathBorder, pathCircle;
 
 Path pathShape;
 float segmentLength;
 float deviation;

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

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

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

 private void init() {
  paintBorder = new Paint();
  paintBorder.setColor(Color.BLUE);
  paintBorder.setStrokeWidth(20);
  paintBorder.setStyle(Paint.Style.STROKE);
  
  paintCircle = new Paint();
  paintCircle.setColor(Color.RED);
  paintCircle.setStrokeWidth(20);
  paintCircle.setStyle(Paint.Style.STROKE);

  pathBorder = new Path();
  pathCircle = new Path();
  
  pathShape = new Path();
  pathShape.moveTo(0, 0);
  pathShape.lineTo(10, 20);
  pathShape.lineTo(20, 0);
  pathShape.close();
  
  segmentLength = 30.0f;
  deviation = 30.0f;
 }

 @SuppressLint("DrawAllocation")
 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  canvas.drawColor(Color.GRAY);

  pathBorder.reset();
  pathBorder.moveTo(50,  50);
  pathBorder.lineTo(50, getHeight()-50);
  pathBorder.lineTo(getWidth()-50, getHeight()-50);
  pathBorder.lineTo(getWidth()-50, 50);
  pathBorder.close();
  
  float radius;
  pathCircle.reset();
  if(getWidth()>getHeight()){
   radius = getHeight()/4;
  }else{
   radius = getWidth()/4;
  }
  pathCircle.addCircle(getWidth()/2, getHeight()/2, radius, Direction.CCW);

  DiscretePathEffect discretePathEffect =
    new DiscretePathEffect(segmentLength, deviation);
  paintBorder.setPathEffect(discretePathEffect);
  paintCircle.setPathEffect(discretePathEffect);
  
  canvas.drawPath(pathBorder, paintBorder);
  canvas.drawPath(pathCircle, paintCircle);

 }
 
 public void setDeviation(int dev){
  deviation = (float)dev;
  invalidate();
 }
 
 public void setSegmentLength(int seglen){
  
  //force segmentLength not 0
  if (seglen==0){
   seglen = 1;
  }
   
  segmentLength = (float)seglen;
  invalidate();
 }
 
 public void setStrokeWidth(int strwidth){
  paintBorder.setStrokeWidth(strwidth);
  paintCircle.setStrokeWidth(strwidth);
  invalidate();
 }

}

- More examples of drawing path on custom View.

May 9, 2014

Effect of advance, phase, style in PathDashPathEffect

The example make PathDashPathEffect with interactive setting of advance, phase and style; such that you can know how they affect the result.


Main layout, /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: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"
    tools:context="com.example.androidview.MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="android-coding.blogspot.com" />
    
    <TextView 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="advance"/>
    <SeekBar 
        android:id="@+id/advance"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="100"
        android:progress="30"/>
    
    <TextView 
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="phase"/>
    <SeekBar 
        android:id="@+id/phase"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="100"
        android:progress="30"/>
    <Spinner
        android:id="@+id/style"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    
    <com.example.androidview.MyView
        android:id="@+id/myview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>

MainActivity.java
package com.example.androidview;

import android.app.Activity;
import android.graphics.PathDashPathEffect;
import android.graphics.PathDashPathEffect.Style;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.Spinner;

public class MainActivity extends Activity {
 
 private MyView myView;
 private SeekBar seekBarAdvance, seekBarPhase;
 private Spinner spinnerStyle;
 
 private String[] styleNames ={
  "PathDashPathEffect.Style.MORPH",
  "PathDashPathEffect.Style.ROTATE",
  "PathDashPathEffect.Style.TRANSLATE"};
 private Style[] styleSettings = {
  PathDashPathEffect.Style.MORPH,
  PathDashPathEffect.Style.ROTATE,
  PathDashPathEffect.Style.TRANSLATE};
 
 private ArrayAdapter<String> spinnerStyleAdapter;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  
  myView = (MyView)findViewById(R.id.myview);
  
  seekBarAdvance = (SeekBar)findViewById(R.id.advance);
  seekBarAdvance.setOnSeekBarChangeListener(seekBarAdvanceChangeListener);
  seekBarPhase = (SeekBar)findViewById(R.id.phase);
  seekBarPhase.setOnSeekBarChangeListener(seekBarPhaseChangeListener);
  
  spinnerStyle = (Spinner)findViewById(R.id.style);
  spinnerStyleAdapter = new ArrayAdapter<String>(this, 
   android.R.layout.simple_spinner_item, styleNames);
  spinnerStyleAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
  spinnerStyle.setAdapter(spinnerStyleAdapter);
  spinnerStyle.setOnItemSelectedListener(spinnerStyleOnItemSelectedListener);

 }
 
 OnSeekBarChangeListener seekBarAdvanceChangeListener =
  new OnSeekBarChangeListener(){

   @Override
   public void onProgressChanged(SeekBar seekBar, int progress,
     boolean fromUser) {
    myView.setAdvance(progress);
   }

   @Override
   public void onStartTrackingTouch(SeekBar seekBar) {}

   @Override
   public void onStopTrackingTouch(SeekBar seekBar) {}
  
 };
 
 OnSeekBarChangeListener seekBarPhaseChangeListener =
  new OnSeekBarChangeListener(){

   @Override
   public void onProgressChanged(SeekBar seekBar, int progress,
     boolean fromUser) {
    myView.setPhase(progress);
   }

   @Override
   public void onStartTrackingTouch(SeekBar seekBar) {}
    @Override
   public void onStopTrackingTouch(SeekBar seekBar) {}
  
 };
 
 OnItemSelectedListener spinnerStyleOnItemSelectedListener =
  new OnItemSelectedListener(){

   @Override
   public void onItemSelected(AdapterView<?> parent, View view,
     int position, long id) {
    myView.setStype(styleSettings[position]);
   }

   @Override
   public void onNothingSelected(AdapterView<?> parent) {
    // TODO Auto-generated method stub
    
   }
 };
 
}

MyView.java
package com.example.androidview;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathDashPathEffect;
import android.graphics.Path.Direction;
import android.util.AttributeSet;
import android.view.View;

public class MyView extends View {

 Paint paint;
 Path pathBorder, pathCircle;
 
 Path pathShape;
 float phase;
 float advance;
 PathDashPathEffect.Style style;

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

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

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

 private void init() {
  paint = new Paint();
  paint.setColor(Color.BLUE);
  paint.setStrokeWidth(20);
  paint.setStyle(Paint.Style.STROKE);

  pathBorder = new Path();
  pathCircle = new Path();
  
  pathShape = new Path();
  pathShape.moveTo(0, 0);
  pathShape.lineTo(10, 20);
  pathShape.lineTo(20, 0);
  pathShape.close();
  
  phase = 30.0f;
  advance = 30.0f;
  style = PathDashPathEffect.Style.MORPH;
 }

 @SuppressLint("DrawAllocation")
 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  canvas.drawColor(Color.GRAY);

  pathBorder.reset();
  pathBorder.moveTo(50,  50);
  pathBorder.lineTo(50, getHeight()-50);
  pathBorder.lineTo(getWidth()-50, getHeight()-50);
  pathBorder.lineTo(getWidth()-50, 50);
  pathBorder.close();
  
  float radius;
  pathCircle.reset();
  if(getWidth()>getHeight()){
   radius = getHeight()/4;
  }else{
   radius = getWidth()/4;
  }
  pathCircle.addCircle(getWidth()/2, getHeight()/2, radius, Direction.CCW);

  PathDashPathEffect pathDashPathEffect =
    new PathDashPathEffect(pathShape, advance, phase, style);
  paint.setPathEffect(pathDashPathEffect);
  
  canvas.drawPath(pathCircle, paint);
  canvas.drawPath(pathBorder, paint);

 }
 
 public void setAdvance(int adv){
  advance = (float)adv;
  invalidate();
 }
 
 public void setPhase(int ph){
  phase = (float)ph;
  invalidate();
 }
 
 public void setStype(PathDashPathEffect.Style sty){
  style = sty;
  invalidate();
 }

}


- Running PathDashPathEffect example

- More examples of drawing path on custom View.

May 8, 2014

Running PathDashPathEffect example

This example implement running PathDashPathEffect, by varying phase parameter.


Modify MyView.java from the post.

package com.example.androidview;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.graphics.PathDashPathEffect;
import android.util.AttributeSet;
import android.view.View;

public class MyView extends View {

 Paint paint;
 Path path;
 
 Path pathShape;
 float phase;
 float advance;
 PathDashPathEffect.Style style;

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

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

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

 private void init() {
  paint = new Paint();
  paint.setColor(Color.RED);
  paint.setStrokeWidth(20);
  paint.setStyle(Paint.Style.STROKE);

  path = new Path();
  
  pathShape = new Path();
  pathShape.addCircle(10, 10, 10, Direction.CCW);
  
  phase = 0;
  advance = 30.0f;
  style = PathDashPathEffect.Style.ROTATE;

 }

 @SuppressLint("DrawAllocation")
 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  canvas.drawColor(Color.GRAY);

  path.reset();
  path.moveTo(50,  50);
  path.lineTo(50, getHeight()-50);
  path.lineTo(getWidth()-50, getHeight()-50);
  path.lineTo(getWidth()-50, 50);
  path.close();
  
  phase++;
  PathDashPathEffect pathDashPathEffect =
    new PathDashPathEffect(pathShape, advance, phase, style);
  paint.setPathEffect(pathDashPathEffect);
  
  canvas.drawPath(path, paint);
  
  invalidate();
 }

}


- Effect of advance, phase, style in PathDashPathEffect

- More examples of drawing path on custom View

Infolinks In Text Ads