【问题标题】:Unable to find layout for following design找不到以下设计的布局
【发布时间】:2016-09-26 04:38:05
【问题描述】:

所有按钮文本都是从服务器动态生成的。我已经尝试了所有基本的给定布局来形成这个设计,但无法得到想要的结果。请帮帮我,我该如何在android中解决这个设计实现。

【问题讨论】:

  • 没有可以做到这一点的 Android 视图。除了每行 1-3 个随机按钮之外,没有其他模式
  • 您只需要一行中的 2 个和另一行中的 3 个,或者根据可用空间,可能会有更多类似标签?
  • @PreetikaKaur - 不是这样,这完全取决于文本的宽度,这些是将从服务器获取的动态值。所有要生成的按钮数量都是动态的。如果有 4 个小字,那么它可能会容纳在单行中
  • 尝试使用 recyclerview 使用交错布局

标签: android android-layout android-xml android-button


【解决方案1】:

您需要的小部件是 AutoResize TextView

试试下面的课程,它可能对你有帮助

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.RectF;
import android.os.Build;
import android.text.Layout.Alignment;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.SparseIntArray;
import android.util.TypedValue;
import android.widget.TextView;

public class AutoResizeTextView extends TextView {
private interface SizeTester {
    /**
     * 
     * @param suggestedSize
     *            Size of text to be tested
     * @param availableSpace
     *            available space in which text must fit
     * @return an integer < 0 if after applying {@code suggestedSize} to
     *         text, it takes less space than {@code availableSpace}, > 0
     *         otherwise
     */
    public int onTestSize(int suggestedSize, RectF availableSpace);
}

private RectF mTextRect = new RectF();

private RectF mAvailableSpaceRect;

private SparseIntArray mTextCachedSizes;

private TextPaint mPaint;

private float mMaxTextSize;

private float mSpacingMult = 1.0f;

private float mSpacingAdd = 0.0f;

private float mMinTextSize = 20;

private int mWidthLimit;

private static final int NO_LINE_LIMIT = -1;
private int mMaxLines;

private boolean mEnableSizeCache = true;
private boolean mInitializedDimens;

public AutoResizeTextView(Context context) {
    super(context);
    initialize();
}

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

public AutoResizeTextView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    initialize();
}

private void initialize() {
    mPaint = new TextPaint(getPaint());
    mMaxTextSize = getTextSize();
    mAvailableSpaceRect = new RectF();
    mTextCachedSizes = new SparseIntArray();
    if (mMaxLines == 0) {
        // no value was assigned during construction
        mMaxLines = NO_LINE_LIMIT;
    }
}

@Override
public void setTextSize(float size) {
    mMaxTextSize = size;
    mTextCachedSizes.clear();
    adjustTextSize();
}

@Override
public void setMaxLines(int maxlines) {
    super.setMaxLines(maxlines);
    mMaxLines = maxlines;
    adjustTextSize();
}

public int getMaxLines() {
    return mMaxLines;
}

@Override
public void setSingleLine() {
    super.setSingleLine();
    mMaxLines = 1;
    adjustTextSize();
}

@Override
public void setSingleLine(boolean singleLine) {
    super.setSingleLine(singleLine);
    if (singleLine) {
        mMaxLines = 1;
    } else {
        mMaxLines = NO_LINE_LIMIT;
    }
    adjustTextSize();
}

@Override
public void setLines(int lines) {
    super.setLines(lines);
    mMaxLines = lines;
    adjustTextSize();
}

@Override
public void setTextSize(int unit, float size) {
    Context c = getContext();
    Resources r;

    if (c == null)
        r = Resources.getSystem();
    else
        r = c.getResources();
    mMaxTextSize = TypedValue.applyDimension(unit, size,
            r.getDisplayMetrics());
    mTextCachedSizes.clear();
    adjustTextSize();
}

@Override
public void setLineSpacing(float add, float mult) {
    super.setLineSpacing(add, mult);
    mSpacingMult = mult;
    mSpacingAdd = add;
}

/**
 * Set the lower text size limit and invalidate the view
 * 
 * @param minTextSize
 */
public void setMinTextSize(float minTextSize) {
    mMinTextSize = minTextSize;
    adjustTextSize();
}

private void adjustTextSize() {
    if (!mInitializedDimens) {
        return;
    }
    int startSize = (int) mMinTextSize;
    int heightLimit = getMeasuredHeight() - getCompoundPaddingBottom()
            - getCompoundPaddingTop();
    mWidthLimit = getMeasuredWidth() - getCompoundPaddingLeft()
            - getCompoundPaddingRight();
    mAvailableSpaceRect.right = mWidthLimit;
    mAvailableSpaceRect.bottom = heightLimit;
    super.setTextSize(
            TypedValue.COMPLEX_UNIT_PX,
            efficientTextSizeSearch(startSize, (int) mMaxTextSize,
                    mSizeTester, mAvailableSpaceRect));
}

private final SizeTester mSizeTester = new SizeTester() {
    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    public int onTestSize(int suggestedSize, RectF availableSPace) {
        mPaint.setTextSize(suggestedSize);
        String text = getText().toString();
        boolean singleline = getMaxLines() == 1;
        if (singleline) {
            mTextRect.bottom = mPaint.getFontSpacing();
            mTextRect.right = mPaint.measureText(text);
        } else {
            StaticLayout layout = new StaticLayout(text, mPaint,
                    mWidthLimit, Alignment.ALIGN_NORMAL, mSpacingMult,
                    mSpacingAdd, true);
            // return early if we have more lines
            if (getMaxLines() != NO_LINE_LIMIT
                    && layout.getLineCount() > getMaxLines()) {
                return 1;
            }
            mTextRect.bottom = layout.getHeight();
            int maxWidth = -1;
            for (int i = 0; i < layout.getLineCount(); i++) {
                if (maxWidth < layout.getLineWidth(i)) {
                    maxWidth = (int) layout.getLineWidth(i);
                }
            }
            mTextRect.right = maxWidth;
        }

        mTextRect.offsetTo(0, 0);
        if (availableSPace.contains(mTextRect)) {
            // may be too small, don't worry we will find the best match
            return -1;
        } else {
            // too big
            return 1;
        }
    }
};

/**
 * Enables or disables size caching, enabling it will improve performance
 * where you are animating a value inside TextView. This stores the font
 * size against getText().length() Be careful though while enabling it as 0
 * takes more space than 1 on some fonts and so on.
 * 
 * @param enable
 *            enable font size caching
 */
public void enableSizeCache(boolean enable) {
    mEnableSizeCache = enable;
    mTextCachedSizes.clear();
    adjustTextSize(getText().toString());
}

private int efficientTextSizeSearch(int start, int end,
        SizeTester sizeTester, RectF availableSpace) {
    if (!mEnableSizeCache) {
        return binarySearch(start, end, sizeTester, availableSpace);
    }
    int key = getText().toString().length();
    int size = mTextCachedSizes.get(key);
    if (size != 0) {
        return size;
    }
    size = binarySearch(start, end, sizeTester, availableSpace);
    mTextCachedSizes.put(key, size);
    return size;
}

private static int binarySearch(int start, int end, SizeTester sizeTester,
        RectF availableSpace) {
    int lastBest = start;
    int lo = start;
    int hi = end - 1;
    int mid = 0;
    while (lo <= hi) {
        mid = (lo + hi) >>> 1;
        int midValCmp = sizeTester.onTestSize(mid, availableSpace);
        if (midValCmp < 0) {
            lastBest = lo;
            lo = mid + 1;
        } else if (midValCmp > 0) {
            hi = mid - 1;
            lastBest = hi;
        } else {
            return mid;
        }
    }
    // make sure to return last best
    // this is what should always be returned
    return lastBest;

}

@Override
protected void onTextChanged(final CharSequence text, final int start,
        final int before, final int after) {
    super.onTextChanged(text, start, before, after);
    adjustTextSize();
}

@Override
protected void onSizeChanged(int width, int height, int oldwidth,
        int oldheight) {
    mInitializedDimens = true;
    mTextCachedSizes.clear();
    super.onSizeChanged(width, height, oldwidth, oldheight);
    if (width != oldwidth || height != oldheight) {
        adjustTextSize();
    }
}
}

github 上也有一个库

https://github.com/grantland/android-autofittextview

编码愉快!

【讨论】:

  • 如果有帮助,您可以将其标记为正确答案以帮助他人:)
【解决方案2】:

将此添加到您的布局中。

<LinearLayout
                android:id="@+id/tagviews"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:orientation="vertical" >

在你的 Java 类中

tagViews= (LinearLayout)findViewById(R.id.tagviews);
tagViews.removeAllViews();
        LinearLayout ll = new LinearLayout(context);
        ll.setOrientation(LinearLayout.HORIZONTAL);
        ll.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
        LinearLayout childView;
        int remainingWidth, count = tagViews.getChildCount();
        if (count <= 0)
            tagViews.addView(ll);
        TextView tagText;

        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
                LinearLayout.LayoutParams.WRAP_CONTENT);
        params.setMargins(5, 5, 5, 5);

        int width = 0;
        WindowManager w = ((Activity) context).getWindowManager();
        Point size = new Point();
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
            w.getDefaultDisplay().getSize(size);
            width = size.x;
        } else {
//            Display d = w.getDefaultDisplay();
//            width = d.getWidth();
            DisplayMetrics displaymetrics = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
             width = displaymetrics.widthPixels;
            //int screenHeight = displaymetrics.heightPixels;
        }
        try {
            // you might have some array from where you want to set Tags
            for (int k = 0; k < arr.length(); k++) {
                JSONObject obj = arr.getJSONObject(k);                
                final String name = obj.getString("name");
                for (int i = 0; i < tagViews.getChildCount(); i++) {
                    childView = (LinearLayout) tagViews.getChildAt(i);
                    tagText = new TextView(context);                    
                    tagText.setText(name);
                    tagText.setLayoutParams(params);
                    tagText.setPadding(10, 5, 10, 5);
                    tagText.setBackgroundColor(Color.rgb(0xee, 0xee, 0xee));
                    tagText.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            // for handling clicks on tags
                        }
                    });
                   // count = tagViews.getChildCount();
                    childView.measure(0, 0);
                    remainingWidth = width - childView.getMeasuredWidth();
                    //// Log.v("subcriptionAdapter", "remaining width=" + remainingWidth + " childview width= " + childView.getMeasuredWidth());
                    try {
                        if (remainingWidth > childView.getMeasuredWidth()) {
                            childView.addView(tagText);
                            childView.invalidate();
                            break;
                        } else if ((i == tagViews.getChildCount() - 1) && (remainingWidth < childView.getMeasuredWidth())) {
                            childView = new LinearLayout(context);
                            childView.setOrientation(LinearLayout.HORIZONTAL);
                            childView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
                            childView.addView(tagText);
                            tagViews.addView(childView);
                            childView.invalidate();
                            break;
                        } else {
                            continue;
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        } catch (Exception e) {
            // TODO: handle exception
        }
        tagViews.invalidate();

它对我有用 试试看,让我知道....

【讨论】:

  • 我可以知道这里的持有人是什么吗?和RecyvlerView Holder有关系吗?
  • @AnkitGupta 我已经编辑过,实际上我在我的 recyclerview 支架适配器类中使用了它,所以在上面的代码中粘贴代码时,在几个点错误地没有删除支架。我现在已经编辑过了。你可以使用它。
  • 感谢您的帮助。我根据需要将其标记为正确,我面临的唯一错误是很少有按钮已溶解底部。可能是由于保证金,但也尝试过。将再次粘贴图片。
  • 很高兴为您提供帮助.. 当然我想看看
【解决方案3】:

Android 提供了一个名为Chips 的视图组件,允许您包含文本、图像、图标等。您可以尝试将芯片与 staggeredGrid 结合来实现上述视图。或者,您可以尝试使用ChipView,因为它是高度可定制的。要使用自己的布局,您需要创建一个适配器并实现ChipViewAdapter。前往 ChipView 了解更多详情。 - https://github.com/Plumillon/ChipView

public class MainChipViewAdapter extends ChipViewAdapter {
public MainChipViewAdapter(Context context) {
    super(context);
}

@Override
public int getLayoutRes(int position) {
    Tag tag = (Tag) getChip(position);

    switch (tag.getType()) {
        default:
        case 2:
        case 4:
            return 0;

        case 1:
        case 5:
            return R.layout.chip_double_close;

        case 3:
            return R.layout.chip_close;
    }
}

【讨论】:

    猜你喜欢
    • 2018-06-12
    • 2017-08-13
    • 1970-01-01
    • 1970-01-01
    • 2014-04-03
    • 1970-01-01
    • 1970-01-01
    • 2019-11-30
    • 2017-02-14
    相关资源
    最近更新 更多