Integrate Unity3d view into Android activity

2019-01-23 08:46发布

问题:

I'm currently working on a small AR app for Android and am facing the problem of integrating Unity3d into an activity. The requirements indicate that I need to be able to present some Android UI - e.g. menus and an action bar - and a camera view that will display a model created in Unity3d when the target is detected.

I found a link that helped me a lot: Unity3d forums. One of the users there asked the same question I have now but never got any proper answer -that's why I'm posting here.

Problem:

I got a small Unity3d project that is essentially a white cube and am trying to display it in one of my Android activities. The model looks fine when activity doesn't have setContentView() in its onCreate() method but then I can't specify my layout in an XML file.

When I do add the setContentView() method, I can see the cube but it's very small and there doesn't seem to be any way of actually making it change its size.

The XML file:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/unityView"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >
</FrameLayout>

1st version of the activity implementation:

    public class HomeActivity extends UnityPlayerActivity {

        UnityPlayer unityPlayer;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        }
    }

And the resulting screenshot:

2nd version of the activity implementation:

public class HomeActivity extends UnityPlayerActivity {

        UnityPlayer unityPlayer;

        @Override
        protected void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);

            setContentView(R.layout.activity_home);
            unityPlayer = new UnityPlayer(this);
            int glesMode = unityPlayer.getSettings().getInt("gles_mode", 1);
            unityPlayer.init(glesMode, false);

            FrameLayout layout = (FrameLayout) findViewById(R.id.unityView);
            LayoutParams lp = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
            layout.addView(unityPlayer.getView(), 0, lp);
        }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {

        super.onWindowFocusChanged(hasFocus);
        unityPlayer.windowFocusChanged(hasFocus);

    }
}

And the resulting screenshot:

Could anyone explain to me why that is and how to fix it?

回答1:

While I still don't know why it works like that, I've found a way of fixing it.

Instead of simply using setContentView() in onCreate(), extend onResume() and in that method recursively look through all the available views to find the parent view of the UnityPlayer object. Once that's found, layouts and other views can be inflated and added to that parent view.

Here's the link with a code example - I've used this to make my app work: https://developer.vuforia.com/resources/dev-guide/extending-unity-android-activity-and-adding-custom-views-eclipse

Edit: Here's a code snippet showing my solution.

@Override
public void onResume() {

    super.onResume();

    if (unityPlayer == null) {

        View rootView = findViewById(android.R.id.content);
        unityPlayer = findUnityPlayerView(rootView);

        if (unityPlayer != null) {

            ViewGroup unityPlayerParentView = (ViewGroup)(unityPlayer.getParent());

            View mainHomeView = getLayoutInflater().inflate(R.layout.activity_main, null);
            LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
            unityPlayerParentView.addView(mainHomeView, layoutParams);

        }
    }
}

and

private UnityPlayer findUnityPlayerView(View view) {

    if (view instanceof UnityPlayer) {

        return (UnityPlayer) view;
    }
    if (view instanceof ViewGroup) {

        ViewGroup childrenViews = (ViewGroup) view;

        for (int i = 0; i < childrenViews.getChildCount(); i++) {

            UnityPlayer foundView = findUnityPlayerView(childrenViews.getChildAt(i));

            if (foundView != null) {

                return foundView;
            }
        }
    }

    return null;
}