【问题标题】:Android: How to keep layout stable when replacing fragments?Android:替换片段时如何保持布局稳定?
【发布时间】:2015-04-12 17:13:29
【问题描述】:

目前我正在为Android开发一款棋盘游戏,主要由以下UI元素组成

  • 一块板子(惊喜!)
  • 控件
  • 一个用于显示提示的 TextView 和一个用于关闭显示的提示的按钮

为了给看板尽可能多的屏幕空间并保持布局灵活,我为控件实现了一个片段,另一个用于显示提示的片段。

目前我正在使用以下布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:padding="@dimen/default_padding">

    <FrameLayout
        android:id="@+id/input_and_hints_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true" />

    <some.package.BoardView
        android:id="@+id/board"
        android:layout_height="match_parent"
        android:layout_width="wrap_content"
        android:layout_above="@id/input_and_hints_container" />

</RelativeLayout>

当 Activity 启动时,它会将控件片段放入 FrameLayout。控件包含一个用于显示提示的按钮(如果适用),它将控件片段替换为显示提示片段。 show-hints-fragment 有一个关闭按钮,它将 show-hints-fragment 替换为 controls-fragment。

我的问题是,show-hints-fragment 可能会比 control-fragment 占用更多(或更少)的空间,这会导致板的大小调整。 (我希望电路板尺寸保持稳定,只要没有方向变化。)

我想了两种可能的方法来保持布局稳定:

  1. 将控件片段的初始大小保持为状态,为 show-hints-fragment 实现自定义视图,并让它在其 onMeasure 中返回相同的尺寸。我的直觉是,这过于复杂而且相当丑陋。我认为必须有一个更优雅的解决方案。

  2. 使用ViewPager 来包含两个片段。我以前从未使用过 ViewPager,所以我只是推测这会保持布局稳定。

肯定会有更多选择,所以我想知道最好的方法是什么。

谢谢,一切顺利。

【问题讨论】:

  • 只为容器布局指定一个固定的高度或重量?
  • 嗨,海盗船,非常感谢您的意见,但我认为这种方法不会很灵活。控件在没有固定高度的情况下被测量并很好地布置;我唯一的要求是替换片段不应该占用更多的垂直空间。也许自定义 ViewGroup 实现是要走的路。我会继续研究。
  • 好的,然后将替换片段移动到第一个片段内,放在它自己的布局顶部,匹配布局高度(如果你的布局根有FrameLayout,应该是可行的)。

标签: android android-layout android-fragments


【解决方案1】:

经过更多研究后,我决定实现自己的自定义 ViewGroup。从需要编写的少量状态和代码来看,这似乎是一个可行的解决方案。

我以this article 为起点。

我的解决方案削减了很多角落(基于领域知识) - 它从下到上布置了它的孩子。最后一个孩子只需占用剩余的空间。 一个特定的孩子得到一个不同的(精确的)测量规范,以保持稳定:

public class PlayViewGroup extends ViewGroup {
    private int mMeasuredControlHeight = -1;

    public PlayViewGroup(final Context context) {
        super(context);
    }

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

    @Override
    protected void onLayout(final boolean changed, final int l, final int t, final int r, final int b) {
        final int width = r - l;
        final int height = b - t;
        int currentChildBottom = height;
        for(int i=0; i <this.getChildCount(); i++){
            final View view = getChildAt(i);
            final int childLeft = (width - view.getMeasuredWidth()) / 2;
            final int childRight = width - childLeft;
            final int childTop = currentChildBottom - view.getMeasuredHeight();
            view.layout(childLeft, childTop, childRight, currentChildBottom);
            currentChildBottom -= view.getMeasuredHeight();
        }
    }

    @Override
    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int wspec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.AT_MOST);
        int remainingHeight = getMeasuredHeight();
        for (int i=0; i<getChildCount(); i++) {
            boolean controlPanelFound = false;
            final View view = getChildAt(i);
            int hspec = MeasureSpec.makeMeasureSpec(remainingHeight, MeasureSpec.AT_MOST);
            if (view.getId() == R.id.input_and_hints_container) {
                final FrameLayout mContainer = (FrameLayout) view;
                if (mContainer.getChildCount() == 1) {
                    final View containedView = mContainer.getChildAt(0);
                    if (containedView instanceof InputPanel) {
                        controlPanelFound = true;
                    } else if (containedView != null && mMeasuredControlHeight > 0) {
                        hspec = MeasureSpec.makeMeasureSpec(mMeasuredControlHeight, MeasureSpec.EXACTLY);
                        wspec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY);
                    }
                }
            }

            view.measure(wspec, hspec);
            if (controlPanelFound) {
                mMeasuredControlHeight = view.getMeasuredHeight();
            }
            remainingHeight -= view.getMeasuredHeight();
        }
    }
}

【讨论】:

  • 这可能也可以通过RelativeLayout 实现,并带有明确的布局对齐方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-01-28
  • 2016-05-21
  • 1970-01-01
  • 1970-01-01
  • 2016-05-07
  • 1970-01-01
  • 2015-08-13
相关资源
最近更新 更多