2012-09-04 21 views
263

मैंने कस्टम घटक करने की कोशिश की। मैंने View कक्षा बढ़ा दी और onDraw ओवरराइड विधि में कुछ ड्राइंग करें। मुझे onMeasure को ओवरराइड करने की आवश्यकता क्यों है? अगर मैंने नहीं किया, तो सबकुछ सही दिखता था। क्या कोई इसे समझा सकता है? मुझे अपनी onMeasure विधि कैसे लिखनी चाहिए? मैंने कुछ ट्यूटोरियल देखे हैं, लेकिन प्रत्येक एक दूसरे से थोड़ा अलग है। कभी-कभी वे अंत में super.onMeasure पर कॉल करते हैं, कभी-कभी वे setMeasuredDimension का उपयोग करते हैं और इसे कॉल नहीं करते हैं। एक अंतर कहां है?ऑनमी कस्टम व्यू स्पष्टीकरण

आखिरकार मैं बिल्कुल वही घटकों का उपयोग करना चाहता हूं। मैंने उन घटकों को अपने XML फ़ाइल में जोड़ा, लेकिन मुझे नहीं पता कि उन्हें कितना बड़ा होना चाहिए। मैं अपनी स्थिति और आकार बाद में सेट करना चाहता हूं (मुझे onMeasure में आकार सेट करने की आवश्यकता क्यों है यदि onDraw में जब मैं इसे खींचता हूं, तो भी कस्टम घटक वर्ग में) काम कर रहा है। जब मुझे वास्तव में ऐसा करने की ज़रूरत है?

उत्तर

649

onMeasure() एंड्रॉइड को यह बताने का अवसर है कि आप अपने कस्टम व्यू को माता-पिता द्वारा प्रदान की गई लेआउट बाधाओं पर कितना बड़ा होना चाहते हैं; यह जानने के लिए आपके कस्टम व्यू का अवसर भी है कि उन लेआउट की बाधाएं क्या हैं (यदि आप wrap_content स्थिति की तुलना में match_parent स्थिति में अलग-अलग व्यवहार करना चाहते हैं)। इन बाधाओं को विधि में पारित MeasureSpec मानों में पैक किया गया है। यहाँ मोड मूल्यों का एक मोटा संबंध है:

  • बिल्कुल मतलब है layout_width या layout_height मूल्य एक विशिष्ट मान पर सेट किया गया था। आपको शायद इस आकार को अपना आकार बनाना चाहिए। यह तब भी ट्रिगर हो सकता है जब match_parent का उपयोग आकार को बिल्कुल मूल दृश्य में सेट करने के लिए किया जाता है (यह लेआउट ढांचे में निर्भर है)।
  • AT_MOST आम तौर पर layout_width या layout_height मूल्य (इस ढांचे में निर्भर लेआउट है) match_parent या wrap_content जहां अधिकतम आकार की जरूरत है करने के लिए स्थापित किया गया था, और माता पिता के आयाम के आकार मूल्य है मतलब है। आपको इस आकार से बड़ा नहीं होना चाहिए।
  • अनिर्दिष्ट आम तौर पर layout_width या layout_height मूल्य बिना किसी प्रतिबंध के wrap_content लिए सेट किया गया है। आप जो भी आकार चाहते हैं वह हो सकता है। कुछ लेआउट भी आपके इच्छित आकार को जानने के लिए इस कॉलबैक का उपयोग करते हैं, यह निर्धारित करने से पहले कि वास्तव में एक दूसरे उपाय अनुरोध में आपको वास्तव में कौन सा चश्मा पारित किया जाए।

अनुबंध है कि onMeasure() के साथ मौजूद है कि setMeasuredDimension()MUST आकार के साथ अंत में कहा जा आप दृश्य होना चाहते हैं है। इस विधि को सभी ढांचे के कार्यान्वयन द्वारा बुलाया जाता है, जिसमें View में पाया गया डिफ़ॉल्ट कार्यान्वयन शामिल है, इसलिए यह आपके उपयोग के मामले में फिट होने पर super पर कॉल करना सुरक्षित है।

अनुमोदित, क्योंकि ढांचा एक डिफ़ॉल्ट कार्यान्वयन लागू करता है, इसलिए आपके लिए इस विधि को ओवरराइड करना आवश्यक नहीं हो सकता है, लेकिन आप उन मामलों में क्लिपिंग देख सकते हैं जहां दृश्य स्थान आपकी सामग्री से छोटा है यदि आप नहीं करते हैं, और यदि आप दोनों दिशाओं में wrap_content के साथ अपना कस्टम व्यू डालते हैं, आपका दृश्य बिल्कुल दिखाई नहीं दे सकता है क्योंकि ढांचे को यह नहीं पता कि यह कितना बड़ा है!

आम तौर पर, यदि आप View न कि किसी अन्य मौजूदा विजेट अधिभावी कर रहे हैं, यह शायद एक कार्यान्वयन प्रदान करने के लिए एक अच्छा विचार है, भले ही वह कुछ इस तरह के रूप में सरल है:

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

    int desiredWidth = 100; 
    int desiredHeight = 100; 

    int widthMode = MeasureSpec.getMode(widthMeasureSpec); 
    int widthSize = MeasureSpec.getSize(widthMeasureSpec); 
    int heightMode = MeasureSpec.getMode(heightMeasureSpec); 
    int heightSize = MeasureSpec.getSize(heightMeasureSpec); 

    int width; 
    int height; 

    //Measure Width 
    if (widthMode == MeasureSpec.EXACTLY) { 
     //Must be this size 
     width = widthSize; 
    } else if (widthMode == MeasureSpec.AT_MOST) { 
     //Can't be bigger than... 
     width = Math.min(desiredWidth, widthSize); 
    } else { 
     //Be whatever you want 
     width = desiredWidth; 
    } 

    //Measure Height 
    if (heightMode == MeasureSpec.EXACTLY) { 
     //Must be this size 
     height = heightSize; 
    } else if (heightMode == MeasureSpec.AT_MOST) { 
     //Can't be bigger than... 
     height = Math.min(desiredHeight, heightSize); 
    } else { 
     //Be whatever you want 
     height = desiredHeight; 
    } 

    //MUST CALL THIS 
    setMeasuredDimension(width, height); 
} 

आशा है कि मदद करता है।

+1

अरे @ डेवुनवार्ड अच्छा स्पष्टीकरण जो मैंने अभी तक पढ़ा है। आपके स्पष्टीकरण ने मेरे कई प्रश्नों का उत्तर दिया और कुछ संदेहों को मंजूरी दे दी, लेकिन फिर भी एक बनी हुई है: यदि मेरा कस्टम व्यू कुछ अन्य दृश्यों के साथ व्यू ग्रुप के अंदर है (कोई फर्क नहीं पड़ता) कि व्यू ग्रुप अपने सभी बच्चों को एक प्रत्येक लेआउटपैमर्स बाधा के लिए प्रत्येक जांच के लिए और प्रत्येक बच्चे को अपनी बाधाओं के अनुसार स्वयं को मापने के लिए कहें? – pharaoh

+0

हां, माप/लेआउट प्रक्रिया के दौरान 'ViewGroup' की 'मापChildren()' विधि क्या है। – Devunwired

+34

ध्यान दें कि यदि आप किसी भी ViewGroup उपclass के माप पर ओवरराइड करते हैं तो यह कोड नहीं करेगा। आपके सबव्यूव्यू दिखाई नहीं देंगे और सभी के पास 0x0 का आकार होगा। यदि आपको कस्टम व्यू ग्रुप के मापन पर ओवरराइड करने की आवश्यकता है, तो चौड़ाई मोड, चौड़ाई आकार, ऊंचाई मोड और ऊंचाई बदलें, उन्हें मापने के लिए संकलित करें, MeasureSpec.makeMeasureSpec का उपयोग करके स्पीक्स और super.onMeasure के परिणामस्वरूप पूर्णांक पास करें। – Alexey

4

वास्तव में, आपका उत्तर पूरा नहीं हुआ है क्योंकि मान भी रैपिंग कंटेनर पर निर्भर करते हैं। रिश्तेदार या रेखीय लेआउट के मामले में, मूल्यों इस तरह व्यवहार करते हैं:

  • बिल्कुल match_parent बिल्कुल + माता पिता के आकार
  • एक AT_MOST MeasureSpec
  • अनिर्दिष्ट कभी नहीं में AT_MOST wrap_content परिणाम है ट्रिगर

क्षैतिज स्क्रॉल दृश्य के मामले में, आपका कोड काम करेगा।

+49

यदि आपको लगता है कि यहां कुछ जवाब अधूरा है, तो कृपया आंशिक उत्तर देने के बजाय इसमें जोड़ें। –

+0

लेआउट काम करने के तरीके को जोड़ने के लिए अच्छा ओन्या, लेकिन मेरे मामले में मेजर को मेरे कस्टम व्यू के लिए तीन बार कहा जाता है। प्रश्न में दृश्य में एक wrap_content ऊंचाई और भारित चौड़ाई थी (चौड़ाई = 0, वजन = 1)।पहली कॉल ने अप्रतिबंधित/अप्रतिबंधित किया था, दूसरे में AT_MOST/सटीक था और तीसरा वास्तव में/बिल्कुल था। –

संबंधित मुद्दे