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.

No comments:

Post a Comment

Infolinks In Text Ads