बहु-ढाल आकार


177

मैं एक आकृति बनाना चाहता हूँ जो निम्न छवि की तरह है:

वैकल्पिक शब्द

कलर 1 से कलर 2 तक के टॉप हाफ ग्रेडिएंट को नोटिस करें, लेकिन एक बॉटम हाफ को रंग 3 से कलर में ढालते हैं। 4. मुझे पता है कि सिंगल ग्रेडिएंट के साथ शेप कैसे बनाते हैं, लेकिन मुझे यकीन नहीं है कि शेप को कैसे विभाजित किया जाए दो हिस्सों और 2 अलग-अलग ग्रेडिएंट के साथ 1 आकार बनाते हैं।

कोई विचार?


यह भी देखें stackoverflow.com/a/26270218/185022
AZ_

जवाबों:


383

मुझे नहीं लगता कि आप एक्सएमएल में ऐसा कर सकते हैं (कम से कम एंड्रॉइड में नहीं), लेकिन मैंने यहां एक अच्छा समाधान पोस्ट किया है जो दिखता है कि यह एक बड़ी मदद होगी!

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);

मूल रूप से, इंट सरणी आपको कई रंग स्टॉप का चयन करने की अनुमति देता है, और निम्न फ्लोट एरे परिभाषित करता है कि उन स्टॉप्स को कहां से रखा गया है (0 से 1 तक)। आप तब, जैसा कि कहा जा सकता है, बस इसे एक मानक ड्राएबल के रूप में उपयोग करें।

संपादित करें: यहां बताया गया है कि आप अपने परिदृश्य में इसका उपयोग कैसे कर सकते हैं। मान लें कि आपके पास 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 में काम करता है, लेकिन यह जावा में आकार के लिए भी उपयुक्त होना चाहिए। यह जटिल है, और मुझे लगता है कि इसे एक एकल आकार में सरल बनाने का एक तरीका है, लेकिन यह वही है जो मैंने अभी के लिए प्राप्त किया है:

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>

ठीक है, इसलिए मूल रूप से मैंने क्षैतिज हरे रंग की ढाल के लिए एक्सएमएल में एक आकार ढाल बनाया है, 0 डिग्री के कोण पर सेट करें, शीर्ष क्षेत्र के बाएं हरे रंग से, सही हरे रंग के लिए जा रहा है। अगला, मैंने आधा पारदर्शी ग्रे के साथ एक आकार का आयत बनाया। मुझे पूरा यकीन है कि इस अतिरिक्त फ़ाइल को देखते हुए, लेयर-लिस्ट XML में इनबिल्ट किया जा सकता है, लेकिन मुझे यकीन नहीं है कि कैसे। लेकिन ठीक है, तो लेयर_लिस्ट एक्सएमएल फ़ाइल में हैकी हिस्सा आता है। मैंने नीचे की परत के रूप में हरे रंग की ढाल लगाई, फिर दूसरी परत के रूप में आधा ओवरले डाला, ऊपर से 50dp से ऑफसेट। जाहिर है कि आप चाहते हैं कि यह संख्या हमेशा आपके दृश्य आकार का आधा हो, हालांकि, और निश्चित 50dp नहीं है। मुझे नहीं लगता कि आप प्रतिशत का उपयोग कर सकते हैं, हालांकि। वहाँ से, मैंने सिर्फ अपने test.xml लेआउट में एक TextView सम्मिलित किया, मेरी पृष्ठभूमि के रूप में layer_list.xml फ़ाइल का उपयोग किया।

वैकल्पिक शब्द

टाडा!

एक और संपादित करें : मैंने महसूस किया है कि आप केवल आइटम के रूप में ड्रा करने योग्य परत सूची में आकृतियों को एम्बेड कर सकते हैं, जिसका अर्थ है कि आपको 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>

आप इस तरह से जितने चाहें उतने आइटम लेयर कर सकते हैं! मैं आसपास खेलने और यह देखने की कोशिश कर सकता हूं कि क्या मुझे जावा के माध्यम से अधिक बहुमुखी परिणाम मिल सकता है।

मुझे लगता है कि यह अंतिम संपादन है ... : ठीक है, तो आप निश्चित रूप से जावा के माध्यम से स्थिति को ठीक कर सकते हैं, निम्न की तरह:

    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 को माप नहीं सकते। मुझे अभी तक यकीन नहीं है कि आप इसे कैसे पूरा कर सकते हैं ... लेकिन मैन्युअल रूप से टॉपइनसेट के लिए एक नंबर डालने से काम होता है।

मैंने झूठ बोला, एक और संपादन

ठीक है, पता चला कि कंटेनर की ऊंचाई से मिलान करने के लिए इस परत को मैन्युअल रूप से कैसे अपडेट किया जाए, पूर्ण विवरण यहां पाया जा सकता है । यह कोड आपके ऑनक्रिएट () विधि में जाना चाहिए:

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);
            }
        });

और मैं कर रहा हूँ! वाह! :)


इसके साथ समस्या यह है कि ग्रेडिएंट वर्टिकल है। मुझे आकार को लंबवत रूप से अलग करने की आवश्यकता है (यानी: एक क्षैतिज रेखा), लेकिन मुझे ढाल के क्षैतिज होने की आवश्यकता है (यानी: बाएं से दाएं)। इस उदाहरण के साथ, विभाजक और ढाल दोनों लंबवत हैं।
एंड्रयू

ओह ठीक है, मुझे वही मिलेगा जो आप अभी कह रहे हैं। (छवियां काम पर अवरुद्ध हैं, इसलिए मैं केवल अपने फोन से आपको देख सकता हूं, विवरणों को अच्छी तरह से बताना मुश्किल है)। दुर्भाग्य से मेरे पास उस अपराध का कोई हल नहीं है, हालांकि मैं मानूंगा कि आप दो आयतों के साथ एक आकर्षक आकार बना सकते हैं, एक क्षैतिज ढाल के साथ, एक सफेद-से-काली ऊर्ध्वाधर ढाल के साथ आधे आकार में आधा अपारदर्शिता पर, नीचे से संरेखित करें। जहाँ तक यह करने के लिए कि मेरे पास फिलहाल कोई विशिष्ट उदाहरण नहीं है।
केविन कोपॉक

हाँ, यही मैं करने में सक्षम होने की उम्मीद कर रहा था, लेकिन मैंने अभी तक इसका पता नहीं लगाया है। मैं आपकी मदद की सराहना करता हूं
एंड्रयू

आपका स्वागत है! मैंने इसे एक और कोशिश दी है, और मुझे लगता है कि मुझे बहुत मिल गया है जो आप ढूंढ रहे हैं। आपको जावा (टिप्पणियों के अनुसार) के माध्यम से गतिशील रूप से बनाना पड़ सकता है, लेकिन यह अभी निश्चित आकार के लिए चाल करता है।
केविन कोप्पॉक

17
इस तरह का उत्तर आप कम से कम +10 देना चाहते हैं। मुझे आपके उत्तर में लड़ाई की भावना पसंद है: आप बनाम Android एपीआई, कौन जीतेगा? क्या हम कभी जान पाएंगे? ;) इसके अलावा, यह सुपर उपयोगी सीखने की सामग्री है क्योंकि आपने अपने सामने आने वाली सभी quirks को बरकरार रखा है।
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

क्या आपने ग्रीन ग्रेडिएंट के लिए एक अपारदर्शी अपारदर्शिता के साथ किसी अन्य छवि के शीर्ष पर लगभग पारदर्शी पारदर्शिता के साथ एक ढाल को ओवरले करने की कोशिश की है?


नहीं, मैंने नहीं किया है, हालांकि मुझे यकीन नहीं है कि एक आकार में दूसरे पर एक ढाल कैसे रखा जाए। मैं एंड्रॉइड का उपयोग करके एक रैखिकलेयूट की पृष्ठभूमि के रूप में आकार का उपयोग कर रहा हूं: पृष्ठभूमि = "@ drawable / myshape"
एंड्रयू

क्या दो आकृतियों को एक दूसरे के ऊपर अलग-अलग अपारदर्शी के साथ परत करना संभव है? (मुझे नहीं पता।)
ग्रेग डी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.