哪个LayoutManager用于2048游戏的动画?

时间:2017-09-22 08:15:43

标签: android android-layout android-animation android-constraintlayout android-gridlayout

出于培训目的,我目前正在复制2048游戏。我完成了逻辑和交互,但是在一个TextView内打印(并简单地刷新)它当然看起来很荒谬。

在考虑如何为游戏构建UI时,我不确定选择哪个LayoutManager。我需要在游戏的4 x 4网格中做的是合并并在动画的行和列中添加单元格。在我看来:

  • GridLayout无法正常工作,因为它需要能够处理单行和列时处理完整数据集(四行/列中的16个图块)。但是,我不确定这一点。我之前曾与GridLayout合作过,但从未操纵过项目数量(添加,删除),也从未使用动画进行操作。有没有办法操纵单行和列?

  • LinearLayout无效,因为我在操作列时出现问题,但有四个水平LinearLayout个或行,但有四个垂直LinearLayout

  • RelativeLayoutConstraintLayout是可能的 - 也许吧。这里的问题似乎是我必须跟踪我的16个视图,TextView可能,并以编程方式构建完整的布局,以便我可以告诉动画该做什么。当然可行,但具有挑战性。

  • CustomLayout是一个选择,但我应该在哪个超类上构建它以及为什么?

我错过了简单的解决方案吗?如果没有,那么对于我的数据结构(当前是16个整数的数组,但可以很容易地更改为4 x 4整数数组),最“自然”LayoutManager是什么。

2 个答案:

答案 0 :(得分:8)

更新:包含的图块演示和两个图块合并。

我建议你选择ConstraintLayout。它将允许您有效地定位您的视图,并可以为您提供一些简单的动画。我在下面嘲笑了一个快速示例来演示这种方法。

以下是结果视频:

enter image description here

XML布局使用ConstraintLayout作为视图组。这两个框只是文本视图,但可以很容易地成为图像视图或其他类型的视图。

这两个框只是在24dpgdln0)和520dpgdln100)的水平指南之间垂直移动textView1148dp gdln25的{​​{1}}和520dpgdln100)。textView2。这些移动使用ConstraintSetTransitionManager通过附加到" animate"的点击处理程序进行动画制作。按钮。这是XML后跟代码:

<强> activity_main.xml中

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <android.support.constraint.Guideline
        android:id="@+id/gdln0"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_begin="24dp" />

    <android.support.constraint.Guideline
        android:id="@+id/gdln25"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_begin="148dp" />

    <android.support.constraint.Guideline
        android:id="@+id/gdln50"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_begin="272dp" />

    <android.support.constraint.Guideline
        android:id="@+id/gdln75"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_begin="396dp" />

    <android.support.constraint.Guideline
        android:id="@+id/gdln100"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_begin="520dp" />

    <TextView
        android:id="@+id/textView1"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_marginStart="24dp"
        android:background="@android:color/darker_gray"
        android:gravity="center"
        android:text="2"
        android:textColor="@android:color/white"
        android:textSize="72sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/gdln0" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_marginStart="24dp"
        android:background="@android:color/darker_gray"
        android:gravity="center"
        android:text="4"
        android:textColor="@android:color/white"
        android:textSize="72sp"
        app:layout_constraintStart_toEndOf="@+id/textView1"
        app:layout_constraintTop_toBottomOf="@id/gdln25" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        android:layout_marginRight="16dp"
        android:text="Animate"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintRight_toRightOf="parent" />
</android.support.constraint.ConstraintLayout>

<强> MainActivity.java

public class MainActivity extends AppCompatActivity {

    private int mSquareSide;
    private int mMargin;
    private int mBoardState = 0;
    private TextView mNewView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Resources r = getResources();
        mSquareSide = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 100, r.getDisplayMetrics());
        mMargin = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24, r.getDisplayMetrics());

        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ConstraintLayout layout = (ConstraintLayout) findViewById(R.id.layout);
                ConstraintSet newSet = new ConstraintSet();

                mBoardState = (mBoardState + 1) % 3;
                switch (mBoardState) {
                    case 0: // Just reset the board to its starting condition.
                        setContentView(R.layout.activity_main);
                        findViewById(R.id.button).setOnClickListener(this);
                        break;

                    case 1: // Move tiles down and insert new tile.
                        mNewView = new TextView(layout.getContext());
                        mNewView.setId(View.generateViewId());
                        mNewView.setBackgroundColor(getResources().getColor(android.R.color.darker_gray));
                        mNewView.setTextSize(72);
                        mNewView.setTextColor(getResources().getColor(android.R.color.white));
                        mNewView.setText("2");
                        mNewView.setVisibility(View.INVISIBLE);
                        mNewView.setGravity(Gravity.CENTER);
                        ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(mSquareSide, mSquareSide);
                        mNewView.setLayoutParams(lp);
                        layout.addView(mNewView);
                        newSet.clone(layout);
                        newSet.connect(mNewView.getId(), ConstraintSet.TOP,
                                       R.id.gdln0, ConstraintSet.BOTTOM);
                        newSet.connect(mNewView.getId(), ConstraintSet.START,
                                       ConstraintSet.PARENT_ID, ConstraintSet.START, mMargin);
                        newSet.clear(R.id.textView1, ConstraintSet.TOP);
                        newSet.clear(R.id.textView2, ConstraintSet.TOP);
                        newSet.connect(R.id.textView1, ConstraintSet.BOTTOM,
                                       R.id.gdln100, ConstraintSet.BOTTOM);
                        newSet.connect(R.id.textView2, ConstraintSet.BOTTOM,
                                       R.id.gdln100, ConstraintSet.BOTTOM);
                        TransitionManager.beginDelayedTransition(layout);
                        newSet.applyTo(layout);
                        mNewView.setVisibility(View.VISIBLE);
                        break;

                    case 2: // Move tiles up and combine two tiles.
                        newSet.clone(layout);
                        newSet.clear(R.id.textView1, ConstraintSet.BOTTOM);
                        newSet.clear(R.id.textView2, ConstraintSet.BOTTOM);
                        newSet.connect(R.id.textView1, ConstraintSet.TOP,
                                       R.id.gdln0, ConstraintSet.BOTTOM);
                        newSet.connect(R.id.textView2, ConstraintSet.TOP,
                                       R.id.gdln0, ConstraintSet.BOTTOM);
                        Transition transition = new AutoTransition();
                        transition.addListener(new Transition.TransitionListener() {
                            @Override
                            public void onTransitionStart(Transition transition) {
                            }

                            @Override
                            public void onTransitionEnd(Transition transition) {
                                mNewView.setText("4");
                            // Here you would remove the overlapped view
                            // with layout.removeView(View);
                            }

                            @Override
                            public void onTransitionCancel(Transition transition) {
                            }

                            @Override
                            public void onTransitionPause(Transition transition) {
                            }

                            @Override
                            public void onTransitionResume(Transition transition) {
                            }
                        });
                        TransitionManager.beginDelayedTransition(layout, transition);
                        newSet.applyTo(layout);
                        break;
                }
            }
        });
    }
}

答案 1 :(得分:3)

我想我会在不使用任何TextView或类似内容的情况下简单地绘制整个内容。

让我解释一下原因。

假设您有一组16 TextView,这是您在网格中可以拥有的最大值,您应该管理哪一个是可见的,哪一个不可见,隐藏与否,将其移入布局与否。这会占用很多资源,如果你使用的是你所描述的布局,那么“自由”转换也是不可能的。

假设您有两个图块,并且您希望一个图块在另一个图块上滑动并合并它们。我能想到的唯一可用的布局是RelativeLayout,因为它是具有最容易操纵的约束的布局。

你必须处理每个TextView,管理逐渐过渡和重叠,同时让Android考虑TextView可以做的所有事情。

现在,无论如何,你必须完成所有运动/重叠的东西,所以为什么不通过绘制每个瓷砖来做到这一点?您需要编写更多代码才能将假设Tile类绘制到canvas中(请注意,您可能会稍微更改一下数据结构)。


在你拥有绘图机制之后,你必须使用与TextViews相同的东西,但是以一种不同的,更自由的思维方式,使用更少的约束和使用较少的Android资源。

我知道你在询问一些Layout使用的建议,我建议自己画瓷砖,这可能不是你需要的,如果我用这个长篇大论打扰你,我道歉,但是如果你以“更广泛”的方式征求意见,我认为这是一个好主意。
这也是在Android上学习2D绘图的好时机!

快乐的编码!