অ্যান্ড্রয়েডের জন্য লাইন-ব্রেকিং উইজেট বিন্যাস


100

আমি এমন একটি ক্রিয়াকলাপ তৈরি করার চেষ্টা করছি যা ব্যবহারকারীর কাছে কিছু ডেটা উপস্থাপন করে। ডেটা এমন যে এটিকে 'শব্দের' মধ্যে বিভক্ত করা যেতে পারে, প্রতিটিই একটি উইজেট এবং শব্দগুলির অনুক্রমের ফলে শব্দগুলি সমন্বিত ভিউগ্রুপ উইজেট ডেটা তৈরি হয় ('বাক্য'?)। যেহেতু একটি "বাক্য" তে সমস্ত 'শব্দের' জন্য প্রয়োজনীয় স্থানটি ডিসপ্লেতে উপলব্ধ অনুভূমিক স্থানকে ছাড়িয়ে যাবে, আমি এই 'বাক্যগুলি' মোড়ানো চাই আপনি যেমন পাঠ্যের একটি সাধারণ টুকরো।

নিম্নলিখিত কোড:

public class WrapTest extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        LinearLayout l = new LinearLayout(this);
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.FILL_PARENT,
                LinearLayout.LayoutParams.WRAP_CONTENT);
        LinearLayout.LayoutParams mlp = new LinearLayout.LayoutParams(
                new ViewGroup.MarginLayoutParams(
                        LinearLayout.LayoutParams.WRAP_CONTENT,
                        LinearLayout.LayoutParams.WRAP_CONTENT));
        mlp.setMargins(0, 0, 2, 0);

        for (int i = 0; i < 10; i++) {
            TextView t = new TextView(this);
            t.setText("Hello");
            t.setBackgroundColor(Color.RED);
            t.setSingleLine(true);
            l.addView(t, mlp);
        }

        setContentView(l, lp);
    }
}

বাম ছবির মতো কিছু পাওয়া যায় তবে আমি ডান চিত্রের মতো একই উইজেট উপস্থাপন করতে চাই একটি লেআউট চাই।

মোড়ক না

মোড়ানো

লেআউট এবং পরামিতিগুলির এমন কোনও বিন্যাস বা সংমিশ্রণ রয়েছে, বা এর জন্য আমাকে কি আমার নিজস্ব ভিউগ্রুপ বাস্তবায়ন করতে হবে?

উত্তর:


46

মে ২০১ 2016 সাল থেকে গুগল থেকে ফ্লেক্সবক্সলআউট নামে একটি নতুন লেআউট রয়েছে যা আপনি যে উদ্দেশ্যে চান তার জন্য অত্যন্ত কনফিগারযোগ্য।

এই মুহুর্তে https://github.com/google/flexbox-layout এ গুগল গিটহাবের সংগ্রহস্থলে ফ্লেক্সবক্সলআউট রয়েছে ।

আপনি আপনার build.gradleফাইলের উপর নির্ভরতা যুক্ত করে এটি আপনার প্রকল্পে ব্যবহার করতে পারেন :

dependencies {
    compile 'com.google.android:flexbox:0.3.2'
}

ফ্লেক্সবক্সলআউট ব্যবহার এবং রেপোজিটরি রিডমে বা মার্ক অ্যালিসন নিবন্ধগুলিতে আপনি এখানে পেতে পারেন এমন সমস্ত বৈশিষ্ট্য সম্পর্কে আরও জানুন:

https://blog.stylingandroid.com/flexboxlayout-part-1/

https://blog.stylingandroid.com/flexboxlayout-part2/

https://blog.stylingandroid.com/flexboxlayout-part-3/


10
মিষ্টি, এটি ঠিক 7 বছর আগে আমার যা প্রয়োজন ছিল ঠিক তার মতো দেখে মনে হয় :)
হেনরিক গুস্তাফসন

অন্যান্য লাইব্রেরির উপর নির্ভর না করে আমার দিন বাঁচিয়েছে !!
মেহুল জোয়েসার

@ লুকাস- আমি রেডিও গ্রুপের জন্য একই ব্যবহার করছি, ইউআই ঠিকঠাক কাজ করছে তবে রেডিও গ্রুপের কার্যকারিতা বিরক্ত। মানে, একই রেডিও গ্রুপে, আমি একাধিক রেডিও বোতামগুলিতে টিক দিতে পারি। আমি একই সাথে কেবল একটি রেডিও বোতাম চেক করতে চাই। এই জন্য সাহায্য করুন।
রাহুল পাটিদার

এটি একটি মাথা আপ এটি কোনও স্ক্রোলিং পাত্রে কাজ করে না! :(
জ্যাকউইলসন 801

@ জ্যাকউইলসন ৮০১ এটি আমার জন্য স্ক্রোলিং ধারক হিসাবে কাজ করেছিল। তবে এখন রিসাইক্লারভিউতে ফ্লেক্সবক্সলআউটআউট ম্যানেজার রয়েছে , সুতরাং এটি আপনার সমস্যার সমাধান করতে পারে।
লুকাশ নোভাক

95

আমি আমার নিজস্ব লেআউট তৈরি করেছি যা আমি যা চাই তা করি তবে এই মুহূর্তে এটি বেশ সীমাবদ্ধ। মন্তব্য এবং উন্নতি পরামর্শ অবশ্যই স্বাগত।

কার্যক্রম:

package se.fnord.xmms2.predicate;

import se.fnord.android.layout.PredicateLayout;
import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.widget.TextView;

public class Predicate extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        PredicateLayout l = new PredicateLayout(this);
        for (int i = 0; i < 10; i++) {
            TextView t = new TextView(this);
            t.setText("Hello");
            t.setBackgroundColor(Color.RED);
            t.setSingleLine(true);
            l.addView(t, new PredicateLayout.LayoutParams(2, 0));
        }

        setContentView(l);
    }
}

বা একটি এক্সএমএল লেআউটে:

<se.fnord.android.layout.PredicateLayout
    android:id="@+id/predicate_layout"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content"
/>

এবং লেআউট:

package se.fnord.android.layout;

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

/**
 * ViewGroup that arranges child views in a similar way to text, with them laid
 * out one line at a time and "wrapping" to the next line as needed.
 * 
 * Code licensed under CC-by-SA
 *  
 * @author Henrik Gustafsson
 * @see http://stackoverflow.com/questions/549451/line-breaking-widget-layout-for-android
 * @license http://creativecommons.org/licenses/by-sa/2.5/
 *
 */
public class PredicateLayout extends ViewGroup {

    private int line_height;

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

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        assert(MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED);

        final int width = MeasureSpec.getSize(widthMeasureSpec);

        // The next line is WRONG!!! Doesn't take into account requested MeasureSpec mode!
        int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom();
        final int count = getChildCount();
        int line_height = 0;

        int xpos = getPaddingLeft();
        int ypos = getPaddingTop();

        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() != GONE) {
                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
                child.measure(
                        MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
                        MeasureSpec.makeMeasureSpec(height, MeasureSpec.UNSPECIFIED));

                final int childw = child.getMeasuredWidth();
                line_height = Math.max(line_height, child.getMeasuredHeight() + lp.height);

                if (xpos + childw > width) {
                    xpos = getPaddingLeft();
                    ypos += line_height;
                }

                xpos += childw + lp.width;
            }
        }
        this.line_height = line_height;

        if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED){
            height = ypos + line_height;

        } else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST){
            if (ypos + line_height < height){
                height = ypos + line_height;
            }
        }
        setMeasuredDimension(width, height);
    }

    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(1, 1); // default of 1px spacing
    }

    @Override
    protected boolean checkLayoutParams(LayoutParams p) {
        return (p instanceof LayoutParams);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        final int count = getChildCount();
        final int width = r - l;
        int xpos = getPaddingLeft();
        int ypos = getPaddingTop();

        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() != GONE) {
                final int childw = child.getMeasuredWidth();
                final int childh = child.getMeasuredHeight();
                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
                if (xpos + childw > width) {
                    xpos = getPaddingLeft();
                    ypos += line_height;
                }
                child.layout(xpos, ypos, xpos + childw, ypos + childh);
                xpos += childw + lp.width;
            }
        }
    }
}

ফলাফল সহ:

মোড়ানো উইজেটস


আমি কেবল এটি প্রোগ্রামিয়ালি করেছি কারণ ধারণাটি যোগাযোগের জন্য এটি পেস্ট করা অনেক কম :)
হেনরিক গুস্তাফসন

সাইটটি আমাকে সম্মত করেছে যে "ব্যবহারকারী সিসি-উইকির অধীন লাইসেন্সযুক্ত সামগ্রীর অবদানের জন্য প্রয়োজনীয় অবদান রেখেছেন", তাই ... বিস্তারিত জানার জন্য নীচে চেক করুন
হেনরিক গুস্তাফসন

8
কোনও কারণে অ্যান্ড্রয়েড লেআউট সম্পাদকটিতে ভিউ স্ফীত করার চেষ্টা করার সময় আমি "ক্লাসকাস্টএক্সসেপশন অ্যান্ড্রয়েড.ভিউ.ভিউ এন্ড্রয়েড.ভিউ.ভিউগ্রুপে কাস্ট করা যায় না" getting এটি ঠিক করার জন্য কোনও ধারণা?
twig

4
যারা এই উত্তরটি নিয়ে আসে - অনম্যাসার () এ কিছু খারাপ যুক্তি রয়েছে এবং প্রত্যাশার মতো কাজ করবে না। কল্পনা করুন যে এই ভিউগ্রুপের পিতামাতার একটি পরিমাপের অনুরোধ প্রেরণ করে যেখানে এটি উচ্চতার বিষয়ে চিন্তা করে না, এটি 0 উচ্চতা হিসাবে এবং 0 পরিমাপের মোড হিসাবে প্রেরণ করবে। প্রিডিকেট লেআউটটি তার নিজস্ব উচ্চতা হিসাবে 0 পাবে এবং বাচ্চাদের AT_MOST 0 উচ্চতা হতে বাধ্য করবে।
devmiles.com

4
কোডটিতে মন্তব্য যুক্ত করার পরিবর্তে, আপনি কেবল ত্রুটিটি সংশোধন করতে পারবেন না? :)
হেনরিক গুস্তাফসন

43

আমি এর সাথে খুব সামঞ্জস্যপূর্ণ কিছু বাস্তবায়ন করেছি তবে আমি যা মনে করি তা ব্যবহার করে ব্যবধান এবং প্যাডিং পরিচালনা করার জন্য আরও কিছু স্ট্যান্ডার্ড উপায়। দয়া করে আমাকে বলুন আপনি ছেলেরা কী ভাবছেন এবং নির্দ্বিধায় পুনরায় ব্যবহার করতে নির্দ্বিধায়:

package com.asolutions.widget;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

import com.asolutions.widget.R;

public class RowLayout extends ViewGroup {
    public static final int DEFAULT_HORIZONTAL_SPACING = 5;
    public static final int DEFAULT_VERTICAL_SPACING = 5;
    private final int horizontalSpacing;
    private final int verticalSpacing;
    private List<RowMeasurement> currentRows = Collections.emptyList();

    public RowLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray styledAttributes = context.obtainStyledAttributes(attrs, R.styleable.RowLayout);
        horizontalSpacing = styledAttributes.getDimensionPixelSize(R.styleable.RowLayout_android_horizontalSpacing,
                DEFAULT_HORIZONTAL_SPACING);
        verticalSpacing = styledAttributes.getDimensionPixelSize(R.styleable.RowLayout_android_verticalSpacing,
                DEFAULT_VERTICAL_SPACING);
        styledAttributes.recycle();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        final int maxInternalWidth = MeasureSpec.getSize(widthMeasureSpec) - getHorizontalPadding();
        final int maxInternalHeight = MeasureSpec.getSize(heightMeasureSpec) - getVerticalPadding();
        List<RowMeasurement> rows = new ArrayList<RowMeasurement>();
        RowMeasurement currentRow = new RowMeasurement(maxInternalWidth, widthMode);
        rows.add(currentRow);
        for (View child : getLayoutChildren()) {
            LayoutParams childLayoutParams = child.getLayoutParams();
            int childWidthSpec = createChildMeasureSpec(childLayoutParams.width, maxInternalWidth, widthMode);
            int childHeightSpec = createChildMeasureSpec(childLayoutParams.height, maxInternalHeight, heightMode);
            child.measure(childWidthSpec, childHeightSpec);
            int childWidth = child.getMeasuredWidth();
            int childHeight = child.getMeasuredHeight();
            if (currentRow.wouldExceedMax(childWidth)) {
                currentRow = new RowMeasurement(maxInternalWidth, widthMode);
                rows.add(currentRow);
            }
            currentRow.addChildDimensions(childWidth, childHeight);
        }

        int longestRowWidth = 0;
        int totalRowHeight = 0;
        for (int index = 0; index < rows.size(); index++) {
            RowMeasurement row = rows.get(index);
            totalRowHeight += row.getHeight();
            if (index < rows.size() - 1) {
                totalRowHeight += verticalSpacing;
            }
            longestRowWidth = Math.max(longestRowWidth, row.getWidth());
        }
        setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? MeasureSpec.getSize(widthMeasureSpec) : longestRowWidth
                + getHorizontalPadding(), heightMode == MeasureSpec.EXACTLY ? MeasureSpec.getSize(heightMeasureSpec)
                : totalRowHeight + getVerticalPadding());
        currentRows = Collections.unmodifiableList(rows);
    }

    private int createChildMeasureSpec(int childLayoutParam, int max, int parentMode) {
        int spec;
        if (childLayoutParam == LayoutParams.FILL_PARENT) {
            spec = MeasureSpec.makeMeasureSpec(max, MeasureSpec.EXACTLY);
        } else if (childLayoutParam == LayoutParams.WRAP_CONTENT) {
            spec = MeasureSpec.makeMeasureSpec(max, parentMode == MeasureSpec.UNSPECIFIED ? MeasureSpec.UNSPECIFIED
                    : MeasureSpec.AT_MOST);
        } else {
            spec = MeasureSpec.makeMeasureSpec(childLayoutParam, MeasureSpec.EXACTLY);
        }
        return spec;
    }

    @Override
    protected void onLayout(boolean changed, int leftPosition, int topPosition, int rightPosition, int bottomPosition) {
        final int widthOffset = getMeasuredWidth() - getPaddingRight();
        int x = getPaddingLeft();
        int y = getPaddingTop();

        Iterator<RowMeasurement> rowIterator = currentRows.iterator();
        RowMeasurement currentRow = rowIterator.next();
        for (View child : getLayoutChildren()) {
            final int childWidth = child.getMeasuredWidth();
            final int childHeight = child.getMeasuredHeight();
            if (x + childWidth > widthOffset) {
                x = getPaddingLeft();
                y += currentRow.height + verticalSpacing;
                if (rowIterator.hasNext()) {
                    currentRow = rowIterator.next();
                }
            }
            child.layout(x, y, x + childWidth, y + childHeight);
            x += childWidth + horizontalSpacing;
        }
    }

    private List<View> getLayoutChildren() {
        List<View> children = new ArrayList<View>();
        for (int index = 0; index < getChildCount(); index++) {
            View child = getChildAt(index);
            if (child.getVisibility() != View.GONE) {
                children.add(child);
            }
        }
        return children;
    }

    protected int getVerticalPadding() {
        return getPaddingTop() + getPaddingBottom();
    }

    protected int getHorizontalPadding() {
        return getPaddingLeft() + getPaddingRight();
    }

    private final class RowMeasurement {
        private final int maxWidth;
        private final int widthMode;
        private int width;
        private int height;

        public RowMeasurement(int maxWidth, int widthMode) {
            this.maxWidth = maxWidth;
            this.widthMode = widthMode;
        }

        public int getHeight() {
            return height;
        }

        public int getWidth() {
            return width;
        }

        public boolean wouldExceedMax(int childWidth) {
            return widthMode == MeasureSpec.UNSPECIFIED ? false : getNewWidth(childWidth) > maxWidth;
        }

        public void addChildDimensions(int childWidth, int childHeight) {
            width = getNewWidth(childWidth);
            height = Math.max(height, childHeight);
        }

        private int getNewWidth(int childWidth) {
            return width == 0 ? childWidth : width + horizontalSpacing + childWidth;
        }
    }
}

এটির জন্য /res/values/attrs.xML এর অধীনে একটি এন্ট্রিও দরকার, যা এটি ইতিমধ্যে সেখানে না থাকলে আপনি তৈরি করতে পারেন।

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="RowLayout">
        <attr name="android:verticalSpacing" />
        <attr name="android:horizontalSpacing" />
    </declare-styleable>
</resources>

একটি এক্সএমএল লেআউটে ব্যবহারের চেহারা দেখতে এটি:

<?xml version="1.0" encoding="utf-8"?>
<com.asolutions.widget.RowLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:padding="10dp"
    android:horizontalSpacing="10dp"
    android:verticalSpacing="20dp">
    <FrameLayout android:layout_width="30px" android:layout_height="40px" android:background="#F00"/>
    <FrameLayout android:layout_width="60px" android:layout_height="40px" android:background="#F00"/>
    <FrameLayout android:layout_width="70px" android:layout_height="20px" android:background="#F00"/>
    <FrameLayout android:layout_width="20px" android:layout_height="60px" android:background="#F00"/>
    <FrameLayout android:layout_width="10px" android:layout_height="40px" android:background="#F00"/>
    <FrameLayout android:layout_width="40px" android:layout_height="40px" android:background="#F00"/>
    <FrameLayout android:layout_width="40px" android:layout_height="40px" android:background="#F00"/>
    <FrameLayout android:layout_width="40px" android:layout_height="40px" android:background="#F00"/>
</com.asolutions.widget.RowLayout>

আমি এটি ব্যবহার করছি। আমি এই লেআউটে আইটেমগুলি গতিশীলভাবে যুক্ত করছি। এটি যুক্ত হয়ে যায় তবে প্রতিটি দৃষ্টিভঙ্গি ছোট বলার উপায়। কেন?
উমায়ের এ।

4
এক্সএমএলে লেআউট এবং শিশুদের ঘোষণা দিয়ে এটি আমার পক্ষে নিখুঁতভাবে কাজ করছে। ধন্যবাদ!
ডেভিড স্নাবেল-কাউন্ট

4
আমার জন্য কাজ করে। মাইকা ভালো কাজ! এই সমাধান ভাগ করে নেওয়ার জন্য ধন্যবাদ!
মার্সেলো

আমি যে সকল সমাধানের চেষ্টা করেছি তার মধ্যে, এটিই কেবলমাত্র একটি এক্সএমএল লেআউট ফাইল থেকে ব্যবহার করার সময় একটি ক্লাসকাস্টএক্সসেপশনকে ছড়িয়ে দেয়নি।
mdelolmo

এই সমাধান পোস্ট করার জন্য ধন্যবাদ! ঠিক যেটা আমার দরকার ছিল; আমার সময় বাঁচিয়েছে
জুলিয়ানসাইমস


11

এখানে আমার সরলীকৃত, কোড-কেবল সংস্করণ:

    package com.superliminal.android.util;

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


    /**
     * A view container with layout behavior like that of the Swing FlowLayout.
     * Originally from http://nishantvnair.wordpress.com/2010/09/28/flowlayout-in-android/ itself derived from
     * http://stackoverflow.com/questions/549451/line-breaking-widget-layout-for-android
     *
     * @author Melinda Green
     */
    public class FlowLayout extends ViewGroup {
        private final static int PAD_H = 2, PAD_V = 2; // Space between child views.
        private int mHeight;

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

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

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            assert (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED);
            final int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();
            int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom();
            final int count = getChildCount();
            int xpos = getPaddingLeft();
            int ypos = getPaddingTop();
            int childHeightMeasureSpec;
            if(MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST)
                childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
            else
                childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
            mHeight = 0;
            for(int i = 0; i < count; i++) {
                final View child = getChildAt(i);
                if(child.getVisibility() != GONE) {
                    child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), childHeightMeasureSpec);
                    final int childw = child.getMeasuredWidth();
                    mHeight = Math.max(mHeight, child.getMeasuredHeight() + PAD_V);
                    if(xpos + childw > width) {
                        xpos = getPaddingLeft();
                        ypos += mHeight;
                    }
                    xpos += childw + PAD_H;
                }
            }
            if(MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED) {
                height = ypos + mHeight;
            } else if(MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
                if(ypos + mHeight < height) {
                    height = ypos + mHeight;
                }
            }
            height += 5; // Fudge to avoid clipping bottom of last row.
            setMeasuredDimension(width, height);
        } // end onMeasure()

        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            final int width = r - l;
            int xpos = getPaddingLeft();
            int ypos = getPaddingTop();
            for(int i = 0; i < getChildCount(); i++) {
                final View child = getChildAt(i);
                if(child.getVisibility() != GONE) {
                    final int childw = child.getMeasuredWidth();
                    final int childh = child.getMeasuredHeight();
                    if(xpos + childw > width) {
                        xpos = getPaddingLeft();
                        ypos += mHeight;
                    }
                    child.layout(xpos, ypos, xpos + childw, ypos + childh);
                    xpos += childw + PAD_H;
                }
            }
        } // end onLayout()

    }

আমি বিন্যাসে একটি ভিউ যুক্ত করেছি এবং ক্লাসটিকে সেই নামটি দিয়েছি এবং তারপরে সেই ভিউটিতে চাইল্ড বোতাম যুক্ত করেছি। তবে তাদের উচ্চতা কি আমি নিয়ন্ত্রণ করতে পারি না? তারা সকলেই দেখতে চাই না এমন প্যাডিং শীর্ষ / নীচে রয়েছে have
মিগুয়েল

আপনি PAD_V = 0 সেট করতে পারেন, বা প্যাডিং কাস্টমাইজ করতে কনস্ট্রাক্টর আর্গুমেন্ট যুক্ত করতে পারেন।
মেলিন্ডা সবুজ

7

প্রথম উত্তরটি নিয়ে একটি সমস্যা রয়েছে:

child.measure(
    MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
    MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST));

একটি তালিকাভিউতে, উদাহরণস্বরূপ, তালিকার আইটেমগুলি 0 (UNSPECIFIED) এর উচ্চতা ম্যাসারস্পেকটি পাস হয় এবং সুতরাং, 0 আকারের (AT_MOST) মেজারস্পেকটি সমস্ত শিশুকে দেওয়া হয়। এর অর্থ হ'ল পুরো প্রিডিকেটআলআউট অদৃশ্য (উচ্চতা 0)।

দ্রুত স্থির হিসাবে, আমি সন্তানের উচ্চতা ম্যাসারস্পেককে এভাবে পরিবর্তন করেছি:

int childHeightMeasureSpec;
if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
    childHeightMeasureSpec =
        MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
}
else {
    childHeightMeasureSpec = 
        MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);            
}

এবং তারপর

child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), 
    childHeightMeasureSpec);

যা আমার পক্ষে কাজ করে বলে মনে হচ্ছে যদিও ঠিক মোডটি পরিচালনা করে না যা অনেক বেশি জটিল trick


4
লেআউটটি যখন একটি স্ক্রোলভিউতে রাখা হয় তখন এটি সমস্যার সমাধান করে। এটি সমাধান করার জন্য ধন্যবাদ তাই আমাকে নিজের জন্য এটি ব্যবহার করতে হবে না।
skorulis

4

আমার সামান্য পরিবর্তিত সংস্করণ এখানে পোস্টের উপর ভিত্তি করে:

  • এটি Eclipse লেআউট এডিটরে কাজ করে
  • এটি সমস্ত আইটেমকে অনুভূমিকভাবে কেন্দ্র করে

    import android.content.Context;
    import android.util.AttributeSet;
    import android.view.View;
    import android.view.ViewGroup;
    
    public class FlowLayout extends ViewGroup {
    
    private int line_height;
    
    public static class LayoutParams extends ViewGroup.LayoutParams {
    
        public final int horizontal_spacing;
        public final int vertical_spacing;
    
        /**
         * @param horizontal_spacing Pixels between items, horizontally
         * @param vertical_spacing Pixels between items, vertically
         */
        public LayoutParams(int horizontal_spacing, int vertical_spacing, ViewGroup.LayoutParams viewGroupLayout) {
            super(viewGroupLayout);
            this.horizontal_spacing = horizontal_spacing;
            this.vertical_spacing = vertical_spacing;
        }
    
        /**
         * @param horizontal_spacing Pixels between items, horizontally
         * @param vertical_spacing Pixels between items, vertically
         */
        public LayoutParams(int horizontal_spacing, int vertical_spacing) {
            super(0, 0);
            this.horizontal_spacing = horizontal_spacing;
            this.vertical_spacing = vertical_spacing;
        }
    }
    
    public FlowLayout(Context context) {
        super(context);
    }
    
    public FlowLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        assert (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED);
    
        final int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();
        int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom();
        final int count = getChildCount();
        int line_height = 0;
    
        int xpos = getPaddingLeft();
        int ypos = getPaddingTop();
    
        int childHeightMeasureSpec;
        if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
            childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
        } else {
            childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        }
    
    
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() != GONE) {
                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
                child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), childHeightMeasureSpec);
                final int childw = child.getMeasuredWidth();
                line_height = Math.max(line_height, child.getMeasuredHeight() + lp.vertical_spacing);
    
                if (xpos + childw > width) {
                    xpos = getPaddingLeft();
                    ypos += line_height;
                }
    
                xpos += childw + lp.horizontal_spacing;
            }
        }
        this.line_height = line_height;
    
        if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED) {
            height = ypos + line_height;
    
        } else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
            if (ypos + line_height < height) {
                height = ypos + line_height;
            }
        }
        setMeasuredDimension(width, height);
    }
    
    @Override
    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(1, 1); // default of 1px spacing
    }
    
    @Override
    protected android.view.ViewGroup.LayoutParams generateLayoutParams(
            android.view.ViewGroup.LayoutParams p) {
        return new LayoutParams(1, 1, p);
    }
    
    @Override
    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
        if (p instanceof LayoutParams) {
            return true;
        }
        return false;
    }
    
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        final int count = getChildCount();
        final int width = r - l;
        int xpos = getPaddingLeft();
        int ypos = getPaddingTop();
    
        int lastHorizontalSpacing = 0;
        int rowStartIdx = 0;
    
        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() != GONE) {
                final int childw = child.getMeasuredWidth();
                final int childh = child.getMeasuredHeight();
                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
                if (xpos + childw > width) {
                    final int freeSpace = width - xpos + lastHorizontalSpacing;
                    xpos = getPaddingLeft() + freeSpace / 2;
    
                    for (int j = rowStartIdx; j < i; ++j) {
                        final View drawChild = getChildAt(j);
                        drawChild.layout(xpos, ypos, xpos + drawChild.getMeasuredWidth(), ypos + drawChild.getMeasuredHeight());
                        xpos += drawChild.getMeasuredWidth() + ((LayoutParams)drawChild.getLayoutParams()).horizontal_spacing;
                    }
    
                    lastHorizontalSpacing = 0;
                    xpos = getPaddingLeft();
                    ypos += line_height;
                    rowStartIdx = i;
                } 
    
                child.layout(xpos, ypos, xpos + childw, ypos + childh);
                xpos += childw + lp.horizontal_spacing;
                lastHorizontalSpacing = lp.horizontal_spacing;
            }
        }
    
        if (rowStartIdx < count) {
            final int freeSpace = width - xpos + lastHorizontalSpacing;
            xpos = getPaddingLeft() + freeSpace / 2;
    
            for (int j = rowStartIdx; j < count; ++j) {
                final View drawChild = getChildAt(j);
                drawChild.layout(xpos, ypos, xpos + drawChild.getMeasuredWidth(), ypos + drawChild.getMeasuredHeight());
                xpos += drawChild.getMeasuredWidth() + ((LayoutParams)drawChild.getLayoutParams()).horizontal_spacing;
            }
        }
    }
    }
    

3

আমি বাগটি ঠিক করতে এই নমুনাটি আপডেট করেছি, এখন, প্রতিটি লাইনের আলাদা উচ্চতা থাকতে পারে!

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

/**
 * ViewGroup that arranges child views in a similar way to text, with them laid
 * out one line at a time and "wrapping" to the next line as needed.
 * 
 * Code licensed under CC-by-SA
 *  
 * @author Henrik Gustafsson
 * @see http://stackoverflow.com/questions/549451/line-breaking-widget-layout-for-android
 * @license http://creativecommons.org/licenses/by-sa/2.5/
 *
 * Updated by Aurélien Guillard
 * Each line can have a different height
 * 
 */
public class FlowLayout extends ViewGroup {

    public static class LayoutParams extends ViewGroup.LayoutParams {

        public final int horizontal_spacing;
        public final int vertical_spacing;

        /**
         * @param horizontal_spacing Pixels between items, horizontally
         * @param vertical_spacing Pixels between items, vertically
         */
        public LayoutParams(int horizontal_spacing, int vertical_spacing) {
            super(0, 0);
            this.horizontal_spacing = horizontal_spacing;
            this.vertical_spacing = vertical_spacing;
        }
    }

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

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        assert (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED);

        final int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();

        int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom();
        final int count = getChildCount();
        int line_height = 0;

        int xpos = getPaddingLeft();
        int ypos = getPaddingTop();

        int childHeightMeasureSpec;

        if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
            childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);

        } else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) {
            childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);

        } else {
            childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
        }

        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() != GONE) {
                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
                child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), childHeightMeasureSpec);
                final int childw = child.getMeasuredWidth();

                if (xpos + childw > width) {
                    xpos = getPaddingLeft();
                    ypos += line_height;
                }

                xpos += childw + lp.horizontal_spacing;
                line_height = child.getMeasuredHeight() + lp.vertical_spacing;
            }
        }

        if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED) {
            height = ypos + line_height;

        } else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
            if (ypos + line_height < height) {
                height = ypos + line_height;
            }
        }
        setMeasuredDimension(width, height);
    }

    @Override
    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(1, 1); // default of 1px spacing
    }

    @Override
    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
        if (p instanceof LayoutParams) {
            return true;
        }
        return false;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        final int count = getChildCount();
        final int width = r - l;
        int xpos = getPaddingLeft();
        int ypos = getPaddingTop();
        int lineHeight = 0;

        for (int i = 0; i < count; i++) {
            final View child = getChildAt(i);
            if (child.getVisibility() != GONE) {
                final int childw = child.getMeasuredWidth();
                final int childh = child.getMeasuredHeight();
                final LayoutParams lp = (LayoutParams) child.getLayoutParams();

                if (xpos + childw > width) {
                    xpos = getPaddingLeft();
                    ypos += lineHeight;
                }

                lineHeight = child.getMeasuredHeight() + lp.vertical_spacing;

                child.layout(xpos, ypos, xpos + childw, ypos + childh);
                xpos += childw + lp.horizontal_spacing;
            }
        }
    }
}

1

এখানে কিছু ভিন্ন উত্তর আমাকে এক্সক্লিপস লেআউট সম্পাদকের একটি ক্লাসকাস্টএক্সপশন দেবে । আমার ক্ষেত্রে, আমি নিজের তৈরি করার চেয়ে ভিউগ্রুপ.মার্জিন লেআউটপ্যারাম ব্যবহার করতে চেয়েছিলাম। যে কোনও উপায়ে, আপনার কাস্টম বিন্যাস শ্রেণীর জেনারেট লেআউটপ্যারামগুলিতে প্রয়োজনীয় লেআউটপ্যারামগুলির উদাহরণটি ফিরে আসার বিষয়টি নিশ্চিত করুন। আমার দেখতে দেখতে এটি দেখতে ঠিক তাই, আপনার ভিউগ্রুপের প্রয়োজনের সাথে কেবল মার্জিনলাউটপ্যারামগুলি প্রতিস্থাপন করুন:

@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
    return new MarginLayoutParams(getContext(), attrs);
}

@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
    return p instanceof MarginLayoutParams;
}

দেখে মনে হচ্ছে যে এই পদ্ধতিটি ভিউগ্রুপের প্রতিটি সন্তানের জন্য একটি লেআউটপ্যারামস অবজেক্ট বরাদ্দ করার জন্য ডেকে আনা হয়েছে।


1
    LinearLayout row = new LinearLayout(this);

    //get the size of the screen
    Display display = getWindowManager().getDefaultDisplay();
    this.screenWidth = display.getWidth();  // deprecated

    for(int i=0; i<this.users.length; i++) {

        row.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));

        this.tag_button = new Button(this);
        this.tag_button.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, 70));
        //get the size of the button text
        Paint mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setTextSize(tag_button.getTextSize());
        mPaint.setTypeface(Typeface.create(Typeface.SERIF, Typeface.NORMAL));
        float size = mPaint.measureText(tag_button.getText().toString(), 0, tag_button.getText().toString().length());
        size = size+28;
        this.totalTextWidth += size;

        if(totalTextWidth < screenWidth) {
            row.addView(tag_button);
        } else {
            this.tags.addView(row);
            row = new LinearLayout(this);
            row.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
            row.addView(tag_button);
            this.totalTextWidth = size;
        }
    }

1

আমি উপরের কয়েকটি ওডকে অভিযোজিত করেছি এবং একটি প্রবাহ বিন্যাস প্রয়োগ করেছি যা সমস্ত শিশু দৃষ্টিভঙ্গি, অনুভূমিক এবং উল্লম্বকে কেন্দ্র করে। এটি আমার প্রয়োজনের সাথে খাপ খায়।

public class CenteredFlowLayout extends ViewGroup {

  private int lineHeight;

  private int centricHeightPadding;

  private final int halfGap;

  public static final List<View> LINE_CHILDREN = new ArrayList<View>();

  public static class LayoutParams extends ViewGroup.LayoutParams {

    public final int horizontalSpacing;

    public final int verticalSpacing;

    public LayoutParams(int horizontalSpacing, int verticalSpacing) {
      super(0, 0);
      this.horizontalSpacing = horizontalSpacing;
      this.verticalSpacing = verticalSpacing;
    }
  }

  public CenteredFlowLayout(Context context) {
    super(context);
    halfGap = getResources().getDimensionPixelSize(R.dimen.half_gap);
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    final int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();
    int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom();
    final int maxHeight = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom();
    final int count = getChildCount();
    int lineHeight = 0;

    int xAxis = getPaddingLeft();
    int yAxis = getPaddingTop();

    int childHeightMeasureSpec;
    if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
      childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
    } else {
      childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
    }

    for (int i = 0; i < count; i++) {
      final View child = getChildAt(i);
      if (child.getVisibility() != GONE) {
        final CentricFlowLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
        child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), childHeightMeasureSpec);
        final int childMeasuredWidth = child.getMeasuredWidth();
        lineHeight = Math.max(lineHeight, child.getMeasuredHeight() + lp.verticalSpacing);

        if (xAxis + childMeasuredWidth > width) {
          xAxis = getPaddingLeft();
          yAxis += lineHeight;
        } else if (i + 1 == count) {
          yAxis += lineHeight;
        }

        xAxis += childMeasuredWidth + lp.horizontalSpacing;
      }
    }
    this.lineHeight = lineHeight;

    if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED) {
      height = yAxis + lineHeight;
    } else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
      if (yAxis + lineHeight < height) {
        height = yAxis + lineHeight;
      }
    }
    if (maxHeight == 0) {
      maxHeight = height + getPaddingTop();
    }
    centricHeightPadding = (maxHeight - height) / 2;
    setMeasuredDimension(width, disableCenterVertical ? height + getPaddingTop() : maxHeight);
  }

  @Override
  protected CentricFlowLayout.LayoutParams generateDefaultLayoutParams() {
    return new CentricFlowLayout.LayoutParams(halfGap, halfGap);
  }

  @Override
  protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
    if (p instanceof LayoutParams) {
      return true;
    }
    return false;
  }

  @Override
  protected void onLayout(boolean changed, int l, int t, int r, int b) {
    final int count = getChildCount();
    final int width = r - l;
    int yAxis = centricHeightPadding + getPaddingTop() + getPaddingBottom();
    View child;
    int measuredWidth;
    int lineWidth = getPaddingLeft() + getPaddingRight();
    CentricFlowLayout.LayoutParams lp;
    int offset;
    LINE_CHILDREN.clear();
    for (int i = 0; i < count; i++) {
      child = getChildAt(i);
      lp = (LayoutParams) child.getLayoutParams();
      if (GONE != child.getVisibility()) {
        measuredWidth = child.getMeasuredWidth();
        if (lineWidth + measuredWidth + lp.horizontalSpacing > width) {
          offset = (width - lineWidth) / 2;
          layoutHorizontalCentricLine(LINE_CHILDREN, offset, yAxis);
          lineWidth = getPaddingLeft() + getPaddingRight() + measuredWidth + lp.horizontalSpacing;
          yAxis += lineHeight;
          LINE_CHILDREN.clear();
          LINE_CHILDREN.add(child);
        } else {
          lineWidth += measuredWidth + lp.horizontalSpacing;
          LINE_CHILDREN.add(child);
        }
      }
    }
    offset = (width - lineWidth) / 2;
    layoutHorizontalCentricLine(LINE_CHILDREN, offset, yAxis);
  }

  private void layoutHorizontalCentricLine(final List<View> children, final int offset, final int yAxis) {
    int xAxis = getPaddingLeft() + getPaddingRight() + offset;
    for (View child : children) {
      final int measuredWidth = child.getMeasuredWidth();
      final int measuredHeight = child.getMeasuredHeight();
      final CentricFlowLayout.LayoutParams lp = (LayoutParams) child.getLayoutParams();
      child.layout(xAxis, yAxis, xAxis + measuredWidth, yAxis + measuredHeight);
      xAxis += measuredWidth + lp.horizontalSpacing;
    }
  }    
}


0

Lp এর লেআউটপ্যারাম দুটিই সেট করার চেষ্টা করুন WRAP_CONTENT

এমপিএলকে সেট করা WRAP_CONTENT, WRAP_CONTENTআপনার টেক্সটভিউ (গুলি) টি "হ্যালো" বা আপনি যে স্ট্রিংয়ের মধ্যে রেখেছেন তা যথেষ্ট প্রশস্ত এবং যথেষ্ট যথেষ্ট তা নিশ্চিত করে। আমি মনে করি আমি কিভাবে ব্যাপক আপনার সচেতন নাও হতে পারে টি 'র আছে। setSingleLine(true)খুব অবদান হতে পারে।


যতদূর আমি জানি, লিনিয়ারলআউট কোনও মোড়ক দেয় না। উভয় অক্ষের Wrap_CONTENT লিনিয়ারলআউট-উইজেটকে এক লাইন উঁচু করে তুলবে এবং স্ক্রিনের বাইরে যেতে হবে। এবং আমি যা বুঝতে পারি তা থেকে, পাঠ্য-উইজেটের সেটসাইনলাইন কেবলমাত্র সেই উইজেটের আকার এবং আকারকেই প্রভাবিত করে, এর পিতামাতার বিন্যাসকে নয়।
হেনরিক গুস্তাফসন

@ উইল, আমি মনে করি আপনি Wrap_CONTENT এর অর্থ ভুল বুঝেছেন।
jfritz42
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.