ऑनमोर () को ओवरराइड करने का आधिकारिक तरीका?


88

ऑनमार्ट () को ओवरराइड करने का सही तरीका क्या है? मैंने विभिन्न दृष्टिकोण देखे हैं। उदाहरण के लिए, पेशेवर एंड्रॉइड डेवलपमेंट आयामों की गणना करने के लिए मीजस्पीक का उपयोग करता है, फिर सेटमेशर्डडिमेंशन () में कॉल के साथ समाप्त होता है। उदाहरण के लिए:

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
this.setMeasuredDimension(parentWidth/2, parentHeight);
}

दूसरी ओर, इस पोस्ट के अनुसार , "सही" तरीका है मापक का उपयोग, कॉल सेटमैस्डडिमेंशन्स (), इसके बाद सेटलेयूटपराम () को कॉल करें, और सुपरऑनमर्ज़ () को कॉल के साथ समाप्त करें। उदाहरण के लिए:

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
this.setMeasuredDimension(parentWidth/2, parentHeight);
this.setLayoutParams(new *ParentLayoutType*.LayoutParams(parentWidth/2,parentHeight));
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

तो सही तरीका कौन सा है? न तो दृष्टिकोण ने मेरे लिए 100% काम किया है।

मुझे वास्तव में लगता है कि मैं जो पूछ रहा हूं, क्या वह किसी ट्यूटोरियल के बारे में जानता है जो ऑनमर्न्स (), लेआउट, बच्चे के विचारों के आयाम आदि के बारे में बताता है?


15
क्या आपको उत्तर उपयोगी / सही लगा? इसे उत्तर के रूप में चिह्नित क्यों नहीं किया गया ?
सुपरजोस

जवाबों:


68

अन्य समाधान व्यापक नहीं हैं। वे कुछ मामलों में काम कर सकते हैं, और शुरू करने के लिए एक अच्छी जगह है, लेकिन उन्हें काम करने की गारंटी नहीं है।

जब onMeasure कहा जाता है तो आपको आकार बदलने के अधिकार हो सकते हैं या नहीं भी हो सकते हैं। मूल्यों है कि आपके onMeasure को पास किया जाता ( widthMeasureSpec, heightMeasureSpec) अपने बच्चे को देखने के लिए क्या करने की अनुमति दी है क्या के बारे में जानकारी होती है। वर्तमान में तीन मूल्य हैं:

  1. MeasureSpec.UNSPECIFIED - आप जितना चाहें उतना बड़ा हो सकता है
  2. MeasureSpec.AT_MOST- जब तक आप चाहते हैं (कल्पना आकार तक), यह parentWidthआपके उदाहरण में है।
  3. MeasureSpec.EXACTLY- कोई विकल्प नहीं। माता-पिता ने चुना है।

ऐसा इसलिए किया जाता है ताकि एंड्रॉइड प्रत्येक आइटम के लिए सही आकार खोजने के लिए कई पास बना सके, अधिक जानकारी के लिए यहां देखें।

यदि आप इन नियमों का पालन नहीं करते हैं, तो आपका दृष्टिकोण काम करने की गारंटी नहीं है।

उदाहरण के लिए यदि आप जांचना चाहते हैं कि क्या आपको आकार बदलने की अनुमति है तो आप निम्न कार्य कर सकते हैं:

final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
boolean resizeWidth = widthSpecMode != MeasureSpec.EXACTLY;
boolean resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;

इस जानकारी का उपयोग करके आप जान पाएंगे कि आप अपने कोड में मानों को संशोधित कर सकते हैं या नहीं। या अगर आपको कुछ अलग करने की आवश्यकता है। अपने इच्छित आकार को हल करने का एक त्वरित और आसान तरीका निम्नलिखित तरीकों में से एक का उपयोग करना है:

int resolutionSndAndState (इंट साइज़, इंट मी नापसंद, इंट चाइल्डमैश्चरस्टेट)

int resolutionSize (इंट आकार, इंट मी नापसंद)

जबकि पहला केवल हनीकॉम्ब पर उपलब्ध है, दूसरा सभी संस्करणों पर उपलब्ध है।

नोट: आपको लग सकता है कि resizeWidthया resizeHeightहमेशा झूठे हैं। अगर मैं अनुरोध कर रहा था तो मुझे यह मामला लगा MATCH_PARENT। मैं WRAP_CONTENTअपने माता-पिता के लेआउट पर अनुरोध करके इसे ठीक करने में सक्षम था और फिर UNSPECIFIED चरण के दौरान आकार का अनुरोध करता था Integer.MAX_VALUE। ऐसा करने से आपको अपने माता-पिता को अगले आकार पर अधिकतम पास की अनुमति मिलती है।


39

प्रलेखन इस मामले पर अधिकार है: http://developer.android.com/guide/topics/ui/how-android-draws.html और http://developer.android.com/guide/topics/ui/custom -components.html

संक्षेप में: अपनी ओवरराइड onMeasureविधि के अंत में आपको कॉल करना चाहिए setMeasuredDimension

आपको कॉल करने के super.onMeasureबाद कॉल नहीं करना चाहिए setMeasuredDimension, जो आपके द्वारा सेट किए गए को मिटा देगा। कुछ स्थितियों में आप super.onMeasureपहले कॉल करना चाहते हैं और फिर कॉल करके परिणाम संशोधित कर सकते हैं setMeasuredDimension

setLayoutParamsमें कॉल न करें onMeasure। मापने के बाद लेआउट एक दूसरे पास में होता है।


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

2

मुझे लगता है कि यह उस अभिभावक पर निर्भर करता है जिसे आप ओवरराइड कर रहे हैं।

उदाहरण के लिए, यदि आप एक ViewGroup (जैसे FrameLayout) का विस्तार कर रहे हैं, जब आपने आकार मापा है, तो आपको नीचे कॉल करना चाहिए

super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
                MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));

क्योंकि आप बाकी काम करने के लिए ViewGroup करना चाहते हैं (बच्चे को देखने के लिए कुछ सामान दें)

यदि आप एक दृश्य (जैसे ImageView) का विस्तार कर रहे हैं, तो आप बस कॉल कर सकते हैं this.setMeasuredDimension(width, height);, क्योंकि मूल वर्ग बस कुछ ऐसा करेगा जैसा आपने आमतौर पर किया है।

एक शब्द में, यदि आप चाहते हैं कि कुछ सुविधाएँ आपके मूल वर्ग को मुफ्त super.onMeasure()मिलें तो आपको कॉल करना चाहिए (पास करें। सामान्य रूप से नापें), आमतौर पर कॉल this.setMeasuredDimension(width, height);पर्याप्त है।


1

यहां बताया गया है कि मैंने इस समस्या को कैसे हल किया:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        ....

        setMeasuredDimension( measuredWidth, measuredHeight );

        widthMeasureSpec = MeasureSpec.makeMeasureSpec( measuredWidth, MeasureSpec.EXACTLY );
        heightMeasureSpec = MeasureSpec.makeMeasureSpec( measuredHeight, MeasureSpec.EXACTLY);

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

}

इसके अलावा यह ViewPager घटक के लिए आवश्यक था


3
यह उचित समाधान नहीं है। super.onMeasureउपयोग किए गए आयामों को स्पष्ट करेगा setMeasuredDimension
टॉमहॉर्ब

@tomrozb यह नहीं कर रहा है humptydevelopers.com/2013/05/... और आप एंड्रॉयड स्रोतों की जांच कर सकते हैं
युली Reiri

@YuliReiri: सही समाधान!
शायन तबताबाई

0

अगर onMeasureआप की जरूरत के अंदर विचारों का आकार बदलने के लिए setMeasuredDimensionकॉल है। यदि आप बाहर का आकार बदल रहे हैं तो आपको onMeasureकॉल करने की आवश्यकता है setLayoutParams। उदाहरण के लिए, जब पाठ बदला जाता है, तो पाठ दृश्य का आकार बदलना।


आप अभी भी setMinWidth () और setMaxWidth () को कॉल कर सकते हैं और मानक ऑनमार्ट को संभाल सकते हैं। मैंने पाया है कि एक कस्टम व्यू क्लास के अंदर से setLoutoutParams को कॉल न करना बेहतर है। यह वास्तव में चाइल्ड व्यू व्यवहार को ओवरराइड करने के लिए ViewGroups या गतिविधियों के लिए उपयोग किया जाता है।
डोरिन

0

आपके द्वारा उपयोग किए जा रहे नियंत्रण पर निर्भर करता है। प्रलेखन में निर्देश कुछ नियंत्रणों के लिए काम करते हैं (TextView, Button, ...), लेकिन दूसरों के लिए नहीं (LinearLayout, ...)। जिस तरह से मेरे लिए बहुत अच्छा काम किया गया था कि मैं एक बार सुपर को कॉल करूं। नीचे दिए गए लिंक में लेख के आधार पर।

http://humptydevelopers.blogspot.in/2013/05/android-view-overriding-onmeasure.html


-1

मुझे लगता है, setLayoutParams और माप की पुन: गणना करना बच्चे के विचारों को सही ढंग से आकार देने के लिए एक समाधान है, क्योंकि यह आमतौर पर व्युत्पन्न वर्ग की ऑनमर्स में किया जाता है।

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


-5

आप इस कोड को onMeasure () के उदाहरण के रूप में ले सकते हैं ::

public class MyLayerLayout extends RelativeLayout {

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
        int parentHeight = MeasureSpec.getSize(heightMeasureSpec);

        int currentChildCount = getChildCount();
        for (int i = 0; i < currentChildCount; i++) {
            View currentChild = getChildAt(i);

            //code to find information

            int widthPercent = currentChildInfo.getWidth();
            int heightPercent = currentChildInfo.getHeight();

//considering we will pass height & width as percentage

            int myWidth = (int) Math.round(parentWidth * (widthPercent / 100.0));
            int myHeight = (int) Math.round(parentHeight * (heightPercent / 100.0));

//Considering we need to set horizontal & vertical position of the view in parent

            AlignmentTraitValue vAlign = currentChildInfo.getVerticalLocation() != null ? currentChildlayerInfo.getVerticalLocation() : currentChildAlignmentTraitValue.TOP;
            AlignmentTraitValue hAlign = currentChildInfo.getHorizontalLocation() != null ? currentChildlayerInfo.getHorizontalLocation() : currentChildAlignmentTraitValue.LEFT;
            int topPadding = 0;
            int leftPadding = 0;

            if (vAlign.equals(currentChildAlignmentTraitValue.CENTER)) {
                topPadding = (parentHeight - myHeight) / 2;
            } else if (vAlign.equals(currentChildAlignmentTraitValue.BOTTOM)) {
                topPadding = parentHeight - myHeight;
            }

            if (hAlign.equals(currentChildAlignmentTraitValue.CENTER)) {
                leftPadding = (parentWidth - myWidth) / 2;
            } else if (hAlign.equals(currentChildAlignmentTraitValue.RIGHT)) {
                leftPadding = parentWidth - myWidth;
            }
            LayoutParams myLayoutParams = new LayoutParams(myWidth, myHeight);
            currentChildLayoutParams.setMargins(leftPadding, topPadding, 0, 0);
            currentChild.setLayoutParams(myLayoutParams);
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

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