Android: मैं ViewPager WRAP_CONTENT होने में असमर्थ हूं


258

मेरे पास एक सरल ViewPager सेटअप है जिसमें प्रत्येक पृष्ठ पर 200dp की ऊंचाई के साथ एक ImageView है।

यहाँ मेरा पेजर है:

pager = new ViewPager(this);
pager.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT));
pager.setBackgroundColor(Color.WHITE);
pager.setOnPageChangeListener(listener);
layout.addView(pager);

Wra_content के रूप में सेट की गई ऊँचाई के बावजूद, पेजर हमेशा स्क्रीन को भरता है भले ही इमेजव्यू केवल 200dp हो। मैंने "200" के साथ पेजर की ऊंचाई को बदलने की कोशिश की, लेकिन यह मुझे कई प्रस्तावों के साथ अलग परिणाम देता है। मैं उस मान में "dp" जोड़ने में असमर्थ हूं। मैं पेजर के लेआउट में 200dp कैसे जोड़ूं?


1
कृपया स्टार इश्यू कोड। www.p/android/issues/detail
क्राइस्ट

जवाबों:


408

आपके ViewPagerइस प्रकार के ऑनराइडिंग को ओवरराइड करने से यह वर्तमान में सबसे बड़े बच्चे की ऊंचाई प्राप्त कर लेगा।

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

    int height = 0;
    for(int i = 0; i < getChildCount(); i++) {
        View child = getChildAt(i);
        child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
        int h = child.getMeasuredHeight();
        if(h > height) height = h;
    }

    if (height != 0) {
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
    }

    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

24
यह मेरी जरूरत के सबसे करीब आता है, लेकिन इसमें दो चीजें शामिल हैं: 1. ViewPager केवल अपने वास्तविक बच्चों में से सबसे बड़ा है, अर्थात्, केवल वर्तमान में दिखाई देने वाली वस्तु और सीधे बगल वाले। ViewPager पर setOffscreenPageLimit (बच्चों की कुल संख्या) को कॉल करना इसे हल करता है और एक ViewPager में परिणाम होता है जिसका आकार उसके सभी आइटमों में से सबसे बड़ा पर सेट होता है और कभी भी आकार नहीं बदलता है। 2. WebViews के पास कुछ अजीब मुद्दे हैं जब उन्हें मापने की कोशिश की जा रही है। कुछ हल करने के बाद एक WebView पर RequestLayout () को कॉल करना।
0101100101

3
बस एक छोटी सी समस्या है जिसे मैं ठीक करने जा रहा हूं: अगर व्यूगर को इसकी दृश्यता GONE से मिलती है और आप इसे दृश्यमान पर सेट करते हैं, तो इसके टुकड़े होने से पहले OnMeasure को कॉल किया जाता है। तो यह 0. की ऊंचाई तक समाप्त हो जाएगा। अगर किसी को कोई विचार है, तो उसका स्वागत है। मुझे लगता है कि मैं एक कॉलबैक के साथ जाऊंगा जब टुकड़ा बनाया जाता है
edoardotognoni

4
यह काम नहीं करेगा यदि आपके पास सजावट वाले बच्चे के दृश्य हैं - यह इसलिए है क्योंकि ViewPager.onMeasure () सजावट विचारों को मापता है और पहले उन्हें स्थान आवंटित करता है, फिर गैर-सजावट वाले बच्चों को शेष स्थान देता है। फिर भी, यह अब तक का सबसे कम गलत समाधान है, इसलिए मैंने इसे उखाड़ फेंका है;)
बेंजामिन डोबेल

3
मैं इसे देखने के लिए हर बार आता रहता हूं, जब मैं
ono

7
getChildCount () पहले से ही सेटअप एडाप्टर () ViewPager पर प्रदर्शन करते समय 0 पर वापस आ सकता है! वास्तविक पॉप्युलेट () कॉल (जो विचार बनाता है) सुपर.मॉनमर्ज़ (चौड़ाईमेयरस्पेक, ऊंचाईमेयरस्पेसेक) के अंदर होता है; कहते हैं। इस कार्य के प्रारंभ में अतिरिक्त सुपर.मोनारम () कॉल लगाकर चाल चली। इसके अलावा stackoverflow.com/questions/38492210/…
southerton

106

एक और अधिक सामान्य समाधान wrap_contentसिर्फ काम करने के लिए है।

मैं ViewPagerओवरराइड करने के लिए बढ़ा हूं onMeasure()। ऊंचाई को पहले बच्चे के दृश्य के चारों ओर लपेटा जाता है। यदि बच्चे के विचार समान ऊंचाई नहीं हैं तो यह अप्रत्याशित परिणाम दे सकता है। उसके लिए कक्षा को वर्तमान दृश्य / पृष्ठ के आकार को चेतन करने के लिए आसानी से बढ़ाया जा सकता है। लेकिन मुझे इसकी जरूरत नहीं थी

आप मूल ViewPager की तरह yout XML लेआउट में इस ViewPager का उपयोग कर सकते हैं:

<view
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    class="de.cybergen.ui.layout.WrapContentHeightViewPager"
    android:id="@+id/wrapContentHeightViewPager"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"/>

लाभ: यह दृष्टिकोण किसी भी लेआउट में ViewPager का उपयोग करने की अनुमति देता है जिसमें अन्य ui तत्वों को ओवरले करने के लिए RelativeLayout भी शामिल है।

एक दोष यह है: यदि आप मार्जिन का उपयोग करना चाहते हैं, तो आपको दो नेस्टेड लेआउट बनाने होंगे और आंतरिक को वांछित मार्जिन देना होगा।

यहाँ कोड है:

public class WrapContentHeightViewPager extends ViewPager {

    /**
     * Constructor
     *
     * @param context the context
     */
    public WrapContentHeightViewPager(Context context) {
        super(context);
    }

    /**
     * Constructor
     *
     * @param context the context
     * @param attrs the attribute set
     */
    public WrapContentHeightViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

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

        // find the first child view
        View view = getChildAt(0);
        if (view != null) {
            // measure the first child view with the specified measure spec
            view.measure(widthMeasureSpec, heightMeasureSpec);
        }

        setMeasuredDimension(getMeasuredWidth(), measureHeight(heightMeasureSpec, view));
    }

    /**
     * Determines the height of this view
     *
     * @param measureSpec A measureSpec packed into an int
     * @param view the base view with already measured height
     *
     * @return The height of the view, honoring constraints from measureSpec
     */
    private int measureHeight(int measureSpec, View view) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else {
            // set the height from the base view if available
            if (view != null) {
                result = view.getMeasuredHeight();
            }
            if (specMode == MeasureSpec.AT_MOST) {
                result = Math.min(result, specSize);
            }
        }
        return result;
    }

}

34
जब वर्तमान दृश्य नष्ट हो गया और फिर से खुला तो किसी और को वर्तमान आइटम के पास खाली पृष्ठ मिला?
ज्यू

1
मुझे खाली पेज भी मिले।
21

10
आपको बस इस प्रश्न के दो शीर्ष उत्तरों को मेरे ब्लॉग में वर्णित करने की आवश्यकता है: pristalovpavel.wordpress.com/2014/12/26/…
anil

4
बस 'डैनियल लोपेज़ लैक्ले' द्वारा दिए गए उत्तर के साथ 'ऑनमर्ज़' पद्धति के कोड को बदलें।
योग गुरु

1
महान..! मेरे लिए काम किया .. @cybergen बहुत बहुत धन्यवाद मेरा दिन बचाया ..!
एम

59

मैंने डैनियल लोपेज़ लाकले और इस पोस्ट http://www.henning.ms/2013/09/09/viewpager-that-simply-dont-measure-up/ पर अपना जवाब आधारित किया । डैनियल के जवाब के साथ समस्या यह है कि कुछ मामलों में मेरे बच्चों की ऊंचाई शून्य थी। दुर्भाग्य से उपाय दो बार मापना था।

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int mode = MeasureSpec.getMode(heightMeasureSpec);
    // Unspecified means that the ViewPager is in a ScrollView WRAP_CONTENT.
    // At Most means that the ViewPager is not in a ScrollView WRAP_CONTENT.
    if (mode == MeasureSpec.UNSPECIFIED || mode == MeasureSpec.AT_MOST) {
        // super has to be called in the beginning so the child views can be initialized.
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int height = 0;
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
            int h = child.getMeasuredHeight();
            if (h > height) height = h;
        }
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
    }
    // super has to be called again so the new specs are treated as exact measurements
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

यदि आप ऐसा करना चाहते हैं, तो आप ViewPager पर एक ऊँचाई सेट कर सकते हैं।


मेरे पास एक ही समस्या थी और इसे आपके उत्तर के साथ हल कर दिया, धन्यवाद। लेकिन कोई स्पष्टीकरण क्यों?
बार्ट बर्ग

मुझे लगता है कि वे रैप कंटेंट का समर्थन नहीं करना चाहते थे क्योंकि मुझे नहीं लगता कि उन्हें लगा कि यह एक सामान्य उपयोग का मामला है। इसका समर्थन करने के लिए हमें अपने बच्चों को मापने के बाद अपने आप को फिर से मापना होगा ताकि हम सामग्री लपेट सकें।
मिन्समैन

क्यों इस ViewPager में छवियां उन ImageView की तुलना में कम हैं जो समान scaleTypeऔर समान layout_width=match_parentरूप से और साथ ही उपयोग करता है layout_height=wrap_content? वहाँ 20dp की तरह गायब है।
शार्क

शार्क, मुझे यकीन नहीं है। कि आपके स्केल प्रकार वास्तव में क्या कर रहे हैं के साथ कुछ करने के लिए हो सकता है। ऊँचाई सेट करने का प्रयास करना चाह सकते हैं।
मिंसमैन

1
मैं यह विश्वास नहीं कर सकता हूँ! मैंने अपने कस्टम व्यूपॉगर को एक साथ 2 दिन बिताए और एक समस्या पर फंस गया, जब मेरा प्रारंभिक दृश्य दिखाई नहीं देगा और मैं अभी पता नहीं लगा सका कि क्यों! // super has to be called in the beginning so the child views can be initialized.<----- यह कारण था, इसे शुरुआत में और ऑनमार्ट फ़ंक्शन के अंत में कॉल करना था। Yippiii, आज मुझ पर आभासी उच्च फाइव्स!
Starwave

37

मैं इस बारे में एक बहुत ही समान प्रश्न का उत्तर दे रहा था, और ऐसा तब हुआ जब मुझे अपने दावों का समर्थन करने के लिए एक लिंक की तलाश थी, इसलिए भाग्यशाली था **

मेरा अन्य उत्तर:
व्यूपैगर इसका समर्थन नहीं करता wrap_contentहै (आमतौर पर) इसके सभी बच्चों को कभी भी एक ही समय में लोड नहीं किया जाता है, और इसलिए इसे उचित आकार नहीं मिल सकता है (विकल्प में पेजर होगा जो आपके स्विच किए जाने पर हर बार आकार बदलता है। पृष्ठ)।

हालांकि, आपको तथा एक सही आयाम स्थापित कर सकते हैं (उदाहरण के लिए 150dp) match_parentकाम करता है और साथ ही।
आप अपने कोड से डायनामिक रूप से डायमेंशन को बदलकर इसके height-attribute को बदल सकते हैं LayoutParams

अपनी जरूरतों के लिए आप ViewPager को अपनी स्वयं की xml- फ़ाइल में बना सकते हैं, जिसमें 200_p पर लेआउट_हाइट सेट है, और फिर अपने कोड में, स्क्रैच से एक नया ViewPager बनाने के बजाय, आप उस xml-फ़ाइल को बढ़ा सकते हैं:

LayoutInflater inflater = context.getLayoutInflater();
inflater.inflate(R.layout.viewpagerxml, layout, true);

3
अच्छा जवाब, इस तरह का गुस्सा कि डिफ़ॉल्ट व्यवहार "कुछ हद तक समझ से बाहर है।" स्पष्टीकरण के लिए धन्यवाद।
क्रिस वंदेवल्डे

8
@ChrisVandevelde यह कुछ Android पुस्तकालयों का एक सामान्य किरायेदार लगता है। जैसे ही आप बुनियादी बातों को सीखते हैं, आपको एहसास होता है कि कुछ भी उनका अनुसरण नहीं करता है
CQM

1
लेकिन @ जय, क्यों दर्शक अपने बच्चों को लोड कर रहे हैं हर बार ऊंचाई को समायोजित नहीं कर सकते?
19

@CQM वास्तव में! ViewPagerIndicator लाइब्रेरी में layout_heightसेट के साथ समान समस्या है wrap_content, लेकिन यह और भी बदतर है क्योंकि इसे एक निश्चित राशि तक सेट करने के लिए सरल वर्कअराउंड काम नहीं करता है।
गिउलिओ पियानकैसेली

20

डैनियल लोपेज़ लोकेल उत्तर का उपयोग करते हुए , मैंने कोटलिन में इस वर्ग का निर्माण किया। आशा है कि यह आपको अधिक समय बचाएगा

class DynamicHeightViewPager @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : ViewPager(context, attrs) {

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
    var heightMeasureSpec = heightMeasureSpec

    var height = 0
    for (i in 0 until childCount) {
        val child = getChildAt(i)
        child.measure(widthMeasureSpec, View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED))
        val h = child.measuredHeight
        if (h > height) height = h
    }

    if (height != 0) {
        heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)
    }

    super.onMeasure(widthMeasureSpec, heightMeasureSpec)
}}

16

मैंने पहले ही कई प्रोजेक्ट में इस मुद्दे का सामना किया है और कभी भी इसका पूरा हल नहीं निकला। इसलिए मैंने ViewPager के लिए इन-प्लेस प्रतिस्थापन के रूप में WrapContentViewPager github प्रोजेक्ट बनाया।

https://github.com/rnevet/WCViewPager

समाधान यहाँ कुछ उत्तरों से प्रेरित था, लेकिन इसमें सुधार हुआ:

  • स्क्रॉल करते समय वर्तमान दृश्य के अनुसार ViewPager ऊँचाई को गतिशील रूप से बदलता है।
  • PagerTabStrip जैसे "सजावट" विचारों की ऊंचाई पर विचार करता है।
  • सभी पैडिंग को ध्यान में रखता है।

समर्थन लाइब्रेरी संस्करण 24 के लिए अपडेट किया गया जिसने पिछले कार्यान्वयन को तोड़ दिया।


@mvai क्या आप किसी मुद्दे को खोल सकते हैं, या उसे कांटा कर सकते हैं और नमूना ऐप को संशोधित कर सकते हैं?
राणान Ra

1
मुझे पता चला कि RecyclerView में कुछ रैप_ कॉन्टेंट मुद्दे भी हैं; यदि आप इस तरह से एक कस्टम LinearLayoutManager का उपयोग करते हैं तो यह काम करता है । तो आपके पुस्तकालय में कुछ भी गलत नहीं है।
नैटारियो

1
अभी भी जो कुछ तय किया जाना है वह है FragmentStatePagerAdapter के साथ इसका उपयोग। ऐसा लगता है कि टुकड़े टुकड़े किए जाने से पहले यह चिल्ड को माप रहा है, इस प्रकार छोटी ऊंचाई देता है। मेरे लिए क्या काम किया गया था @logan का जवाब है, हालांकि मैं अभी भी इस पर काम कर रहा हूं। आप अपने पुस्तकालय में उस दृष्टिकोण को मर्ज करने का प्रयास कर सकते हैं। मैं गितुब, सॉरी से परिचित नहीं हूं।
नैटारियो

धन्यवाद, मैं उस पर एक नज़र डालूँगा।
रावण

1
FragmentPagerAdapter के साथ इस कार्य को करने के तरीके के बारे में सोच रहे किसी के लिए, अपने एडेप्टर को Fragments की सूची रखकर आंतरिक रूप से ObjectAtPositionInterface को लागू करें, ताकि वह getbbjectAtPosition विधि से संबंधित Fragment को वापस कर सके।
पाब्लो

15

मैं बस एक ही मुद्दे पर टकरा गया। मेरे पास एक ViewPager था और मैं इसके बटन पर एक विज्ञापन प्रदर्शित करना चाहता था। मैंने जो समाधान पाया वह पेजर को एक रिलेटिव व्यू में प्राप्त करने के लिए था और इसे उस लेआउट आईडी पर सेट करें जिसे मैं नीचे देखना चाहता हूं। मेरे लिए काम किया।

यहाँ मेरा लेआउट XML है:

  <RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <LinearLayout
        android:id="@+id/AdLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:orientation="vertical" >
    </LinearLayout>

    <android.support.v4.view.ViewPager
        android:id="@+id/mainpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/AdLayout" >
    </android.support.v4.view.ViewPager>
</RelativeLayout>

4
केवल संदर्भ के लिए, आपको xmlns की आवश्यकता नहीं है: Android = " schemas.android.com/apk/res/android " दोनों में, केवल पहले एक में।
मार्टिन मार्कोसिनी

2
आपका मुद्दा बिल्कुल भी ऐसा नहीं था। आपका लेआउट ठीक से काम करता है ViewPager के साथ मैच_परेंट के लिए सेट - ओपी में एक ऐसी स्थिति थी जहां वह चाहता था कि व्यूपैगर इसे सामग्री से लपेटे।
k2col

9

मैं भी इस समस्या में भाग गया, लेकिन मेरे मामले में मेरे पास एक FragmentPagerAdapterआपूर्ति थीViewPager इसके पृष्ठों साथ । समस्या मैं था कि था onMeasure()की ViewPagerमें से किसी से पहले कहा जाता थाFragments निर्मित किया गया था (और इसलिए कर सकते थे नहीं आकार में ही सही ढंग से)।

थोड़ा परीक्षण और त्रुटि के बाद, मैंने पाया कि finishUpdate()FragmentPagerAdapter की विधि Fragmentsको आरंभिक रूप से शुरू करने के बाद कहा जाता है ( instantiateItem()में सेFragmentPagerAdapter ), और भी के बाद / पेज स्क्रॉल के दौरान। मैंने एक छोटा इंटरफ़ेस बनाया:

public interface AdapterFinishUpdateCallbacks
{
    void onFinishUpdate();
}

जो मैं अपने में गुजारता हूँ FragmentPagerAdapter और कॉल करता :

@Override
public void finishUpdate(ViewGroup container)
{
    super.finishUpdate(container);

    if (this.listener != null)
    {
        this.listener.onFinishUpdate();
    }
}

जो बदले में मुझे setVariableHeight()अपने CustomViewPagerकार्यान्वयन पर कॉल करने की अनुमति देता है :

public void setVariableHeight()
{
    // super.measure() calls finishUpdate() in adapter, so need this to stop infinite loop
    if (!this.isSettingHeight)
    {
        this.isSettingHeight = true;

        int maxChildHeight = 0;
        int widthMeasureSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY);
        for (int i = 0; i < getChildCount(); i++)
        {
            View child = getChildAt(i);
            child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.UNSPECIFIED));
            maxChildHeight = child.getMeasuredHeight() > maxChildHeight ? child.getMeasuredHeight() : maxChildHeight;
        }

        int height = maxChildHeight + getPaddingTop() + getPaddingBottom();
        int heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);

        super.measure(widthMeasureSpec, heightMeasureSpec);
        requestLayout();

        this.isSettingHeight = false;
    }
}

मुझे यकीन नहीं है कि यह सबसे अच्छा तरीका है, अगर आपको लगता है कि यह अच्छा / बुरा / बुरा है, तो टिप्पणी पसंद आएगी, लेकिन यह मेरे कार्यान्वयन में बहुत अच्छा काम कर रहा है :)

उम्मीद है कि इससे वहां किसी को मदद मिलेगी!

संपादित करें: मैं requestLayout()कॉल करने के बाद जोड़ना भूल गया super.measure()(अन्यथा यह दृश्य को फिर से नहीं बनाता है)।

मैं माता-पिता की गद्दी को अंतिम ऊंचाई तक जोड़ना भी भूल गया।

मैं भी आवश्यक रूप से एक नया बनाने के पक्ष में मूल चौड़ाई / ऊँचाई को मापता हूँ। तदनुसार कोड अपडेट किया है।

एक अन्य समस्या मैं था कि यह अपने आप में एक में सही ढंग से आकार नहीं होता था ScrollViewऔर पाया अपराधी के साथ बच्चे को मापने था MeasureSpec.EXACTLYबजायMeasureSpec.UNSPECIFIED । इसे प्रतिबिंबित करने के लिए अद्यतन किया गया।

इन परिवर्तनों को कोड में जोड़ा गया है। आप चाहें तो पुराने (गलत) संस्करणों को देखने के लिए इतिहास की जांच कर सकते हैं।


आप उन लोगों को शामिल नहीं करते जिन्हें आप कृपया कोड में भूल गए हैं।
हसन

@ हसन मैंने पहले ही कर दिया था, किसी भी भ्रम के लिए खेद है! उत्तर को अपडेट करने के लिए कहेंगे कि
लोगन

बहुत बढ़िया! खुशी है कि यह मदद की :)
लोगान

8

एक अन्य उपाय है ViewPagerकि वर्तमान पृष्ठ की ऊंचाई के अनुसार ऊंचाई को अद्यतन किया जाए PagerAdapter। यह मानते हुए कि आपके ViewPagerपेज इस तरह से बन रहे हैं:

@Override
public Object instantiateItem(ViewGroup container, int position) {
  PageInfo item = mPages.get(position);
  item.mImageView = new CustomImageView(container.getContext());
  item.mImageView.setImageDrawable(item.mDrawable);
  container.addView(item.mImageView, 0);
  return item;
}

जहां संरचनाओं mPagesकी आंतरिक सूची को PageInfoगतिशील रूप से जोड़ा गया है PagerAdapterऔर CustomImageViewयह ImageViewओवररिडेन के साथ नियमित हैonMeasure() विधि के जो निर्दिष्ट चौड़ाई के अनुसार अपनी ऊंचाई निर्धारित करता है और छवि अनुपात को बनाए रखता है।

आप विधि ViewPagerमें ऊँचाई बढ़ा सकते हैं setPrimaryItem():

@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
  super.setPrimaryItem(container, position, object);

  PageInfo item = (PageInfo) object;
  ViewPager pager = (ViewPager) container;
  int width = item.mImageView.getMeasuredWidth();
  int height = item.mImageView.getMeasuredHeight();
  pager.setLayoutParams(new FrameLayout.LayoutParams(width, Math.max(height, 1)));
}

ध्यान दें Math.max(height, 1)। वह कष्टप्रद बग को ठीक ViewPagerकरता है जो प्रदर्शित पृष्ठ को अपडेट नहीं करता है (इसे खाली दिखाता है), जब पिछले पृष्ठ में शून्य ऊंचाई (यानी शून्य में खींचने योग्य CustomImageView) होती है, तो प्रत्येक विषम दो पृष्ठों के बीच आगे और पीछे स्वाइप होता है।


यह मुझे सही रास्ता लगता है, लेकिन मुझे तरीकों item.mImageView.measure(..)में सही आयाम प्राप्त getMeasuredXXX()करने की आवश्यकता है।
गियानलुका पी।

6

दृश्यदर्शी के अंदर स्थिर सामग्री का उपयोग करते समय और आप कोई फैंसी एनीमेशन नहीं चाहते हैं, तो आप निम्नलिखित दृश्य पेजर का उपयोग कर सकते हैं

public class HeightWrappingViewPager extends ViewPager {

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

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

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)   {
      super.onMeasure(widthMeasureSpec, heightMeasureSpec);
      View firstChild = getChildAt(0);
      firstChild.measure(widthMeasureSpec, heightMeasureSpec);
      super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(firstChild.getMeasuredHeight(), MeasureSpec.EXACTLY));
  }
}

यह ठीक काम करता है। मैंने इसे बच्चों के माध्यम से पाला और अधिकतम ऊंचाई के साथ ले जाकर बढ़ाया।
जेवियर मेंडोंका

यहां तक ​​कि ठीक है भी
पुनर्नवीनीकरण

मुझे यह अपवाद मिल रहा है- java.lang.NullPointerException: आभासी विधि 'void android.view.View.measure (int, int)' को एक अशक्त वस्तु संदर्भ पर लागू करने का प्रयास
PJ2104

लेकिन पहला तत्व लेना गलत हो सकता है।
टोबियास रिइच

4
public CustomPager (Context context) {
    super(context);
}

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

int getMeasureExactly(View child, int widthMeasureSpec) {
    child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
    int height = child.getMeasuredHeight();
    return MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
}

@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    boolean wrapHeight = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST;

    final View tab = getChildAt(0);
    if (tab == null) {
        return;
    }

    int width = getMeasuredWidth();
    if (wrapHeight) {
        // Keep the current measured width.
        widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
    }
    Fragment fragment = ((Fragment) getAdapter().instantiateItem(this, getCurrentItem()));
    heightMeasureSpec = getMeasureExactly(fragment.getView(), widthMeasureSpec);

    //Log.i(Constants.TAG, "item :" + getCurrentItem() + "|height" + heightMeasureSpec);
    // super has to be called again so the new specs are treated as
    // exact measurements.
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

4

पॉपकॉर्न समय से एंड्रॉइड ऐप के स्रोत कोड से मुझे यह समाधान मिला जो गतिशील रूप से वर्तमान बच्चे के आकार के आधार पर अच्छे एनीमेशन के साथ व्यूपेगर के आकार को समायोजित करता है।

https://git.popcorntime.io/popcorntime/android/blob/5934f8d0c8fed39af213af4512272d12d2efb6a6/mobile/src/main/java/pct/droid/widget/WrappingViewPager.java

public class WrappingViewPager extends ViewPager {

    private Boolean mAnimStarted = false;

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

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

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        if(!mAnimStarted && null != getAdapter()) {
            int height = 0;
            View child = ((FragmentPagerAdapter) getAdapter()).getItem(getCurrentItem()).getView();
            if (child != null) {
                child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
                height = child.getMeasuredHeight();
                if (VersionUtils.isJellyBean() && height < getMinimumHeight()) {
                    height = getMinimumHeight();
                }
            }

            // Not the best place to put this animation, but it works pretty good.
            int newHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
            if (getLayoutParams().height != 0 && heightMeasureSpec != newHeight) {
                    final int targetHeight = height;
                    final int currentHeight = getLayoutParams().height;
                    final int heightChange = targetHeight - currentHeight;

                    Animation a = new Animation() {
                        @Override
                        protected void applyTransformation(float interpolatedTime, Transformation t) {
                            if (interpolatedTime >= 1) {
                                getLayoutParams().height = targetHeight;
                            } else {
                                int stepHeight = (int) (heightChange * interpolatedTime);
                                getLayoutParams().height = currentHeight + stepHeight;
                            }
                            requestLayout();
                        }

                        @Override
                        public boolean willChangeBounds() {
                            return true;
                        }
                    };

                    a.setAnimationListener(new Animation.AnimationListener() {
                        @Override
                        public void onAnimationStart(Animation animation) {
                            mAnimStarted = true;
                        }

                        @Override
                        public void onAnimationEnd(Animation animation) {
                            mAnimStarted = false;
                        }

                        @Override
                        public void onAnimationRepeat(Animation animation) {
                        }
                    });

                    a.setDuration(1000);
                    startAnimation(a);
                    mAnimStarted = true;
            } else {
                heightMeasureSpec = newHeight;
            }
        }

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

4

यदि आपको ViewPager की आवश्यकता है, तो इसका आकार हर बच्चे को समायोजित करें , न कि केवल सबसे बड़े एक के लिए, मैंने एक कोड कोड लिखा है जो इसे करता है। ध्यान दें कि उस परिवर्तन पर कोई एनीमेशन नहीं है (मेरे मामले में परिचारिका नहीं)

Android: minHeight ध्वज भी समर्थित है।

public class ChildWrappingAdjustableViewPager extends ViewPager {
    List<Integer> childHeights = new ArrayList<>(getChildCount());
    int minHeight = 0;
    int currentPos = 0;

    public ChildWrappingAdjustableViewPager(@NonNull Context context) {
        super(context);
        setOnPageChangeListener();
    }

    public ChildWrappingAdjustableViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        obtainMinHeightAttribute(context, attrs);
        setOnPageChangeListener();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {            
        childHeights.clear();

        //calculate child views
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
            int h = child.getMeasuredHeight();
            if (h < minHeight) {
                h = minHeight;
            }
            childHeights.add(i, h);
        }

        if (childHeights.size() - 1 >= currentPos) {
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(childHeights.get(currentPos), MeasureSpec.EXACTLY);
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    private void obtainMinHeightAttribute(@NonNull Context context, @Nullable AttributeSet attrs) {
        int[] heightAttr = new int[]{android.R.attr.minHeight};
        TypedArray typedArray = context.obtainStyledAttributes(attrs, heightAttr);
        minHeight = typedArray.getDimensionPixelOffset(0, -666);
        typedArray.recycle();
    }

    private void setOnPageChangeListener() {
        this.addOnPageChangeListener(new SimpleOnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {
                currentPos = position;

                ViewGroup.LayoutParams layoutParams = ChildWrappingAdjustableViewPager.this.getLayoutParams();
                layoutParams.height = childHeights.get(position);
                ChildWrappingAdjustableViewPager.this.setLayoutParams(layoutParams);
                ChildWrappingAdjustableViewPager.this.invalidate();
            }
        });
    }
}

इसलिए इस एडॉप्टर में एक बड़ी समस्या है जब एडॉप्टर में आइटमों का परिवर्तन बदल जाता है
जॉबबर्ट

क्या आप अपना कथन स्पष्ट कर सकते हैं?
Phatee P

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

4

बेहतर डैनियल लोपेज़ लाक्ले का जवाब, कोटलिन में फिर से लिखा गया :

class MyViewPager(context: Context, attrs: AttributeSet): ViewPager(context, attrs) {
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val zeroHeight = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)

        val maxHeight = children
            .map { it.measure(widthMeasureSpec, zeroHeight); it.measuredHeight }
            .max() ?: 0

        if (maxHeight > 0) {
            val maxHeightSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.EXACTLY)
            super.onMeasure(widthMeasureSpec, maxHeightSpec)
            return
        }

        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
    }
}

3

मैं एक ही मुद्दे पर टकरा गया, और जब पृष्ठ के बीच उपयोगकर्ता स्क्रॉल किया गया तो मुझे इसकी सामग्री के चारों ओर ViewPager को लपेटना पड़ा। सायबरजेन के उपरोक्त उत्तर का उपयोग करते हुए, मैंने निम्नलिखित तरीकों को परिभाषित किया:

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

    if (getCurrentItem() < getChildCount()) {
        View child = getChildAt(getCurrentItem());
        if (child.getVisibility() != GONE) {
            heightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec),
                    MeasureSpec.UNSPECIFIED);
            child.measure(widthMeasureSpec, heightMeasureSpec);
        }

        setMeasuredDimension(getMeasuredWidth(), measureHeight(heightMeasureSpec, getChildAt(getCurrentItem())));            
    }
}

इस तरह, OnMeasure विधि ViewPager द्वारा प्रदर्शित वर्तमान पृष्ठ की ऊंचाई निर्धारित करती है।


आपके उत्तर के साथ केवल सबसे ऊँचाई की सामग्री दिखाई देती है, अन्य सामग्री गायब हो जाती है ...
ब्लेज़ तम

2

ऊपर सुझाए गए कुछ भी मेरे लिए काम नहीं किया। मेरे उपयोग का मामला 4 कस्टम व्यूपैनर्स में है ScrollView। उनमें से टॉप को आस्पेक्ट रेशियो के आधार पर मापा जाता है और बाकी के पास बस होता है layout_height=wrap_content। मैंने सायबरजेन , डैनियल लोपेज़ लैक्ले सॉल्यूशंस की कोशिश की है । उनमें से कोई भी मेरे लिए पूरी तरह से काम नहीं करता है।

मेरा अनुमान है कि साइबरनेट पेज> 1 पर काम क्यों नहीं करता है क्योंकि यह पेज 1 के आधार पर पेजर की ऊंचाई की गणना करता है, जो कि आगे स्क्रॉल करने पर छिपा हुआ है।

सायबरजेन और डैनियल लोपेज़ लाकले दोनों के सुझावों से मेरे मामले में अजीब व्यवहार होता है: 3 में से 2 ठीक हैं और 1 बेतरतीब ढंग से ऊंचाई 0. है। onMeasureबच्चों को आबादी से पहले बुलाया गया था। इसलिए मैं इन 2 उत्तरों के मिश्रण के साथ आया हूं + मेरे अपने सुधार:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    if (getLayoutParams().height == ViewGroup.LayoutParams.WRAP_CONTENT) {
        // find the first child view
        View view = getChildAt(0);
        if (view != null) {
            // measure the first child view with the specified measure spec
            view.measure(widthMeasureSpec, heightMeasureSpec);
            int h = view.getMeasuredHeight();
            setMeasuredDimension(getMeasuredWidth(), h);
            //do not recalculate height anymore
            getLayoutParams().height = h;
        }
    }
}

आइडिया ViewPagerबच्चों के आयामों की गणना करने और लेआउट के पैरामेट्स में पहले पृष्ठ की गणना की गई ऊंचाई को बचाने के लिए है ViewPager। टुकड़े की लेआउट ऊँचाई सेट करना न भूलें wrap_contentअन्यथा आप ऊँचाई = 0 प्राप्त कर सकते हैं। मैंने इसका उपयोग किया है:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="wrap_content">
        <!-- Childs are populated in fragment -->
</LinearLayout>

कृपया ध्यान दें कि यह समाधान बहुत अच्छा काम करता है यदि आपके सभी पृष्ठों की ऊंचाई समान है । अन्यथा आपको ViewPagerवर्तमान में सक्रिय बच्चे के आधार पर ऊँचाई पुनर्गणना करने की आवश्यकता है। मुझे इसकी आवश्यकता नहीं है, लेकिन यदि आप समाधान सुझाते हैं तो मुझे उत्तर को अपडेट करने में खुशी होगी।


क्या आप उन सभी वर्षों के बाद भी अपना जवाब अपडेट कर सकते हैं? एक टन मेरी मदद करेगा
डेनी

2

इस समस्या वाले लोगों के लिए और C # में Xamarin Android के लिए कोडिंग करना, यह एक त्वरित समाधान भी हो सकता है:

pager.ChildViewAdded += (sender, e) => {
    e.Child.Measure ((int)MeasureSpecMode.Unspecified, (int)MeasureSpecMode.Unspecified);
    e.Parent.LayoutParameters.Height = e.Child.MeasuredHeight;
};

यह मुख्य रूप से उपयोगी है यदि आपके बच्चे के विचार समान ऊंचाई के हैं। अन्यथा, आपको उन सभी बच्चों पर कुछ "न्यूनतमहाइट" मान रखने की आवश्यकता होगी जिन्हें आप जांचते हैं, और फिर भी आप अपने छोटे बच्चे के विचारों के नीचे खाली स्थान नहीं देखना चाहते हैं।

हालांकि यह समाधान मेरे लिए पर्याप्त नहीं है, लेकिन ऐसा इसलिए है क्योंकि मेरे बच्चे के आइटम लिस्ट व्यू हैं और उनके मेजरहाइट की सही गणना नहीं की गई है, ऐसा लगता है।


इसने मेरे लिए काम किया। दृश्यदर्शी में मेरे बच्चे के सभी दृश्य समान ऊंचाई के हैं।
दिमित्री

2

मेरे पास WrapContentHeightViewPager का एक संस्करण है, जो एपीआई 23 से पहले सही ढंग से काम कर रहा था, जो चयनित बच्चे के वर्तमान दृश्य पर माता-पिता की ऊंचाई के आधार का आकार बदल देगा।

एपीआई 23 में अपग्रेड करने के बाद इसने काम करना बंद कर दिया। यह पता चलता है कि पुराने समाधान का उपयोग getChildAt(getCurrentItem())वर्तमान बच्चे को देखने के लिए किया जा रहा था ताकि यह मापा जा सके कि काम नहीं कर रहा है। यहां देखें समाधान: https://stackoverflow.com/a/16512217/1265583

नीचे एपीआई 23 के साथ काम करता है:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int height = 0;
    ViewPagerAdapter adapter = (ViewPagerAdapter)getAdapter();
    View child = adapter.getItem(getCurrentItem()).getView();
    if(child != null) {
        child.measure(widthMeasureSpec,  MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
        height = child.getMeasuredHeight();
    }
    heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);

    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

धन्यवाद!! घंटों तक जवाब देने की कोशिश करते रहे और यह एकमात्र ऐसा काम है जो पूरी तरह से मेरे लिए काम करता है। इसे एक कस्टम एडॉप्टर के साथ जोड़ा जाना चाहिए, जहां 'setPrimaryItem ()' पेजर में एक फ़ंक्शन को कॉल करता है जो requestLayout()इतनी ऊंचाई को कॉल करता है जिसे हम एक टैब से अगले तक जाते हैं। क्या आपको याद है कि superदो बार बुलाए जाने की आवश्यकता क्यों है ? मैंने देखा कि यह अन्यथा काम नहीं करेगा।
M3RS

एपीआई 28 के साथ काम करता है।
खालिद लखानी

2

नीचे दिया गया कोड केवल मेरे लिए काम की चीज है

1. इस श्रेणी का उपयोग एक हाईट्रोवपिंग व्यूगर घोषित करने के लिए करें:

 public class HeightWrappingViewPager extends ViewPager {

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

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

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int mode = MeasureSpec.getMode(heightMeasureSpec);
            // Unspecified means that the ViewPager is in a ScrollView WRAP_CONTENT.
            // At Most means that the ViewPager is not in a ScrollView WRAP_CONTENT.
            if (mode == MeasureSpec.UNSPECIFIED || mode == MeasureSpec.AT_MOST) {
                // super has to be called in the beginning so the child views can be initialized.
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
                int height = 0;
                for (int i = 0; i < getChildCount(); i++) {
                    View child = getChildAt(i);
                    child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
                    int h = child.getMeasuredHeight();
                    if (h > height) height = h;
                }
                heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
            }
            // super has to be called again so the new specs are treated as exact measurements
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }

2. अपनी xml फ़ाइल में ऊंचाई रैपिंग व्यू पेजर डालें:

<com.project.test.HeightWrappingViewPager
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
</com.project.test.HeightWrappingViewPager>

3. अपने विचार पेजर की घोषणा करें:

HeightWrappingViewPager mViewPager;
mViewPager = (HeightWrappingViewPager) itemView.findViewById(R.id.pager);
CustomAdapter adapter = new CustomAdapter(context);
mViewPager.setAdapter(adapter);
mViewPager.measure(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT);

धन्यवाद। यह काम किया। लेकिन एंड्रॉइड टीम उनके कोड बेस में ऐसा क्यों नहीं कर सकती है?
मोहनकृष्ण

यह उन चीजों में से एक है जिसे आपको स्वयं को अनुकूलित करना है जो आपकी आवश्यकता पर निर्भर करता है, इस वर्ष 2019 Google I / O में भी Google ने viewPager2 की शुरुआत की है और यह पुराने ViewPager का प्रतिस्थापन है, जिसे 2011 में बनाया गया था, कार्यान्वयन 'androidx.viewpit2: viewpager2 : 1.0.0-अल्फा04 '
हसन

2

मैं चयनित आइटम के आधार पर ऊँचाई को बदलने के लिए व्यूपेंजर बनाने के लिए साइबरबर्न के उत्तर को संपादित करता हूं। कक्षा साइबरबर्न के समान है, लेकिन मैंने पूर्णांक के एक वेक्टर को जोड़ा, जो सभी दर्शकों के बच्चे के दृष्टिकोण को ऊंचाइयों पर देखता है और जब पृष्ठ ऊंचाई अपडेट करने के लिए बदल जाता है तो हम इसे एक्सेस कर सकते हैं

यह वर्ग है:

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.viewpager.widget.ViewPager;

import java.util.Vector;

public class WrapContentHeightViewPager extends ViewPager {
    private Vector<Integer> heights = new Vector<>();

    public WrapContentHeightViewPager(@NonNull Context context) {
        super(context);
    }

    public WrapContentHeightViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

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

        for(int i=0;i<getChildCount();i++) {
            View view = getChildAt(i);
            if (view != null) {
                view.measure(widthMeasureSpec, heightMeasureSpec);
                heights.add(measureHeight(heightMeasureSpec, view));
            }
        }
        setMeasuredDimension(getMeasuredWidth(), measureHeight(heightMeasureSpec, getChildAt(0)));
    }

    public int getHeightAt(int position){
        return heights.get(position);
    }

    private int measureHeight(int measureSpec, View view) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            result = specSize;
        } else {
            if (view != null) {
                result = view.getMeasuredHeight();
            }
            if (specMode == MeasureSpec.AT_MOST) {
                result = Math.min(result, specSize);
            }
        }
        return result;
    }
}

फिर अपनी गतिविधि में एक OnPageChangeListener जोड़ें

WrapContentHeightViewPager viewPager = findViewById(R.id.my_viewpager);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
     @Override
     public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {}
     @Override
     public void onPageSelected(int position) {
         LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) viewPager.getLayoutParams();
         params.height = viewPager.getHeightAt(position);
         viewPager.setLayoutParams(params);
     }
     @Override
     public void onPageScrollStateChanged(int state) {}
});

और यहाँ xml है:

<com.example.example.WrapContentHeightViewPager
    android:id="@+id/my_viewpager"
    android:fillViewport="true"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"/>

यदि आवश्यक हो तो कृपया मेरी अंग्रेजी को सही करें


इसके कुछ मुद्दे हैं। heightsसूची अनंत बढ़ सकता है।
रोशू

@rosuh आपने इस मुद्दे का सामना कब किया? मैंने इसे केवल TabLayout में ViewPager के साथ उपयोग किया, इसलिए मुझे यकीन नहीं है कि यह हर जगह अच्छी तरह से काम करता है
Geggiamarti

@geggiamarti समस्या कुछ पृष्ठों को पुनर्नवीनीकरण किया जाएगा। और फिर से बनाया जब उपयोगकर्ता उन्हें ज़ोर से मारना इसलिए measureबहु समय में कॉल किया जाएगा। यह ऊंचाइयों की सूची बढ़ा सकता है। एक और स्थिति है उपयोगकर्ता इस कॉल के लिए requestLayout(या setLayoutParamsविधि, जैसे आपने क्या किया) मैन्युअल रूप से देख सकता है, यह भी कई बार मापेगा।
रसूख

1

यदि ViewPagerआप उपयोग कर रहे हैं तो ScrollView AND का एक PagerTitleStripबच्चा है और पहले से उपलब्ध कराए गए महान उत्तरों में से एक मामूली संशोधन का उपयोग करने की आवश्यकता होगी। संदर्भ के लिए मेरा XML ऐसा दिखता है:

<ScrollView
    android:id="@+id/match_scroll_view"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="@color/white">

    <LinearLayout
        android:id="@+id/match_and_graphs_wrapper"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <view
            android:id="@+id/pager"
            class="com.printandpixel.lolhistory.util.WrapContentHeightViewPager"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <android.support.v4.view.PagerTitleStrip
                android:id="@+id/pager_title_strip"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_gravity="top"
                android:background="#33b5e5"
                android:paddingBottom="4dp"
                android:paddingTop="4dp"
                android:textColor="#fff" />
        </view>
    </LinearLayout>
</ScrollView>

अपने में onMeasureआप के लिए है ADD की measuredHeight PagerTitleStripयदि कोई मिलता है। अन्यथा इसकी ऊंचाई को सभी बच्चों की सबसे बड़ी ऊंचाई नहीं माना जाएगा, भले ही यह अतिरिक्त स्थान लेता हो।

मनाइए कि यह किसी और के लिए सहायक हो। क्षमा करें कि यह हैक का एक सा है ...

public class WrapContentHeightViewPager extends ViewPager {

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

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int pagerTitleStripHeight = 0;
        int height = 0;
        for(int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
            int h = child.getMeasuredHeight();
            if (h > height) {
                // get the measuredHeight of the tallest fragment
                height = h;
            }
            if (child.getClass() == PagerTitleStrip.class) {
                // store the measured height of the pagerTitleStrip if one is found. This will only
                // happen if you have a android.support.v4.view.PagerTitleStrip as a direct child
                // of this class in your XML.
                pagerTitleStripHeight = h;
            }
        }

        heightMeasureSpec = MeasureSpec.makeMeasureSpec(height+pagerTitleStripHeight, MeasureSpec.EXACTLY);

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

1

अधिकांश समाधान जो मैं यहां देख रहा हूं, वे दोहरा माप कर रहे हैं: पहले बच्चे के विचारों को मापना, और फिर कॉल करना super.onMeasure()

मैं एक रिवाज लेकर आया हूं जो WrapContentViewPagerअधिक कुशल है, RecyclerView और Fragment के साथ अच्छा काम करता है

आप यहां डेमो देख सकते हैं:

GitHub / ssynhtn / WrapContentViewPager

और यहां कक्षा का कोड: WrapContentViewPager.java


0

मेरे पास एक समान (लेकिन अधिक जटिल परिदृश्य) है। मेरे पास एक संवाद है, जिसमें एक ViewPager है।
बाल पृष्ठों में से एक छोटा है, एक स्थिर ऊंचाई के साथ।
एक और चाइल्ड पेज हमेशा जितना संभव हो उतना लंबा होना चाहिए।
एक अन्य चाइल्ड पेज में एक स्क्रॉलव्यू होता है, और पेज (और इस प्रकार पूरा संवाद) WRAP_CONTENT होना चाहिए, अगर स्क्रॉलव्यू कंटेंट को डायलॉग को पूरी ऊंचाई उपलब्ध नहीं है।

मौजूदा उत्तरों में से किसी ने भी इस विशिष्ट परिदृश्य के लिए पूरी तरह से काम नहीं किया। पकड़ो- यह एक ऊबड़ सवारी है।

void setupView() {
    final ViewPager.SimpleOnPageChangeListener pageChangeListener = new ViewPager.SimpleOnPageChangeListener() {
        @Override
        public void onPageSelected(int position) {
            currentPagePosition = position;

            // Update the viewPager height for the current view

            /*
            Borrowed from https://github.com/rnevet/WCViewPager/blob/master/wcviewpager/src/main/java/nevet/me/wcviewpager/WrapContentViewPager.java
            Gather the height of the "decor" views, since this height isn't included
            when measuring each page's view height.
             */
            int decorHeight = 0;
            for (int i = 0; i < viewPager.getChildCount(); i++) {
                View child = viewPager.getChildAt(i);
                ViewPager.LayoutParams lp = (ViewPager.LayoutParams) child.getLayoutParams();
                if (lp != null && lp.isDecor) {
                    int vgrav = lp.gravity & Gravity.VERTICAL_GRAVITY_MASK;
                    boolean consumeVertical = vgrav == Gravity.TOP || vgrav == Gravity.BOTTOM;
                    if (consumeVertical) {
                        decorHeight += child.getMeasuredHeight();
                    }
                }
            }

            int newHeight = decorHeight;

            switch (position) {
                case PAGE_WITH_SHORT_AND_STATIC_CONTENT:
                    newHeight += measureViewHeight(thePageView1);
                    break;
                case PAGE_TO_FILL_PARENT:
                    newHeight = ViewGroup.LayoutParams.MATCH_PARENT;
                    break;
                case PAGE_TO_WRAP_CONTENT:
//                  newHeight = ViewGroup.LayoutParams.WRAP_CONTENT; // Works same as MATCH_PARENT because...reasons...
//                  newHeight += measureViewHeight(thePageView2); // Doesn't allow scrolling when sideways and height is clipped

                    /*
                    Only option that allows the ScrollView content to scroll fully.
                    Just doing this might be way too tall, especially on tablets.
                    (Will shrink it down below)
                     */
                    newHeight = ViewGroup.LayoutParams.MATCH_PARENT;
                    break;
            }

            // Update the height
            ViewGroup.LayoutParams layoutParams = viewPager.getLayoutParams();
            layoutParams.height = newHeight;
            viewPager.setLayoutParams(layoutParams);

            if (position == PAGE_TO_WRAP_CONTENT) {
                // This page should wrap content

                // Measure height of the scrollview child
                View scrollViewChild = ...; // (generally this is a LinearLayout)
                int scrollViewChildHeight = scrollViewChild.getHeight(); // full height (even portion which can't be shown)
                // ^ doesn't need measureViewHeight() because... reasons...

                if (viewPager.getHeight() > scrollViewChildHeight) { // View pager too tall?
                    // Wrap view pager height down to child height
                    newHeight = scrollViewChildHeight + decorHeight;

                    ViewGroup.LayoutParams layoutParams2 = viewPager.getLayoutParams();
                    layoutParams2.height = newHeight;
                    viewPager.setLayoutParams(layoutParams2);
                }
            }

            // Bonus goodies :)
            // Show or hide the keyboard as appropriate. (Some pages have EditTexts, some don't)
            switch (position) {
                // This case takes a little bit more aggressive code than usual

                if (position needs keyboard shown){
                    showKeyboardForEditText();
                } else if {
                    hideKeyboard();
                }
            }
        }
    };

    viewPager.addOnPageChangeListener(pageChangeListener);

    viewPager.getViewTreeObserver().addOnGlobalLayoutListener(
            new ViewTreeObserver.OnGlobalLayoutListener() {
                @Override
                public void onGlobalLayout() {
                    // http://stackoverflow.com/a/4406090/4176104
                    // Do things which require the views to have their height populated here
                    pageChangeListener.onPageSelected(currentPagePosition); // fix the height of the first page

                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
                        viewPager.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                    } else {
                        viewPager.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                    }

                }
            }
    );
}


...

private void showKeyboardForEditText() {
    // Make the keyboard appear.
    getDialog().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
    getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);

    inputViewToFocus.requestFocus();

    // http://stackoverflow.com/a/5617130/4176104
    InputMethodManager inputMethodManager =
            (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
    inputMethodManager.toggleSoftInputFromWindow(
            inputViewToFocus.getApplicationWindowToken(),
            InputMethodManager.SHOW_IMPLICIT, 0);
}

...

/**
 * Hide the keyboard - http://stackoverflow.com/a/8785471
 */
private void hideKeyboard() {
    InputMethodManager inputManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);

    inputManager.hideSoftInputFromWindow(inputBibleBookStart.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}

...

//https://github.com/rnevet/WCViewPager/blob/master/wcviewpager/src/main/java/nevet/me/wcviewpager/WrapContentViewPager.java
private int measureViewHeight(View view) {
    view.measure(ViewGroup.getChildMeasureSpec(-1, -1, view.getLayoutParams().width), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
    return view.getMeasuredHeight();
}

विचारों को मापने और सजावट की ऊँचाई को मापने के लिए कोड के लिए @Ranan का बहुत धन्यवाद। मैं उनकी लाइब्रेरी के साथ समस्याओं में भाग गया- एनीमेशन थम गया, और मुझे लगता है कि मेरे स्क्रॉलव्यू को स्क्रॉल नहीं किया जाएगा जब संवाद की ऊंचाई इसकी आवश्यकता के लिए पर्याप्त थी।


0

मेरे मामले में जोड़ने clipToPaddingसे समस्या हल हो गई।

<android.support.v4.view.ViewPager
    ...
    android:clipToPadding="false"
    ...
    />

चीयर्स!



0

मेरे मामले में, मुझे आकार को लागू करते समय वर्तमान में चयनित तत्व और एनीमेशन के लिए एक wra_content के साथ एक दृश्य-समूह की आवश्यकता थी। नीचे आप मेरा कार्यान्वयन देख सकते हैं। क्या कोई काम आ सकता है।

package one.xcorp.widget

import android.animation.ValueAnimator
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
import one.xcorp.widget.R
import kotlin.properties.Delegates.observable

class ViewPager : android.support.v4.view.ViewPager {

    var enableAnimation by observable(false) { _, _, enable ->
        if (enable) {
            addOnPageChangeListener(onPageChangeListener)
        } else {
            removeOnPageChangeListener(onPageChangeListener)
        }
    }

    private var animationDuration = 0L
    private var animator: ValueAnimator? = null

    constructor (context: Context) : super(context) {
        init(context, null)
    }

    constructor (context: Context, attrs: AttributeSet?) : super(context, attrs) {
        init(context, attrs)
    }

    private fun init(context: Context, attrs: AttributeSet?) {
        context.theme.obtainStyledAttributes(
            attrs,
            R.styleable.ViewPager,
            0,
            0
        ).apply {
            try {
                enableAnimation = getBoolean(
                    R.styleable.ViewPager_enableAnimation,
                    enableAnimation
                )
                animationDuration = getInteger(
                    R.styleable.ViewPager_animationDuration,
                    resources.getInteger(android.R.integer.config_shortAnimTime)
                ).toLong()
            } finally {
                recycle()
            }
        }
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val heightMode = MeasureSpec.getMode(heightMeasureSpec)

        val measuredHeight = if (heightMode == MeasureSpec.EXACTLY) {
            MeasureSpec.getSize(heightMeasureSpec)
        } else {
            val currentViewHeight = findViewByPosition(currentItem)?.also {
                measureView(it)
            }?.measuredHeight ?: 0

            if (heightMode != MeasureSpec.AT_MOST) {
                currentViewHeight
            } else {
                Math.min(
                    currentViewHeight,
                    MeasureSpec.getSize(heightMeasureSpec)
                )
            }
        }

        super.onMeasure(
            widthMeasureSpec,
            MeasureSpec.makeMeasureSpec(measuredHeight, MeasureSpec.EXACTLY)
        )
    }

    private fun measureView(view: View) = with(view) {
        val horizontalMode: Int
        val horizontalSize: Int
        when (layoutParams.width) {
            MATCH_PARENT -> {
                horizontalMode = MeasureSpec.EXACTLY
                horizontalSize = this@ViewPager.measuredWidth
            }
            WRAP_CONTENT -> {
                horizontalMode = MeasureSpec.UNSPECIFIED
                horizontalSize = 0
            }
            else -> {
                horizontalMode = MeasureSpec.EXACTLY
                horizontalSize = layoutParams.width
            }
        }

        val verticalMode: Int
        val verticalSize: Int
        when (layoutParams.height) {
            MATCH_PARENT -> {
                verticalMode = MeasureSpec.EXACTLY
                verticalSize = this@ViewPager.measuredHeight
            }
            WRAP_CONTENT -> {
                verticalMode = MeasureSpec.UNSPECIFIED
                verticalSize = 0
            }
            else -> {
                verticalMode = MeasureSpec.EXACTLY
                verticalSize = layoutParams.height
            }
        }

        val horizontalMeasureSpec = MeasureSpec.makeMeasureSpec(horizontalSize, horizontalMode)
        val verticalMeasureSpec = MeasureSpec.makeMeasureSpec(verticalSize, verticalMode)

        measure(horizontalMeasureSpec, verticalMeasureSpec)
    }

    private fun findViewByPosition(position: Int): View? {
        for (i in 0 until childCount) {
            val childView = getChildAt(i)
            val childLayoutParams = childView.layoutParams as LayoutParams

            val childPosition by lazy {
                val field = childLayoutParams.javaClass.getDeclaredField("position")
                field.isAccessible = true
                field.get(childLayoutParams) as Int
            }

            if (!childLayoutParams.isDecor && position == childPosition) {
                return childView
            }
        }

        return null
    }

    private fun animateContentHeight(childView: View, fromHeight: Int, toHeight: Int) {
        animator?.cancel()

        if (fromHeight == toHeight) {
            return
        }

        animator = ValueAnimator.ofInt(fromHeight, toHeight).apply {
            addUpdateListener {
                measureView(childView)
                if (childView.measuredHeight != toHeight) {
                    animateContentHeight(childView, height, childView.measuredHeight)
                } else {
                    layoutParams.height = animatedValue as Int
                    requestLayout()
                }
            }
            duration = animationDuration
            start()
        }
    }

    private val onPageChangeListener = object : OnPageChangeListener {

        override fun onPageScrollStateChanged(state: Int) {
            /* do nothing */
        }

        override fun onPageScrolled(
            position: Int,
            positionOffset: Float,
            positionOffsetPixels: Int
        ) {
            /* do nothing */
        }

        override fun onPageSelected(position: Int) {
            if (!isAttachedToWindow) {
                return
            }

            findViewByPosition(position)?.let { childView ->
                measureView(childView)
                animateContentHeight(childView, height, childView.measuredHeight)
            }
        }
    }
}

प्रोजेक्ट में attrs.xml जोड़ें:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="ViewPager">
        <attr name="enableAnimation" format="boolean" />
        <attr name="animationDuration" format="integer" />
    </declare-styleable>
</resources>

और उपयोग करें:

<one.xcorp.widget.ViewPager
    android:id="@+id/wt_content"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:enableAnimation="true" />

0

यह ViewPager केवल वर्तमान दृश्यमान बच्चों (इसके वास्तविक बच्चों में से सबसे बड़ा नहीं) का आकार बदलता है

Https://stackoverflow.com/a/56325869/4718406 से विचार

public class DynamicHeightViewPager extends ViewPager {

public DynamicHeightViewPager (Context context) {
    super(context);
    initPageChangeListener();
}

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



private void initPageChangeListener() {
    addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
        @Override
        public void onPageSelected(int position) {
            requestLayout();
        }
    });
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    //View child = getChildAt(getCurrentItem());
    View child = getCurrentView(this);
    if (child != null) {
        child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, 
         MeasureSpec.UNSPECIFIED));
        int h = child.getMeasuredHeight();

        heightMeasureSpec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY);
    }
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}


View getCurrentView(ViewPager viewPager) {
    try {
        final int currentItem = viewPager.getCurrentItem();
        for (int i = 0; i < viewPager.getChildCount(); i++) {
            final View child = viewPager.getChildAt(i);
            final ViewPager.LayoutParams layoutParams = (ViewPager.LayoutParams) 
             child.getLayoutParams();

            Field f = layoutParams.getClass().getDeclaredField("position"); 
            //NoSuchFieldException
            f.setAccessible(true);
            int position = (Integer) f.get(layoutParams); //IllegalAccessException

            if (!layoutParams.isDecor && currentItem == position) {
                return child;
            }
        }
    } catch (NoSuchFieldException e) {
        e.fillInStackTrace();
    } catch (IllegalArgumentException e) {
        e.fillInStackTrace();
    } catch (IllegalAccessException e) {
        e.fillInStackTrace();
    }
    return null;
}

}


0

ViewPager की ऊंचाई को मापें:

public class WrapViewPager extends ViewPager {
    View primaryView;

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (primaryView != null) {
            int height = 0;
            for (int i = 0; i < getChildCount(); i++) {
                if (primaryView == getChildAt(i)) {
                    int childHeightSpec = MeasureSpec.makeMeasureSpec(0x1 << 30 - 1, MeasureSpec.AT_MOST);
                    getChildAt(i).measure(widthMeasureSpec, childHeightSpec);
                    height = getChildAt(i).getMeasuredHeight();
                }

            }

            setMeasuredDimension(widthMeasureSpec, MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));
        }
    }

    public void setPrimaryView(View view) {
        primaryView = view;
    }

}

कॉल सेटप्रीमरी व्यू (देखें) View

public class ZGAdapter extends PagerAdapter {

    @Override
    public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
        super.setPrimaryItem(container, position, object);
        ((WrapViewPager)container).setPrimaryView((View)object);
    }

}

0

ViewPager के मूल लेआउट के रूप में दे NestedScrollView

   <androidx.core.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="5dp"
    android:paddingRight="5dp"
    android:fillViewport="true">
        <androidx.viewpager.widget.ViewPager
            android:id="@+id/viewPager"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
        </androidx.viewpager.widget.ViewPager>
    </androidx.core.widget.NestedScrollView>

सेट करने के लिए मत भूलना android:fillViewport="true"

यह व्यूपोर्ट भरने के लिए स्क्रॉलव्यू और उसके बच्चे की सामग्री को बढ़ाएगा।

https://developer.android.com/reference/android/widget/ScrollView.html#attr_android:fillViewport


0

आप ViewPager2 पर स्विच कर सकते हैं। यह ViewPager का एक अद्यतन संस्करण है। यह ViewPager के रूप में एक ही बात करता है, लेकिन एक चालाक और कुशल तरीके से। ViewPager2 कई नई सुविधाओं के साथ आता है। बेशक लपेट सामग्री विषय ViewPager2 द्वारा हल किया गया है।

Android डॉक्स से: "ViewPager2 अपने पूर्ववर्ती के अधिकांश दर्द-बिंदुओं को संबोधित करते हुए ViewPager को बदल देता है, जिसमें दाएं-से-बाएं लेआउट समर्थन, ऊर्ध्वाधर अभिविन्यास, संशोधित फ़्रैगमेंट संग्रह, आदि शामिल हैं"

मैं इस लेख को शुरुआती लोगों के लिए सुझाता हूं:

https://medium.com/google-developer-experts/exploring-the-view-pager-2-86dbce06ff71


यह समस्या अभी भी जारी करने वाला है। checketracker.google.com/u/0/issues/143095219
सोमेश कुमार
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.