다중 그라데이션 모양


177

다음 이미지와 같은 모양을 만들고 싶습니다.

대체 텍스트

색상 1에서 색상 2 로의 상단 절반 그라디언트를 주목하지만 하단 3에서 색상 3에서 색상 4로 그라디언트하는 하단 절반이 있습니다. 단일 그라디언트로 모양을 만드는 방법을 알고 있지만 모양을 분할하는 방법을 잘 모르겠습니다 두 개의 반쪽과 두 개의 다른 그라디언트로 하나의 모양을 만듭니다.

어떤 아이디어?


답변:


383

나는 당신이 XML (적어도 안드로이드에서는 아님)로 이것을 할 수 있다고 생각하지 않지만, 여기 에 게시 되어 큰 도움이 될만한 좋은 해결책을 찾았습니다 !

ShapeDrawable.ShaderFactory sf = new ShapeDrawable.ShaderFactory() {
    @Override
    public Shader resize(int width, int height) {
        LinearGradient lg = new LinearGradient(0, 0, width, height,
            new int[]{Color.GREEN, Color.GREEN, Color.WHITE, Color.WHITE},
            new float[]{0,0.5f,.55f,1}, Shader.TileMode.REPEAT);
        return lg;
    }
};

PaintDrawable p=new PaintDrawable();
p.setShape(new RectShape());
p.setShaderFactory(sf);

기본적으로 int 배열을 사용하면 여러 색상 정지 점을 선택할 수 있으며 다음 float 배열은 해당 정지 점이 배치되는 위치를 정의합니다 (0에서 1까지). 그런 다음 명시된대로 표준 Drawable로 사용할 수 있습니다.

편집 : 시나리오에서 이것을 사용하는 방법은 다음과 같습니다. XML로 정의 된 Button이 있다고 가정 해 봅시다.

<Button
    android:id="@+id/thebutton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Press Me!"
    />

그런 다음 onCreate () 메소드에 다음과 같은 것을 넣으십시오.

Button theButton = (Button)findViewById(R.id.thebutton);
ShapeDrawable.ShaderFactory sf = new ShapeDrawable.ShaderFactory() {
    @Override
    public Shader resize(int width, int height) {
        LinearGradient lg = new LinearGradient(0, 0, 0, theButton.getHeight(),
            new int[] { 
                Color.LIGHT_GREEN, 
                Color.WHITE, 
                Color.MID_GREEN, 
                Color.DARK_GREEN }, //substitute the correct colors for these
            new float[] {
                0, 0.45f, 0.55f, 1 },
            Shader.TileMode.REPEAT);
         return lg;
    }
};
PaintDrawable p = new PaintDrawable();
p.setShape(new RectShape());
p.setShaderFactory(sf);
theButton.setBackground((Drawable)p);

나는 현재 이것을 테스트 할 수 없다. 이것은 내 머리의 코드이지만 기본적으로 필요한 색상을 대체하거나 정지를 추가한다. 기본적으로 내 예에서는 연한 녹색으로 시작하고 중심보다 약간 전에 흰색으로 희미 해져 (가혹한 전환이 아닌 페이드를 제공하기 위해) 45 %에서 55 % 사이의 흰색에서 중간 녹색으로 페이드 인 중간 녹색에서 진한 녹색으로 55 %에서 끝까지. 이것은 모양과 똑같지 않을 수도 있지만 (지금은이 색상을 테스트 할 방법이 없습니다), 예제를 복제하도록이 값을 수정할 수 있습니다.

편집 : 또한 0, 0, 0, theButton.getHeight()그라디언트의 x0, y0, x1, y1 좌표를 나타냅니다. 따라서 기본적으로 x = 0 (왼쪽), y = 0 (위)에서 시작하여 x = 0으로 확장됩니다 (수직 그라디언트를 원하므로 왼쪽에서 오른쪽 각도가 필요하지 않습니다), y = 높이 버튼의. 따라서 그래디언트는 버튼 상단에서 버튼 하단까지 90도 각도로 진행됩니다.

편집 : 좋아, 그래서 작동하는 아이디어가 하나 더 있습니다. 현재는 XML로 작동하지만 Java의 모양에도 적용 할 수 있어야합니다. 그것은 복잡하고 하나의 모양으로 단순화 할 수있는 방법이 있다고 생각하지만 이것이 내가 지금 얻은 것입니다.

green_horizontal_gradient.xml

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle"
    >
    <corners
        android:radius="3dp"
        />
    <gradient
        android:angle="0"
        android:startColor="#FF63a34a"
        android:endColor="#FF477b36"
        android:type="linear"
        />    
</shape>

half_overlay.xml

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle"
    >
    <solid
        android:color="#40000000"
        />
</shape>

layer_list.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list
    xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <item
        android:drawable="@drawable/green_horizontal_gradient"
        android:id="@+id/green_gradient"
        />
    <item
        android:drawable="@drawable/half_overlay"
        android:id="@+id/half_overlay"
        android:top="50dp"
        />
</layer-list>

test.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center"
    >
    <TextView
        android:id="@+id/image_test"
        android:background="@drawable/layer_list"
        android:layout_width="fill_parent"
        android:layout_height="100dp"
        android:layout_marginLeft="15dp"
        android:layout_marginRight="15dp"
        android:gravity="center"
        android:text="Layer List Drawable!"
        android:textColor="@android:color/white"
        android:textStyle="bold"
        android:textSize="26sp"     
        />
</RelativeLayout>

자, 기본적으로 저는 수평 녹색 그라디언트에 대해 XML로 모양 그라디언트를 만들었습니다. 0도 각도로 설정하여 상단 영역의 왼쪽 녹색에서 오른쪽 녹색으로. 다음으로 반투명 회색 모양의 사각형을 만들었습니다. 레이어 목록 XML에 인라인 되어이 여분의 파일을 제거 할 수 있다고 확신하지만 방법을 잘 모르겠습니다. 그러나 괜찮은 종류의 해키 부분은 layer_list XML 파일에 있습니다. 녹색 그라디언트를 아래쪽 레이어로 넣은 다음 절반 오버레이를 두 번째 레이어로 놓고 위쪽에서 50dp만큼 오프셋합니다. 분명히이 숫자는 항상 고정 크기 50dp가 아닌 뷰 크기의 절반이되기를 원합니다. 그래도 백분율을 사용할 수 있다고 생각하지 않습니다. 여기에서 layer_list.xml 파일을 배경으로 사용하여 test.xml 레이아웃에 TextView를 삽입했습니다.

대체 텍스트

타다!

한 번 더 편집 : 아이템으로 레이어 목록 드로어 블에 도형을 포함시킬 수 있다는 것을 깨달았습니다. 더 이상 3 개의 별도 XML 파일이 필요하지 않습니다! 다음과 같이 조합하여 동일한 결과를 얻을 수 있습니다.

layer_list.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list
    xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <item>
        <shape
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:shape="rectangle"
            >
            <corners
                android:radius="3dp"
                />
            <gradient
                android:angle="0"
                android:startColor="#FF63a34a"
                android:endColor="#FF477b36"
                android:type="linear"
                />    
        </shape>
    </item>
    <item
        android:top="50dp" 
        >
        <shape
            android:shape="rectangle"
            >
            <solid
                android:color="#40000000"
                />
        </shape>            
    </item>
</layer-list>

이 방법으로 원하는만큼 항목을 레이어 할 수 있습니다! 나는 장난을 치며 Java를 통해 더 다양한 결과를 얻을 수 있는지 확인할 수 있습니다.

나는 이것이 마지막 편집이라고 생각합니다 ... : 좋아, 다음과 같이 Java를 통해 위치를 확실히 수정할 수 있습니다.

    TextView tv = (TextView)findViewById(R.id.image_test);
    LayerDrawable ld = (LayerDrawable)tv.getBackground();
    int topInset = tv.getHeight() / 2 ; //does not work!
    ld.setLayerInset(1, 0, topInset, 0, 0);
    tv.setBackgroundDrawable(ld);

하나! 이로 인해 TextView가 그려 질 때까지 TextView를 측정 할 수 없다는 또 다른 성가신 문제가 발생합니다. 아직 어떻게 수행 할 수 있는지 잘 모르겠지만 topInset에 숫자를 수동으로 삽입하면 작동합니다.

거짓말 하나 더 편집

좋아, 컨테이너의 높이에 맞게이 레이어 드로어 블을 수동으로 업데이트하는 방법을 찾았 습니다 . 자세한 설명은 여기를 참조하십시오 . 이 코드는 onCreate () 메소드로 이동해야합니다.

final TextView tv = (TextView)findViewById(R.id.image_test);
        ViewTreeObserver vto = tv.getViewTreeObserver();
        vto.addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                LayerDrawable ld = (LayerDrawable)tv.getBackground();
                ld.setLayerInset(1, 0, tv.getHeight() / 2, 0, 0);
            }
        });

그리고 끝났어요! 아휴! :)


이것의 문제는 그래디언트가 수직이라는 것입니다. 세로로 분리 된 모양이 필요하지만 (예 : 가로선) 그래디언트를 가로로 만들어야합니다 (예 : 왼쪽에서 오른쪽으로 이동). 이 예제에서는 구분자와 그라디언트가 모두 수직입니다.
Andrew

오케이, 지금 네가하는 말을 알아 (직장에서 이미지가 차단되므로 휴대 전화에서만 이미지를 볼 수 있었으므로 세부 정보를 잘 알기 어렵습니다). 불행히도 나는 그 손해에 대한 해결책을 가지고 있지 않지만, 두 개의 직사각형, 수평 그라디언트, 반투명에서 절반 크기의 흰색에서 검은 색 수직 그라디언트로 하나의 그리기 가능한 모양을 만들 수 있다고 가정하지만, 바닥에 맞 춥니 다. 그렇게하는 한 현재로서는 구체적인 예가 없습니다.
Kevin Coppock

그래, 내가 할 수 있기를 바랐지만 아직 이해하지 못했습니다. 도와 주셔서 감사합니다
Andrew

천만에요! 나는 한 번 더 시도해 보았고, 당신이 찾고있는 것을 거의 얻었을 것이라고 생각합니다. 주석에 따라 Java를 통해 동적 으로이 작업을 수행해야 할 수도 있지만 지금은 고정 크기의 트릭을 수행합니다.
Kevin Coppock

17
그것은 적어도 당신이 +10에게주고 싶은 답변입니다. 나는 당신의 대답에서 싸움의 느낌을 좋아합니다 : 당신은 안드로이드 API 대 누가 이길 것입니까? 우리가 알 수 있을까? ;) 또한, 당신이 겪었던 모든 단점을 유지했기 때문에 매우 유용한 학습 자료입니다.
andr

28

레이어 목록을 사용하여 XML에서 그라디언트 모양을 레이어 할 수 있습니다. 두 번째 항목이 반투명 한 기본 상태의 버튼을 상상해보십시오. 그것은 일종의 비네팅을 추가합니다. (사용자 정의 색상을 변명하십시오.)

<!-- Normal state. -->
<item>
    <layer-list>
        <item>  
            <shape>
                <gradient 
                    android:startColor="@color/grey_light"
                    android:endColor="@color/grey_dark"
                    android:type="linear"
                    android:angle="270"
                    android:centerColor="@color/grey_mediumtodark" />
                <stroke
                    android:width="1dp"
                    android:color="@color/grey_dark" />
                <corners
                    android:radius="5dp" />
            </shape>
        </item>
        <item>  
            <shape>
                <gradient 
                    android:startColor="#00666666"
                    android:endColor="#77666666"
                    android:type="radial"
                    android:gradientRadius="200"
                    android:centerColor="#00666666"
                    android:centerX="0.5"
                    android:centerY="0" />
                <stroke
                    android:width="1dp"
                    android:color="@color/grey_dark" />
                <corners
                    android:radius="5dp" />
            </shape>
        </item>
    </layer-list>
</item>


4

xml 모양 만 사용하여 수행 할 수 있습니다. 레이어 목록과 다음과 같이 네거티브 패딩을 사용하십시오.

    <layer-list>

        <item>
            <shape>
                <solid android:color="#ffffff" />

                <padding android:top="20dp" />
            </shape>
        </item>

        <item>
            <shape>
                <gradient android:endColor="#ffffff" android:startColor="#efefef" android:type="linear" android:angle="90" />

                <padding android:top="-20dp" />
            </shape>
        </item>

    </layer-list>

1

이 방법을 사용하면 원하는 모든 것을 할 수 있습니다. 스택
과 같으 므로 어떤 항목이 먼저 또는 마지막에 오게 조심하십시오.

<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android="http://schemas.android.com/apk/res/android">
<item android:right="50dp" android:start="10dp" android:left="10dp">
    <shape
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
        <corners android:radius="3dp" />
        <solid android:color="#012d08"/>
    </shape>
</item>
<item android:top="50dp">
    <shape android:shape="rectangle">
        <solid android:color="#7c4b4b" />
    </shape>
</item>
<item android:top="90dp" android:end="60dp">
    <shape android:shape="rectangle">
        <solid android:color="#e2cc2626" />
    </shape>
</item>
<item android:start="50dp" android:bottom="20dp" android:top="120dp">
    <shape android:shape="rectangle">
        <solid android:color="#360e0e" />
    </shape>
</item>


0

녹색 그라디언트에 대해 불투명 한 불투명도로 다른 이미지 위에 하이라이트를 위해 거의 불투명 한 불투명도로 하나의 그라디언트를 오버레이하려고 했습니까?


아니요, 한 그라디언트를 다른 그라디언트 위에 배치하는 방법을 잘 모르겠습니다. android : background = "@ drawable / myshape"를 사용하여 LinearLayout의 배경으로 모양을 사용하고 있습니다.
Andrew

서로 다른 불투명도로 두 모양을 겹쳐 놓을 수 있습니까? (모름)
Greg D
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.