डायनामिक लेकिन स्क्वायर लेआउट करने का सरल तरीका


84

मैं GridViewदृश्यों का एक गुच्छा प्रदर्शित करने के लिए उपयोग कर रहा हूं जो अनिवार्य रूप से हैं LinearLayouts। मैं चाहता हूं कि LinearLayoutsसभी चौकोर हों, लेकिन मैं यह भी चाहता हूं कि वे गतिशील रूप से आकार में हों - यानी, दो कॉलम हैं और मैं चाहता हूं कि LinearLayoutsस्क्रीन के आकार के आधार पर खिंचाव हो लेकिन वर्गाकार बने रहें। क्या xmlलेआउट के माध्यम से ऐसा करने का कोई तरीका है या क्या मुझे प्रोग्राम को हाइट और चौड़ाई सेट करना है?

जवाबों:


113

चौकोर GridViewवस्तुओं के लिए एक साफ समाधान यह है कि उसका विस्तार करें RelativeLayoutया उसे LinearLayoutओवरराइड onMeasureकरें:

@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, widthMeasureSpec);
}

2
यह setMeasuredDimension () का उपयोग करने के बजाय माप युक्ति का उपयोग कर रहा है ताकि यह अच्छा हो। लेकिन यह बहुत लचीला नहीं है क्योंकि यह हमेशा चौड़ाई लेता है।
— एडम

3
जैसा कि @DavidMerriman ने ऊपर कहा, यदि दृश्य लंबा है, तो यह लंबा है, यह दृश्य क्षेत्र के नीचे का विस्तार करने का कारण होगा, दृश्य के भाग को काटकर।
— vcapra1

5
यह अधिक लचीला होगा यदि यह Super.onMeasure () के दोनों तर्कों में Math.min (widthMeasureSpec, heightMeasureSpec) का मान पारित कर दे
— पॉल विन्ट्ज़

यह गतिविधियों के साथ आसानी से काम करेगा लेकिन यह ऐप विजेट के साथ काम नहीं करेगा।
— अपोलो-रोबोटो

72

उत्तर देने में देर हो सकती है लेकिन फिर भी, यह नए आगंतुकों के लिए उपयोगी होगा।

एंड्रॉइड स्टूडियो 2.3 में पेश किए गए नए कॉन्ट्राटाइनलआउट के साथ , अब उत्तरदायी लेआउट बनाना काफी आसान है।

माता-पिता कांस्ट्रेनल लयआउट में, अपने किसी भी बच्चे को गतिशील रूप से देखने / लेआउट बनाने के लिए, इस विशेषता को जोड़ें

app:layout_constraintDimensionRatio="w,1:1"

डब्ल्यू चौड़ाई-वार बाधाओं को निर्दिष्ट करने के लिए है और 1: 1 अनुपात वर्ग लेआउट सुनिश्चित करता है।


9
यह एक राजा का जवाब है
— itzhar

2
शीर्ष उत्तर यदि आप एक मौजूदा लेआउट को एक वर्ग के रूप में प्रदर्शित करना चाहते हैं!
— क्वेंटिन क्लेन

9
बाल लेआउट में लेआउट की चौड़ाई और ऊंचाई के लिए "0dp" सेट करना सुनिश्चित करें। अन्यथा यह काम नहीं करेगा।
— थिलिना केजे

यह अपने आप में दृश्य के लिए भी काम करता है, मेरा मतलब है कि यदि आप एक कंट्रालेयूट के बच्चे को चौकोर बनाना चाहते हैं, तो आप सीधे बाल दृश्य में लेआउट_कॉस्ट्रैटिनडिमेंट्री अनुपात अनुपात को परिभाषित कर सकते हैं
— प्लिनियो.संतोस

1
समाधान के लिए बहुत-बहुत धन्यवाद; मैंने बनाया है अगर यह आपके समाधान का उपयोग करके मेरे कोड को पूरा करने में मदद करता है: gist.github.com/nadar71/006699e31ef7451813e6c97dacfbc5e2
— android_dev71

44

Xml में ऐसा कुछ भी नहीं है जो आपको चौड़ाई और ऊंचाई के गुणों को जोड़ने देगा। संभवतः सबसे आसान काम उपवर्ग LinearLayoutऔर ओवरराइड करना हैonMeasure

@Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);
    int size = width > height ? height : width;
    setMeasuredDimension(size, size);
}

मैंने इसका उपयोग उन विचारों को बनाने के लिए किया है जो हमेशा पहले चौकोर होते हैं। यह अभी भी एक के लिए काम करना चाहिए LinearLayout।

अधिक जानकारी जो ऐसा करने में मदद करेगी: http://developer.android.com/guide/topics/ui/custom-compenders.html http://developer.android.com/reference/android/view/View/View.M त्ता Spec.html


हाँ, मैंने कुछ ऐसा ही किया। धन्यवाद!
— कैथरीन

1
यदि यह आपके लिए काम करता है, तो क्या आप इसे सही उत्तर के रूप में चिह्नित कर सकते हैं?
— डेविड मेरिमैन

1
@ कैथरीन हे कैथरीन, क्या आप अपना स्निपेट पोस्ट कर सकते हैं? शायद यह दूसरों के लिए उपयोगी होगा :-)
— मर्क सेबेरा

3
जोड़ने के लिए नहीं भूल गया है: super.onMeasure(widthMeasureSpec, widthMeasureSpec);!
— डेकाजू

1
@deKajoo का उपयोग super.onMeasure(widthMeasureSpec, widthMeasureSpec);आपको एक वर्ग देता है, लेकिन यह हमेशा चौड़ाई x चौड़ाई है। यदि दिए गए माप लंबे हैं, तो वे लम्बे हैं, तो आपको समस्या होने वाली है। मेरा समाधान दो मापों में से छोटे का उपयोग करता है, जिससे आपको हमेशा सबसे बड़ा वर्ग मिलता है जो दिए गए आयत के भीतर फिट होगा।
— डेविड मेरिमैन

43

मैंने इस तरह किया है:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);

    int size;
    if(widthMode == MeasureSpec.EXACTLY && widthSize > 0){
        size = widthSize;
    }
    else if(heightMode == MeasureSpec.EXACTLY && heightSize > 0){
        size = heightSize;
    }
    else{
        size = widthSize < heightSize ? widthSize : heightSize;
    }

    int finalMeasureSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
    super.onMeasure(finalMeasureSpec, finalMeasureSpec);
}

इस कार्यान्वयन के साथ, चौड़ाई और ऊँचाई के बीच निचले आकार को मानते हुए, आपका लेआउट वर्गाकार होगा। और इसे गतिशील मूल्यों के साथ भी सेट किया जा सकता है, जैसे कि एक LinearLayout के अंदर वजन का उपयोग करना।


"OnMeasure" विधि एक वर्ग में दिखाई देती है, जो ग्रिड व्यू का विस्तार करता है?
— 22-14

कक्षा में टीटी का ओवररिडेन आप चाहते हैं कि यह चौकोर हो। प्रश्न के मामले के लिए, यह GridView के अंदर LinearLayouts है।
— फर्नांडो कैमार्गो

इसने मुझे एक चौंका देने वाले मुद्दे का उपयोग करने में मदद की, जिसमें एक चौंका देने वाला मुद्दा है StaggeredGridLayout। मेरा अधिक अनुभवहीन कार्यान्वयन बहुत अच्छा नहीं था। धन्यवाद!
— पीटरकड

10

हम इसे बहुत सरल तरीके से कर सकते हैं - बस super.onMeasure()दो बार कॉल करें ।

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    int width = getMeasuredWidth();
    int height = getMeasuredHeight();
    int squareLen = Math.min(width, height);

    super.onMeasure(
        MeasureSpec.makeMeasureSpec(squareLen, MeasureSpec.EXACTLY), 
        MeasureSpec.makeMeasureSpec(squareLen, MeasureSpec.EXACTLY));
}

super.onMeasure()दो बार कॉल करके , यह ड्राइंग प्रक्रिया के संदर्भ में कम कुशल है, लेकिन यह लेआउट के मुद्दों को ठीक करने का एक सरल तरीका है जो अन्य उत्तरों का कारण बन सकता है।


2
दो बार सुपर.ऑन मर्ज़ को कॉल करने के बजाय, दूसरी बार आपको केवल सेटमशीनरीडिमेशन (स्क्वायरलेन, स्क्वायरलेन) कॉल करने की आवश्यकता है;
— user3802077 18

super.onMeasure()दो बार कॉल करने से यह सुनिश्चित हो जाता है कि लेआउट को सही तरीके से देखने का नया आकार दिया गया है। इसके बिना हमें एक लेआउट को अलग तरीके से ट्रिगर करना होगा या गलत लेआउट से निपटना होगा।
— रिचर्ड ले मेसुरियर

4

यह उतना ही सरल है:

public class SquareRelativeLayout extends RelativeLayout {

    public SquareRelativeLayout(Context context) {
        super(context);
    }

    public SquareRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public SquareRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 
    {
        if (widthMeasureSpec < heightMeasureSpec) 
            super.onMeasure(widthMeasureSpec, widthMeasureSpec);
        else
            super.onMeasure(heightMeasureSpec, heightMeasureSpec);
    }
}

1

यहाँ एक समाधान है जो सभी लेआउट मापदंडों के लिए काम करता है जिसे देखने या देखने के लिए सेट किया जा सकता है:

    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);
    int widthDesc = MeasureSpec.getMode(widthMeasureSpec);
    int heightDesc = MeasureSpec.getMode(heightMeasureSpec);
    int size = 0;
    if (widthDesc == MeasureSpec.UNSPECIFIED
            && heightDesc == MeasureSpec.UNSPECIFIED) {
        size = DP(defaultSize); // Use your own default size, in our case
                                // it's 125dp
    } else if ((widthDesc == MeasureSpec.UNSPECIFIED || heightDesc == MeasureSpec.UNSPECIFIED)
            && !(widthDesc == MeasureSpec.UNSPECIFIED && heightDesc == MeasureSpec.UNSPECIFIED)) {
                    //Only one of the dimensions has been specified so we choose the dimension that has a value (in the case of unspecified, the value assigned is 0)
        size = width > height ? width : height;
    } else {
                    //In all other cases both dimensions have been specified so we choose the smaller of the two
        size = width > height ? height : width;
    }
    setMeasuredDimension(size, size);

चियर्स


इस उत्तर में कुछ दिलचस्प विशेषताएं हैं और यह संभावित रूप से अधिक मजबूत है, लेकिन काम की जरूरत है और माप के चश्मे का निर्माण करना चाहिए, जो सेटअमेरिकाडिमेंसेशन () के बजाय सुपर.ओनमर्ज़ () के लिए पास हो जाते हैं क्योंकि यह विभिन्न प्रकार की सुपर कक्षाओं के लिए अनुमति देगा।
— एडम

1

मेरा सुझाव एक कस्टम लेआउट क्लास बनाना है जो फ्रेमलैट से विरासत में मिला है। OnMeasure () पद्धति को ओवरराइड करें और उस SquareFrameLayout के अंदर जो भी नियंत्रण करना चाहते हैं, उसे डाल दें।

यह कैसे Xamarin में किया गया है।

public class SquareFrameLayout : FrameLayout
{
    private const string _tag = "SquareFrameLayout";

    public SquareFrameLayout(Android.Content.Context context):base(context) {}
    public SquareFrameLayout(IntPtr javaReference, Android.Runtime.JniHandleOwnership transfer):base(javaReference, transfer) {}
    public SquareFrameLayout(Android.Content.Context context, IAttributeSet attrs):base(context, attrs) {}
    public SquareFrameLayout(Android.Content.Context context, IAttributeSet attrs, int defStyleAttr):base(context, attrs, defStyleAttr) {}
    public SquareFrameLayout(Android.Content.Context context, IAttributeSet attrs, int defStyleAttr, int defStyleRes):base(context, attrs, defStyleAttr, defStyleRes) {}

    protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        var widthMode = MeasureSpec.GetMode(widthMeasureSpec);
        int widthSize = MeasureSpec.GetSize(widthMeasureSpec);
        var heightMode = MeasureSpec.GetMode(heightMeasureSpec);
        int heightSize = MeasureSpec.GetSize(heightMeasureSpec);

        int width, height;

        switch (widthMode)
        {
            case MeasureSpecMode.Exactly:
                width = widthSize;
                break;
            case MeasureSpecMode.AtMost:
                width = Math.Min(widthSize, heightSize);
                break;
            default:
                width = 100;
                break;
        }

        switch (heightMode)
        {
            case MeasureSpecMode.Exactly:
                height = heightSize;
                break;
            case MeasureSpecMode.AtMost:
                height = Math.Min(widthSize, heightSize);
                break;
            default:
                height = 100;
                break;
        }

        Log.Debug(_tag, $"OnMeasure({widthMeasureSpec}, {heightMeasureSpec}) => Width mode: {widthMode}, Width: {widthSize}/{width}, Height mode: {heightMode}, Height: {heightSize}/{height}");
        var size = Math.Min(width, height);
        var newMeasureSpec = MeasureSpec.MakeMeasureSpec(size, MeasureSpecMode.Exactly);
        base.OnMeasure(newMeasureSpec, newMeasureSpec);
    }
}

यदि आप एक दृश्य (या किसी अन्य नियंत्रण) को स्क्वायर (और केंद्रित) करना चाहते हैं, तो इसे अपने लेआउट में निम्न तरीके से जोड़ें:

<your.namespace.SquareFrameLayout
    android:id="@+id/squareContainer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center">
    <View
        android:id="@+id/squareContent"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</your.namespace.SquareFrameLayout>

1

XML में निम्न पंक्ति जोड़ें:

app:layout_constraintDimensionRatio="1:1"

1
मैं उसी उत्तर को पोस्ट करना चाहता था क्योंकि यह ऐप से बेहतर है: लेआउट_कॉस्ट्रैंटडिमेंशन अनुपात = "डब्ल्यू, 1: 1" क्योंकि यह हमेशा अनुपात रखता है यदि आप कॉन्फ़िगरेशन बदलते हैं
— एलेक्सी सिमचेंको

0

स्क्वायरलेयआउट , एक एंड्रॉइड लाइब्रेरी की जाँच करें जो विभिन्न लेआउट के लिए एक आवरण वर्ग प्रदान करता है, उन्हें बिना किसी अतिरिक्त कार्यात्मकता को खोए हुए स्क्वर्टेड आयाम प्रदान करता है।

आयाम गणना कर रहे हैं बस से पहले लेआउट प्रदान की गई है , इसलिए वहाँ कोई फिर से प्रतिपादन या इस तरह के रूप में कुछ भी एक बार देखें प्राप्त किया जाता है समायोजित करने के लिए है।

लाइब्रेरी का उपयोग करने के लिए, इसे अपने build.gradle में जोड़ें:

repositories {
    maven {
        url "https://maven.google.com"
    }
}

dependencies {
    compile 'com.github.kaushikthedeveloper:squarelayout:0.0.3'
}

जिसकी आपको आवश्यकता है वह SquareLinearLayout है ।


असली डिवाइस पर मेरे लिए काम नहीं करता है :( Android Studio पूर्वावलोकन पर अच्छी तरह से प्रतिपादन, लेकिन डिवाइस पर काम नहीं कर रहा है
— Eugene Voronoy

0

किसी को भी कोटलिन के साथ समाधान चाहता है, यहाँ मैंने क्या किया FrameLayout।

package your.package.name

import android.content.Context
import android.util.AttributeSet
import android.widget.FrameLayout

class SquareLayout: FrameLayout {

    constructor(ctx: Context) : super(ctx)
    constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        if (widthMeasureSpec < heightMeasureSpec)
            super.onMeasure(widthMeasureSpec, widthMeasureSpec)
        else
            super.onMeasure(heightMeasureSpec, heightMeasureSpec)
    }
}

0

इस कोड को आज़माएं:

public class SquareRelativeLayout extends RelativeLayout {
    public SquareRelativeLayout(Context context) {
        super(context);
    }

    public SquareRelativeLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int size;
        if (widthMode == MeasureSpec.EXACTLY && widthSize > 0) {
            size = widthSize;
        } else if (heightMode == MeasureSpec.EXACTLY && heightSize > 0) {
            size = heightSize;
        } else {
            size = widthSize < heightSize ? widthSize : heightSize;
        }

        int finalMeasureSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
        super.onMeasure(finalMeasureSpec, finalMeasureSpec);
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.