AndroidStudio에서는 live template라는 좋은 기능이 있습니다. 단순하게 재사용이 많은 코드에 대해서 매크로 같은 기능이라고 해야 할까요?? 한두단어 쳤을 때 해당 template에 따라서 코드가 작성되는 것입니다. 단적인 예를 들어서 Fragment에서 새로운 instance를 상성하기 위해서는 

이와 같은 코드를 작성한다고 했을 때 키보드를 그래도 수십번??? 의 타이핑이 필요 합니다. 하지만 live template 기능을 이용하면 

이렇게 하면 단 몇번의 타이핑으로 원하는 기본 코드를 작성할 수 있습니다.


그렇다면 File Template기능은.. java나 html..javascript등에서 자주 사용하는 코드들에 대해서 기본 template를 작성해 두고 빠르게 원하는 기본 코드를 작성하도록 해주는 기능 입니다. 기본적으로 Singleton이 되어 있는데 구성을 보면 

이와 같이 되어 있어서 코드 작성할 때 File Template의 Singleton을 선택하게 되면 "NAME"만 입력하면 위와 같은 template에 정의 된 코드들이 만들어지게 됩니다. 


그렇다면 내가 자주 사용하는 코드를 재사용 할 template를 만들어 둔다면 기본적인 코드들의 활용이 높아질 것입니다.


저같은 경우는 Android개발 시 BaseActivity라는 부모 class를 만들고 상속을 통한 하위 구현 Activity를 만들 고 있습니다. 이 부분에서 file template를 통해서 구현의 속도를 향상시키는 방법은.

new -> Edit File TEmplates...를 선택합니다.

그러면 좀전 위에서 본 File and Code Template라는 메뉴를 보실 수 있습니다.


간단하게 

이와같은 template를 만들었다고 한다면.. ${NAME} 에서 이름을 입력 받고, ${LAYOUT_RES_ID} 입력 받는다면 BaseActivity를 상속받은 위 template가 만들어 지게 됩니다. 

위에서 정의한 NAME에는 Child로.. LAYOUT_RES_ID 에서는 activity_child를 입력했습니다.


결과는 

이와 같은 코드가 만들어 집니다.


만약 Adapter나 RecyclerView같은 코드의 template를 만들어 둔다면 더 활용도가 높을 것 입니다.

개발 속도를 빠르게 하는방법은 여러가지가 있겠지만 tool에 대한 이해도를 높이는 것도 좋은 방법이지 않을 까 합니다.


다음에는 이런 template를 group화 시켜서 하나가 아닌 여러개의 파일을 한번에 만드는 방법을 알아볼까 합니다.

자바에서 코드를 작성 시 모델을 만들다 보면 constructor와 기본 getter/setter.. 그리고 상황에 따라서 builder를 만들어 사용해야 합니다.

그런데 이런 일들을 모두 타이핑 하다 보니 보일플레이트 같은 코드들이 많이도 써야 합니다. 코드 제너레이터들이 있어서 편하게 할 수 있긴 하지만 더 편한 방법이 없을까요?

저같은 경우는 lombok을 사용해서 모델 객체들의 불필요한 보일플레이트 코드들을 줄이고 있습니다. annotation방법으로 사용하기 때문에 사용방법도 간단합니다.



1. @Getter / @Setter

기본적으로 멤버필드들에 대한 getter/setter메소드들을 만들어 줍니다.


2. @AllArgsConstructor / @NoArgsConstructor

멤버필드들이 모두 파라미터로 지정된 생성자와 빈 생성자를 만들어 줍니다.


3. @Builder

모델을 빌더 패턴으로 만들어 줍니다.


4. @ToString

toString의 override된 메소드를 만들어 줍니다.


그 외에도 여러 가지가 있지만 lombok features 에서 더 많은 것을 확인할 수 있습니다.



그럼 AndroidStudio에 적용하는 방법을 알아보도록 하죠.


1. 우선 lombok plugin을 설치해야 합니다.

Preference -> Plugins -> Browse Repositories 에서 lombok을 검색하면 Lombok Plugin이 나옵니다. 이걸 설치해 줍니다.


2. gradle에 lombok적용하기.

"""

provided "org.projectlombok:lombok:1.16.8"

"""


3. 트러블슈팅??

 - package javax.annotation does not exist

annotation does not exist...이걸 해결해 주기 위해서 gradle에 annotation을 provide해줍니다.

"""

provided 'org.glassfish:javax.annotation:10.0-b28'

"""


 - cannot find symbol class ConstructorProperties

lombok.config 설정파일을 추가해 줘야 합니다. 프로젝트와 같은 root에 lombok.config파일을 만들고

'''

lombok.anyConstructor.suppressConstructorProperties = true

'''

와 같은 내용을 추가해 줍니다.

자세한 내용은 Configuration system 에서 확인할 수 있습니다.




이와같은 과정 후에 결과를 보게 된다면

AndroidStudio의 structures view를 보게 되면

이와 같은 결과를 볼 수 있습니다.


이제 lombok을 이용해서 코드 다이어트를!!

얼마전 제 블로그의 포스트에서 Dagger2를 이용하는 방법을 간단하게 적어보았습니다.

Android 개발에서 Dagger2이용해보기.

그런데 여기서 @Scope에 대한 설명이 없었던 것 같습니다.

@Scope ... 실질적으로는 Dagger2에서는 @Singleton annotation을 많이 사용합니다. Singleton은 굳이 자세히 설명을 안해도 다들 잘 알고 계시리라 봅니다. 객체 주입에서 @Singleton annotation을 적용해 두면.. 전체 App의 Scope안에서 Singleton객체가 생성되어 주입 됩니다. 그렇다면 다른 custom scope는 없을까요? 물론 @Scope annotation의 custom을 만들어서 사용합니다. 예를 들어서 Activity life cycle에서만 존재할 수 있는 객체 주입을 위해선 @PerActivity라던지 아니면 fragment life cycle에서만 객체 주입이 유지될 수 잇는 @PerFragment같은 custome scope annotation을 만들어 사용할 수 있습니다.



http://fernandocejas.com/wp-content/uploads/2015/04/composed_dagger_graph1.png


그럼 @Scope 를 이용한 예를 들어 볼 까 합니다.

이전에 예를 들었던 포스트인

Fragment에서 onActivityResult 결과 받기.

의 내용을 Dagger2를 이용한 방법으로 변경할려고 합니다. 주된 내용은 기존의 내용에서 EventBus객체를 Singleton pattern으로 생성해서 사용했습니다. 그럼 Dagger2를 이용해서 해당 샘플을 변경하면 어떻게 될까요?

우선 EventBus.java 입니다.

public class EventBus extends Bus {
private Handler handler = new Handler(Looper.getMainLooper());
@Override
public void post(final Object event) {
if (Looper.myLooper() == Looper.getMainLooper()) {
super.post(event);
} else {
handler.post(new Runnable() {
@Override
public void run() {
EventBus.super.post(event);
}
});
}
}
}

보시는 것과 같이 일반 객체와 별 다를 게 없습니다.


그럼 EventBusModule.java 입니다.

@Module
public class EventBusModule {
@Singleton
@Provides
EventBus provideEventBus() {
return new EventBus();
}
}

해당 모듈에서 EventBus를 제공해줄 때 @Singleton annotation이 붙었습니다. 이건 해당 객체를 Singleton으로 제공해 준다는 겁니다.


그리고 EventBusModule의 객체를 Inject를 하기 위한 Bridge역활을 해주는 ApplicationComponent.java 입니다.

@Singleton
@Component(
modules = {
ApplicationModule.class,
EventBusModule.class
}
)
public interface ApplicationComponent {
EventBus getEventBus();
}

해당 Component도 @Singletone으로 적용해두었습니다.


해당 Component자체도 Singleton scope에서 사용하겠다는 내용 입니다.


만약 Activity life cycle에서만 사용할 수 있는 scope를 만든다면

@Scope
@Retention(RUNTIME)
public @interface PerActivity {
}

로 만든다면 원하는 scope에다가 @PerActivity annotation을 적용하면 됩니다.


예제는..

https://github.com/drcarter/RetriveActivityResult 에서 retrive_activity_result_dagger 브랜치를 보시면 됩니다.

https://github.com/drcarter/RetriveActivityResult/tree/retrive_activity_result_dagger

개발을 여러 사람과 같이 하게 되면 각자만의 코드 스타일이 다르기 때문에 코딩 컨벤션은 어느정도 필요하다는 것을 알 수 있습니다. 그렇다고 누구 한명의 기준에 맞출 수도 없는 거죠.

안드로이드 개발자 사이트에 가면 자세히도 코딩 가이드라인이 존재합니다. 사실 개발하다보면 잘 안지키긴 하죠

Code Style Guidelines for Contributors

그럼 이 가이드라인을 지킬 수 있는 설정파일도 존재합니다.

https://github.com/android/platform_development/blob/master/ide/intellij/codestyles/AndroidStyle.xml

그럼 이 설정파일을 적용하는 방법입니다.


1. https://github.com/android/platform_development/blob/master/ide/intellij/codestyles/AndroidStyle.xml에 있는 파일을 다운로드 한다.


2. codestyle에 복사하기.

 - MacOS : ~/Library/Preferences/AndroidStudio{version}/codestyles/AndroidStyle.xml

 - Linux : ~/.AndroidStudio{version}/config/codestyles/AndroidStyle.xml

 - Windows : C:\Users\XXX\.AndroidStudio{version}\config\codestyles\AndroidStyle.xml


3. Preferences (or Settings) -> Editor -> Code Style -> Scheme 



이렇게 하면 코드 스타일이 미리 적용 됩니다.



안드로이드 개발하는 개발 패턴으로는 MVC( Model - View, Controller)와, MVVM(Model - View, ViewModel), 그리고 MVP(Model - View - Presenter)방법이 있습니다. 이 세가지 방법에는 각자만의 스타일과 장단점을 가지고 있구요. 안드로이드 개발자들이 많이 늘어나고 좀더 편한 개발 방법들을 추가하면서 나오는 방법들이지 않을 까 합니다.

1. MVC ( Model - View - Controller )

 - Model : 안드로이드에서 사용될 데이터들.

 -  View : activity_main.xml 과 같은 view layout

 - Controller : Activity, Fragment 들...

알게 모르게 가장 많이 사용된 패턴이지 않을 까 생각됩니다. 그런데 View와 Controller의 coupling이 너무 강합니다. 누구 하나 땔래야 땔 수 없는 구조이죠. 우리가 알고 있는 좋은 구조는 loose coupling이 많아야 좋은 구조라고 배웠을 겁니다. 그래서 장기적으로 봤을 대 어떤 구조로 가야 좋을 지 생각해 볼 필요가 있습니다.


2. MVVM ( Model - View - ViewModel )

ViewModel은 Controller와 View의 구조를 통합적으로 가지고 있다고 보시면 될 거 같습니다. ViewModel을 독립적으로 가져갈 수 있지만, 나중에 View가 변경된다면 ViewModel을 한번에 다 변경해야 할 필요도 있어 보입니다. 가끔 Git에서 안드로이드 ui 라이브러리나 componet를 보면 mvvm으로 구현된 것들이 많았던 것으로 기억됩니다. 이 방법이 그나마 View에 대한 가장 독립적인 방법이지 않았을 까 생각됩니다. 


3. MVP ( Model - View - Presenter )

전체적인 패턴이 MVC와 비슷합니다. Controller가 Presenter로 보시면 될 듯 하지만 틀린 점이라면 View에 대한 관리와 접근은 Activity에서 하고, Model에 대한 컨트롤러 역활은 Presenter에서 하게 됩니다. 


이 세 방법에 대한 생각은 제 주관적인 생각입니다. MVC, MVVM, MVP 뭐 하나 나쁘다 좋다 할 방법은 없다고 생각 됩니다.  각자만의 장단점이 있고 누가 어떻게 사용하느냐 그리고 어떤 프로젝트 인지에 따라서도 많이 틀려질 것으로 보입니다. 저는 최근에 프로젝트를 MVP방법으로 진행했습니다. MVP를 사용하면서 경험을 해봤을 대 각각 구조에 대해서 loose coupling적인 방법으로 구현을 할 수 있었지만, 너무 독립적으로 진행하다보니 해당 interface에 대한 구현이 많아지는 것을 느낄 수 있었습니다. 다른 프로젝트를 진행한다면 다시 MVP방법을 사용해 볼려고는 합니다. 단지 저는 MVC, MVVM방법보다는 그래도 가장 느슨한 결합도를 가졌다고 보여집니다.

공부하면서 만든 샘플은 git에 올려 둡니다. 그냥 참고 자료에요.

https://github.com/drcarter/AndroidDevPattern

Dagger2

url : http://google.github.io/dagger/

요즘 안드로이드 개발에서 Dependency Injection방법을 이용한 개발 방법이 이슈로 자리잡고 있는 듯 합니다. 더군다나 네임드 개발자로 알려진 Jake Wharton 형님이 발표한 자료도 있습니다.

https://speakerdeck.com/jakewharton/dependency-injection-with-dagger-2-devoxx-2014

2라는 숫자가 있는 것을 보면 Dagger1이 있다는 얘기가 됩니다. 처음 Dagger는 Square에서 나왔습니다. 

http://square.github.io/dagger/

이 사이트에 가시면 자세한 설명을 보실 수 있어요. 나중에 Dagger에 대한 샘플을 작성해 볼 생각입니다.


Dagger2를 얘기한 이유는 프로젝트가 google github에 있다는 것 때문입니다. 믿고 써보는 google??이라서?


Dagger2에서 중요한 Annotation은  @Module, @Provides, @Component, @Inject 정도 일 것 같습니다.

@Module : Module로 구성되고, 내부에서 주입될 객체들을 provide해주는 것.

@Provides : 객체 주입에 필요한 내용을 리턴해주는것

@Component : Module과 Inject간의 Bridge같은 역활.

@Inject : 객체의 주입.

대충 이런정도의 설명... 저는 참 설명을 못하네요 ㅡ.ㅡ


Dagger2를 이용하기 위한 전반적인 순서 입니다.

gradle 스크립트에 아래와 같은 내용을 추가 해 줍니다.

apply plugin: 'com.neenbedankt.android-apt'

buildscript {
    repositories {
        mavenCentral()
    }

    dependencies {
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
    }
}

android {
    ........

    dependencies {
        .......
        provided 'javax.annotation:jsr250-api:1.0'
        apt 'com.google.dagger:dagger-compiler:2.0'
        compile 'com.google.dagger:dagger:2.0'
    }
}


그리고 사용할 모델들을 정의 해 줍니다. 저는 아래와 같은 예제를 만들어 보았습니다.

Motor.java

public class Motor {

    private int speed;

    public Motor() {
        this.speed = 0;
    }

    public int getSpeed() {
        return speed;
    }

    public void accelerate(int value) {
        speed = speed + value;
    }

    public void setSpeed(int value) {
        speed = value;
    }

    public void brake() {
        speed = 0;
    }
}


Bike.java

public class Bike {

    private Motor motor;

    public Bike(@NonNull Motor motor) {
        this.motor = motor;
    }

    public void increaseSpped() {
        this.motor.setSpeed(this.motor.getSpeed() + 1);
    }

    public void decreaseSpeed() {
        if (this.motor.getSpeed() > 0) {
            this.motor.setSpeed(this.motor.getSpeed() - 1);
        }
    }

    public int getSpeed() {
        return this.motor.getSpeed();
    }
}


그리고 Module을 정의 합니다.

우선 MotorModule.java 입니다. 이건 단순히 Motor객체를  제공해 주는 역활만 합니다.

@Module
public class MotorModule {

    @Provides
    Motor provideMotor() {
        return new Motor();
    }
}


BikeModule.java입니다.

@Module(
        includes = MotorModule.class
)
public class BikeModule {

    @Provides
    Bike provideBike(Motor motor) {
        return new Bike(motor);
    }
}


여기서 보면 Bike객체를 제공해주는 @Provides을 보면 Motor객체가 파라미터로 존재합니다. 과연 이 파라미터는 어디서 제공받고 있을까 라는 의문이 듭니다. 이건 @Module의 includes부분에 보면 MotorModule.class를 포함하고 있고, MotorModule에서 Motor객체를 provides하고 있기에 가능합니다.

이렇게 되면 BikeModule안에서 Motor객체를 필요로 하는 곳에서는 모두 파라미터로 정의하면 Motor객체를 제공받을 수 있습니다.

그리고 Provides된 것을 Inject 하여 사용할 수 있는데 Bike객체를 Inject하여 사용해 볼까 합니다.

그럼 Bike는 어디에서 사용할 까요? 위에서 중요 Annotation중에 @Component를 알려드렸습니다. Module과 Inject간의 Brige같은 역활을 한다고 했는데 사용할 Component는 아래와 같습니다.

MainActivityComponent.java

@Component(
        ...
        modules = {
                ...
                BikeModule.class
        }
)
public interface MainActivityComponent extends ActivityComponent {
    void inject(@NonNull MainActivity mainActivity);
}


이와 같이 Component를 정의했습니다.

이렇게 Component를 정의하고 컴파일 하면 "DaggerMainActivityComponent가" 만들어 집니다. 이걸 가지고 실질적으로 객체 주입을 진행할 수 있죠.

DaggerMainActivityComponent.builder()
        ...
        .bikeModule(new BikeModule())
        .build();


이와 같이 하면 사용할 Component에 대해서는 준비가 끝납니다. 그럼 객체 주입은 어떻게 할까요?  몇가지 방법이 있지만 저는 객체에 @Inject anootation방법을 이용해서 사용 할려고 준비했습니다.


@Inject
Bike bike;

이와 같이 하여 Bike객체 사용에 대한 준비를 합니다.

이건 component에서 inejct라는 메소드를 정의해서 상용할 수 있는 부분입니다 그럼  inject라는 것을 하지 않고 사용할 방법은 있을까요? Component에서 getBike()라는 메소드를 만들어서 사용할 방법도 있긴 합니다.

이 예제에 대한 소스는

https://github.com/drcarter/Dagger2Example

에 올려둿습니다..

저도 Dagger2에 대해서 공부하고 정리하다 보니 설명이 명확하진 않은 듯 합니다.

오히려 맨 위에 Jake Wharton형님이 pt로 설명한 내용이 더 좋을지도요 ㅎㅎㅎ


안드로이드에서 onActivityResult는 이전 activity에서의 결과를 intent를 통해서 받을 수 있습니다. 개발문서 참고

당연히 Fragment안에서도 onActivityResult가 있고, fragment안에서 startActivityForResult를 통해서 해당 결과를 받을 수 있습니다.


/**
     * Call {@link Activity#startActivityForResult(Intent, int)} from the fragment's
     * containing Activity.
     */
    public void startActivityForResult(Intent intent, int requestCode) {
        if (mHost == null) {
            throw new IllegalStateException("Fragment " + this + " not attached to Activity");
        }
        mHost.onStartActivityFromFragment(this /*fragment*/, intent, requestCode);
    }

이와 같이 fragment에서 startActivityForResult를 하기 위해선 fragment가 activity에 attach되어 있어야 합니다.

fragment에서 startActivityForResult를 Activity에서 보낸 것처럼 할려면

getActivity().startActivityForResult(.......)

로 해서 보내면 됩니다. 이렇게 해서 보내면 onActivityResult로 받게 되는 결과가 fragment에서 바로 받는 것이 아니라 activity에 있는 onActivityResult에서 받게 되어서 이 결과를 바로 fragment에 전달해 줘야 하죠.... 이 부분이 조금 껄끄러운 면이 있습니다. Lollipop에서 material design을 적용하여 Activity Transition이나 Fragment Transition을 적용할려면, onStartActivityForResult의 호출지점이 fragment가 아닌 activity에서 하는 것처럼 보내야 합니다.

그럼 Activity의 onActivityResult로 받은 결과를 어떻게 fragment에 전달하는 것이 좋을까요?

여러가지 방법이 있을 듯 합니다. 가장 쉬운 방법으로는 Activity에서 해당 fragment의 instance를 두고서 전달할 public method를 만들어 전달 할 방법이 있을 것 같습니다. 

제가 이번에 소개해볼 방법은 event bus[Otto - An event bus by Square]를 이용한 방법을 소개해 볼까 합니다. 

ActivityResultEvent.java 로 만든 class 입니다.


public class ActivityResultEvent {

    private int requestCode;
    private int resultCode;
    private Intent data;

    public static ActivityResultEvent create(int requestCode, int resultCode, Intent intent) {
        return new ActivityResultEvent(requestCode, resultCode, intent);
    }

    private ActivityResultEvent(int requestCode, int resultCode, Intent data) {
        this.requestCode = requestCode;
        this.resultCode = resultCode;
        this.data = data;
    }

    public int getRequestCode() {
        return requestCode;
    }

    public int getResultCode() {
        return resultCode;
    }

    public Intent getData() {
        return data;
    }
}

이건 단순히 onActivityResult로 받는 requestCode, resultCode, intent정보를 가지고 fragment에 전달해 주는 용도 입니다.

EventBus.java


public class EventBus extends Bus {

    private static EventBus instance;

    public static EventBus getInstance() {
        if (instance == null) {
            synchronized (EventBus.class) {
                if (instance == null) {
                    instance = new EventBus();
                }
            }
        }
        return instance;
    }

    private Handler handler = new Handler(Looper.getMainLooper());

    @Override
    public void post(final Object event) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            super.post(event);
        } else {
            handler.post(new Runnable() {
                @Override
                public void run() {
                    EventBus.super.post(event);
                }
            });
        }
    }
}

이건 ActivityResultEvent를 보내줄 Bus입니다.. 이 Bus의 이용 방법은 위에 링크 걸린 홈페이지에 자세히 설명 되어 있어요 

해당 EventBus를 Singleton으로 만들었습니다. 


이 부분의 사용 방법은

activity의 onActivityResult에서


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//        super.onActivityResult(requestCode, resultCode, data);
        EventBus.getInstance().post(ActivityResultEvent.create(requestCode, resultCode, data));
    }

이와 같이 호출하면 되고,

fragment에서는 

    @SuppressWarnings("unused")
    @Subscribe
    public void onActivityResultEvent(@NonNull ActivityResultEvent event) {
        onActivityResult(event.getRequestCode(), event.getResultCode(), event.getData());
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
//        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode) {
            case Constants.RequestCode.REQUEST_CODE_NAME_INPUT: {
                if (resultCode == Activity.RESULT_OK) {
                    String text = data.getStringExtra(KeySets.KEY_NAME_INPUT);
                    if (!TextUtils.isEmpty(text)) {
                        textResult.setText(text);
                    }
                }
                break;
            }
        }
    }

이와 같이 Bus를 통해 받은 정보를 fragment의 onActivityResult로 전달하면 됩니다.

Bus를 통해서 정보 공유는 이요할 곳이 참 많아 보입니다. Service에서 activity나 fragment에 결과의 내용을 전달 할 때 사용해도 되구요.

결과를 만들어 내는 방법에는 여러 방법이 있지만, 사용하는건 개발자의 선택인 듯 합니다. 방법에는 정답이 없으니까요.

source : https://github.com/drcarter/RetriveActivityResult

샘플 소스는 제 git에 올려둡니다.



hexagon이미지를 만드는 방법입니다.

방법은 간단히.. 이미지의 중심점을 잡고, 반지름을 구한 뒤 중심점에서 각 0도, 60도, 120도, 180도, 240도, 360도 위치의 점을 잇는 선을 그은 뒤 그에 해당하는 이미지만 뽑아내느 방법입니다.

이걸 활용하면 android에서 사용할 HexagonImageView도 만들어 볼 수 있겠죠.

코드는 아래와 같습니다.


private Bitmap getHexagonImage(Bitmap toTransform) {
    Bitmap output = Bitmap.createBitmap(toTransform.getWidth(),
            toTransform.getHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(output);

    int radius = 0;
    int width = toTransform.getWidth();
    int height = toTransform.getHeight();
    int centerX = width / 2;
    int centerY = height / 2;

    if (width >= height) {
        radius = height / 2;
    } else {
        radius = width / 2;
    }

    Paint paint = new Paint();
    final Rect rect = new Rect(0, 0, toTransform.getWidth(),
            toTransform.getHeight());

    Path path = new Path();
    for (int i = 0; i < 6; i++) {

        int posX = (int) (centerX + radius * Math.cos(Math.toRadians(i * 60 - 30)));
        int posY = (int) (centerY + radius * Math.sin(Math.toRadians(i * 60 - 30)));
        if (i == 0) {
            path.moveTo(posX, posY);
        } else {
            path.lineTo(posX, posY);
        }
    }

    path.close();
    canvas.drawARGB(0, 0, 0, 0);
    paint.setColor(Color.parseColor("#FFFFFF"));
    canvas.drawPath(path, paint);
    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
    canvas.drawBitmap(toTransform, rect, rect, paint);

    return output;
}


+ Recent posts