รูปทรงหลายลาด


177

ฉันต้องการสร้างรูปร่างที่เหมือนภาพต่อไปนี้:

ข้อความแสดงแทน

สังเกตการไล่ระดับสีครึ่งบนจากสี 1 ถึงสี 2 แต่มีครึ่งล่างที่ไล่ระดับสีจากสี 3 เป็นสี 4 ฉันรู้วิธีทำรูปร่างด้วยการไล่ระดับสีเดียว แต่ฉันไม่แน่ใจว่าจะแบ่งรูปร่างออกเป็นอย่างไร แบ่งเป็นสองส่วนและสร้างเป็น 1 รูปร่างโดยมีการไล่ระดับสี 2 แบบ

ความคิดใด ๆ


คำตอบ:


383

ฉันไม่คิดว่าคุณสามารถทำได้ใน XML (อย่างน้อยไม่ได้อยู่ใน Android) แต่ฉันพบวิธีแก้ปัญหาที่ดีที่โพสต์ที่นี่ซึ่งดูเหมือนว่ามันจะช่วยได้มาก!

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 ช่วยให้คุณสามารถเลือกหยุดสีหลายสีและอาร์เรย์ลอยดังต่อไปนี้กำหนดตำแหน่งที่หยุดเหล่านั้น (จาก 0 ถึง 1) จากนั้นคุณสามารถใช้สิ่งนี้เป็น Drawable มาตรฐานได้

แก้ไข: นี่คือวิธีที่คุณสามารถใช้สิ่งนี้ในสถานการณ์ของคุณ สมมติว่าคุณมีปุ่มที่กำหนดไว้ใน XML ดังนี้:

<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 ฉันไม่คิดว่าคุณสามารถใช้เปอร์เซ็นต์ได้ จากนั้นฉันเพิ่งแทรก TextView ลงในเลย์เอาต์ test.xml ของฉันโดยใช้ไฟล์ layer_list.xml เป็นพื้นหลังของฉัน

ข้อความแสดงแทน

Tada!

อีกหนึ่งการแก้ไข : ฉันรู้ว่าคุณสามารถฝังรูปร่างลงในรายการเลเยอร์ที่วาดได้เป็นรายการซึ่งหมายความว่าคุณไม่จำเป็นต้องใช้ไฟล์ XML แยกกันอีก 3 ไฟล์! คุณสามารถได้รับผลลัพธ์เดียวกันโดยรวมสิ่งเหล่านี้:

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 ได้จนกว่าจะถูกดึงออกมา ฉันยังไม่แน่ใจว่าคุณจะทำสิ่งนี้ให้สำเร็จได้อย่างไร ... แต่การแทรกหมายเลขสำหรับ topInset ด้วยตนเองทำงานได้

ฉันโกหกอีกหนึ่งการแก้ไข

เอาล่ะพบวิธีการปรับปรุง drawable ชั้นนี้เพื่อให้ตรงกับความสูงของภาชนะด้วยตนเอง, รายละเอียดเต็มสามารถพบได้ที่นี่ รหัสนี้ควรเป็นไปตามวิธี 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);
            }
        });

และฉันทำเสร็จแล้ว! ต๊าย! :)


ปัญหาของเรื่องนี้คือการไล่ระดับสีเป็นแนวตั้ง ฉันต้องการรูปร่างที่แยกในแนวตั้ง (เช่น: เส้นแนวนอน) แต่ฉันต้องการให้การไล่ระดับสีเป็นแนวนอน (เช่น: เลื่อนจากซ้ายไปขวา) ด้วยตัวอย่างนี้ทั้งตัวคั่นและการไล่ระดับสีจะเป็นแนวตั้ง
แอนดรูว์

โอเคฉันเข้าใจแล้วว่าคุณกำลังพูดอะไรอยู่ตอนนี้ (รูปภาพถูกบล็อกในที่ทำงานดังนั้นฉันสามารถดูได้เฉพาะจากโทรศัพท์ของฉันยากที่จะบอกรายละเอียดได้ดี) น่าเสียดายที่ฉันไม่มีวิธีแก้ปัญหาแบบฉับพลันแม้ว่าฉันจะสมมติว่าคุณสามารถสร้างรูปร่างที่วาดได้ด้วยสี่เหลี่ยมสองรูปอันที่มีการไล่ระดับแนวนอนหนึ่งที่มีการไล่ระดับแนวตั้งสีขาวเป็นสีดำที่ครึ่งขนาดที่ครึ่งทึบ ชิดกับด้านล่าง เท่าที่จะทำได้ฉันยังไม่มีตัวอย่างที่เฉพาะเจาะจงในตอนนี้
Kevin Coppock

ใช่นั่นคือสิ่งที่ฉันหวังว่าจะสามารถทำได้ แต่ฉันก็ยังไม่ได้คิดออก ฉันขอขอบคุณสำหรับความช่วยเหลือของคุณ
Andrew

ยินดีต้อนรับคุณ! ฉันลองอีกครั้งแล้วและฉันคิดว่าฉันมีสิ่งที่คุณต้องการ คุณอาจต้องทำสิ่งเหล่านี้แบบไดนามิกผ่าน Java (ตามความคิดเห็น) แต่นี่จะเป็นการหลอกลวงขนาดที่แน่นอนในขณะนี้
Kevin Coppock

17
นั่นเป็นคำตอบที่คุณต้องการให้อย่างน้อย +10 ฉันชอบความรู้สึกของการต่อสู้ในคำตอบของคุณ: คุณเทียบกับ Android API ใครจะเป็นผู้ชนะ เราจะเคยรู้หรือไม่? ;) นอกจากนี้ยังเป็นสื่อการเรียนรู้ที่มีประโยชน์มากเพราะคุณยังคงรักษานิสัยที่คุณพบ
andr

28

คุณสามารถเลเยอร์รูปร่างไล่ระดับสีใน xml โดยใช้เลเยอร์รายการ ลองจินตนาการถึงปุ่มที่มีสถานะเริ่มต้นด้านล่างซึ่งรายการที่สองนั้นกึ่งโปร่งใส มันเพิ่มประเภทของ vignetting (โปรดแก้ตัวสีที่กำหนดเอง)

<!-- 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

คุณพยายามที่จะซ้อนทับหนึ่งไล่ระดับสีที่มีความทึบเกือบโปร่งใสสำหรับไฮไลต์ที่ด้านบนของภาพอื่นด้วยความทึบแสงทึบแสงสำหรับการไล่ระดับสีเขียวหรือไม่?


ไม่ฉันยังไม่ได้แม้ว่าฉันไม่แน่ใจว่าจะวางไล่ระดับสีหนึ่งไปยังอีกรูปแบบหนึ่งได้อย่างไร ฉันใช้รูปร่างเป็นพื้นหลังของ LinearLayout โดยใช้ android: background = "@ drawable / myshape"
Andrew

เป็นไปได้หรือไม่ที่จะเลเยอร์สองรูปร่างที่มีความแตกต่างของโอเปร่าที่ด้านบนของกันและกัน? (ฉันไม่รู้)
Greg D
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.