Android : 필터로 StateListDrawable을 만들기 위해 드로어 블 복제


91

눌렀을 때 / 초점 / 선택 / 등을 선택 했을 때 Drawable을 강조 표시하는 일반적인 프레임 워크 기능을 만들려고합니다 .

내 함수는 Drawable을 가져 와서 StateListDrawable을 반환합니다. 여기서 기본 상태는 Drawable 자체이고 상태 android.R.attr.state_pressed는 동일한 드로어 블 setColorFilter입니다.

내 문제는 드로어 블을 복제하고 필터를 적용하여 별도의 인스턴스를 만들 수 없다는 것입니다. 내가 달성하려는 것은 다음과 같습니다.

StateListDrawable makeHighlightable(Drawable drawable)
{
    StateListDrawable res = new StateListDrawable();

    Drawable clone = drawable.clone(); // how do I do this??

    clone.setColorFilter(0xFFFF0000, PorterDuff.Mode.MULTIPLY);
    res.addState(new int[] {android.R.attr.state_pressed}, clone);
    res.addState(new int[] { }, drawable);
    return res;
}

복제하지 않으면 필터가 두 상태 모두에 분명히 적용됩니다. 가지고 놀아 봤는데 mutate()도움이 안되네요 ..

어떤 아이디어?

최신 정보:

허용되는 대답은 실제로 드로어 블을 복제합니다. 내 일반 기능이 다른 문제에서 실패하기 때문에 도움이되지 않았습니다. StateList에 드로어 블을 추가하면 모든 필터가 손실되는 것 같습니다.


안녕하세요, 드로어 블이 필터를 잃어 버리는 해결책을 찾았습니까? 동일한 문제가 발생했습니다. (결국 Bitmap을 복제하고 픽셀 단위로 필터를 적용하여 소스 이미지에서 다른 이미지를 생성했습니다. 예, 이것은 비효율적이지만 한 번 처리 된 작은 이미지 만 있습니다.
port443

StateListDrawable로 해결할 수 없었지만 StateListDrawable을 사용하지 않고 여전히 필터가 손실되는 경우 비트 맵이 변경 가능한지 확인하십시오. 좋은 관련 질문이 있습니다 : stackoverflow.com/questions/5499637/… , 또한 LightingColorFilter가 PorterDuff가 실패한 곳에서 작동한다는 것을 발견했습니다 .. lovin this android :)
talkol

이 링크에 대한 훌륭한 답변 stackoverflow.com/questions/10889415/…
Alan

에 의해 유발 된 유사한 부작용이 있는데 ImageView.setImageDrawable, 받아 들여진 답변 덕분에 해결할 수있었습니다.
Giulio Piancastelli

나는 똑같은 일을하려고하는데 어떻게 든 예상대로 작동하지만 ColorFilter가 손실되지 않았습니다. 차이점은 드로어 블을 변경했다는 것입니다.
Henry

답변:


162

다음을 시도하십시오.

Drawable clone = drawable.getConstantState().newDrawable();

1
감사! 이 방법은 드로어 블을 성공적으로 복제하는 것 같습니다. 작성하려고했던 함수가 작동하지 않습니다. 드로어 블이 StateList에 삽입되면 필터가 손실되는 것 같습니다. (
talkol

3
AlertDialog의 ItemizedOverlay에서 Drawable을 재사용하면 트리거 될 때 ItemizedOverlay가 이동하는 MapView의 매우 이상한 오류를 수정하는 데 도움이되었습니다. Drawable의 새 인스턴스를 만들면 문제가 해결되었습니다.
kskjon 2011

9
setAlpha 메소드를 사용하면 올바르게 작동하도록하십시오. 이 경우 두 드로어 블 변경 비트 맵입니다. 그런 다음 첫 번째 드로어 블을 getResources (). getDrawable (), 두 번째로 getResources (). getDrawable (). mutate ()로 얻습니다.
Yura Shinkarev

감사합니다. API Mapsforge에서 경계 기능을 적용 할 때 발생했던 문제를 해결했습니다. 이제 어디서나 드로어 블을 성공적으로 사용할 수 있습니다!
xarlymg89 2013

18
@Flavio-컬러 필터로 시도했지만 드로어 블의 모든 인스턴스에 색상이 지정되었습니다! 당신이 사용해야하는 것처럼 보입니다 .mutate()(내 대답 참조).
Peter Ajtai

106

로 생성 된 드로어 블에 필터 등을 적용하면 getConstantState().newDrawable()드로어 블이을 constantState캐시로 사용하기 때문에 해당 드로어 블의 모든 인스턴스도 변경됩니다 !

따라서 색상 필터와를 사용하여 원을 newDrawable()색칠하면 모든 원의 색상이 변경됩니다.

다른 인스턴스에 영향을주지 않고이 드로어 블을 업데이트 할 수 있도록하려면 기존 상수 상태를 변경해야합니다.

// To make a drawable use a separate constant state
drawable.mutate()

좋은 설명은 다음을 참조하십시오.

http://www.curious-creature.org/2009/05/02/drawable-mutations/

http://developer.android.com/reference/android/graphics/drawable/Drawable.html#mutate ()


사실 mutate ()는 똑같은 인스턴스를 반환하지만 내부 상태가 변경되어 색상 필터를 적용해도 다른 인스턴스에 영향을주지 않습니다. 답변을 검토하고 수정할 수 있습니까?
clemp6r

1
당신 돌연변이에게 색상 변화의 모든 인스턴스를 사용하지 않는 경우 @ clemp6r - 당신은 단지 클론의 색상 변경하기 위해 연변를 호출 할 필요가
피터 Ajtai

2
체크 API의 심판 과 - ( ". 반환이 당김이 당김 변경할 확인") 소스 코드를 ( "이 반환"). mutate () 호출이 필요하지만 반환 된 인스턴스는 동일합니다. 이것은 복제본을 생성하지 않으며, 동일한 드로어 블의 다른 인스턴스에 영향을주지 않고 수정할 수 있도록 드로어 블 인스턴스의 내부 상태 만 변경합니다.
clemp6r 2014 년

그럼 난 문제에 대해 잘 모르겠지만,이 대답은 내가 ... TU 필요한 정확한 것은 않습니다
EVREN Ozturk

1
사람들은 최고의 링크, 당신은 참조 준 것들
쇼크 바르 마

15

이것이 나를 위해 일하는 것입니다.

Drawable clone = drawable.getConstantState().newDrawable().mutate();

예, 왜 그런지 모르겠지만이 조합 newDrawable () 및 mutate () 만 저에게 작동합니다. 다른 단일 mutate () 또는 단일 newDrawable ()이 저에게 제대로 작동하지 않습니다
Michał Ziobro

12

이것은이 SO 질문을 기반으로 한 내 솔루션 입니다.

ImageView사용자가 터치하면 컬러 필터 를 얻고, 터치를 중지하면 컬러 필터가 제거 된다는 아이디어입니다 . 드로어 블 / 비트 맵이 1 개만 메모리에 있으므로 낭비 할 필요가 없습니다. 제대로 작동합니다.

class PressedEffectStateListDrawable extends StateListDrawable {

    private int selectionColor;

    public PressedEffectStateListDrawable(Drawable drawable, int selectionColor) {
        super();
        this.selectionColor = selectionColor;
        addState(new int[] { android.R.attr.state_pressed }, drawable);
        addState(new int[] {}, drawable);
    }

    @Override
    protected boolean onStateChange(int[] states) {
        boolean isStatePressedInArray = false;
        for (int state : states) {
            if (state == android.R.attr.state_pressed) {
                isStatePressedInArray = true;
            }
        }
        if (isStatePressedInArray) {
            super.setColorFilter(selectionColor, PorterDuff.Mode.MULTIPLY);
        } else {
            super.clearColorFilter();
        }
        return super.onStateChange(states);
    }

    @Override
    public boolean isStateful() {
        return true;
    }
}

용법:

Drawable drawable = new FastBitmapDrawable(bm);
imageView.setImageDrawable(new PressedEffectStateListDrawable(drawable, 0xFF33b5e5));

나에게도 작동합니다! 그것은 흥미로운 해결책입니다. 감사합니다!) PS android는
짜증나고,

나는 이것이 (StateListDrawable + BitmapDrawable)에서 버그를 해결하는 가장 좋은 솔루션이라고 생각합니다!
Xavier.S

1

여기서 관련 질문에 답 했습니다.

기본적으로 StateListDrawables가 실제로 필터를 잃어버린 것처럼 보입니다. 원래 사용하고 싶었던 Bitmap의 변경된 복사본에서 새 BitmapDrawale을 만들었습니다.


0
Drawable clone = drawable.mutate().getConstantState().newDrawable().mutate();

getConstantState()반환 하는 경우 null.


0

사용하여 클론 드로어 블을 가져 newDrawable()오지만 변경 가능한지 확인하십시오. 그렇지 않으면 클론 효과가 사라지고 몇 줄의 코드를 사용했으며 예상대로 작동합니다. getConstantState()주석에서 제안한대로 null 일 수 있으므로 드로어 블을 복제하는 동안이 RunTimeException을 처리하십시오.

Drawable.ConstantState state = d.mutate().getConstantState();
if (state != null) {
    Drawable drawable = state.newDrawable().mutate();
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.