将arFragment(sceneForm)与现有Fragment APP

时间:2018-05-18 01:15:47

标签: arcore sceneform

我们一直在努力为我们现有的APP添加AR功能几个月,但进展有限。非常高兴能从google在sceneForm和arFragment上阅读最近的开发。我们目前的APP包含三个片段,其中一个片段需要AR功能。

它看起来很直接,所以我们用arFragment替换了APP中的Fragment。构建成功并在运行期间停止,几乎没有调试信息。关于我们从Fragment升级到arFragment的正确步骤的任何建议?或者我在这里错过了arFragment的观点?

为了显示问题而不通过我们的长度代码(对我们有价值),我们构建了一个基于Google示例项目的虚拟项目:HelloSceneform。基本上,我们将静态片段更改为动态片段。只更改了两个文件,并添加了两个文件,这些文件随后附加。修改后的项目可以成功构建,但在开始运行时停止。

谢谢

彼得

///////文件已修改,HelloSceneformActivity.java:

import android.support.v4.app.FragmentTransaction;

// private ArFragment arFragment;
private ItemOneFragment arFragment;
//arFragment = (ArFragment) getSupportFragmentManager().findFragmentById(R.id.ux_fragment);
arFragment =  ItemOneFragment.newInstance();

//Manually displaying the first fragment - one time only
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frame_layout, arFragment);
transaction.commit();

///////文件已修改,activity_ux.xml:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  xmlns:tools="http://schemas.android.com/tools"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  tools:context=".HelloSceneformActivity">

</FrameLayout>

//////文件已添加fragment_item_one.xml:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/frame_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ItemOneFragment">
</FrameLayout>

///////文件已添加,ItemOneragment.java:

package com.google.ar.sceneform.samples.hellosceneform;

import android.os.Bundle;    
import android.view.LayoutInflater;
import android.view.View; 
import android.view.ViewGroup;
import com.google.ar.sceneform.ux.ArFragment;

public class ItemOneFragment extends ArFragment {

  public static ItemOneFragment newInstance() {
    ItemOneFragment fragment = new ItemOneFragment();
    return fragment;
  }
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
  }

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    return inflater.inflate(R.layout.fragment_item_one, container, false);
  }

}

5 个答案:

答案 0 :(得分:1)

在我的一个项目中,我使用以下结构来完成ArFragment的集成。也许这会给您一些新的提示。

我有一个根布局,其中第一个元素是称为“ body”的FrameLayout。

此“ body”用作占位符,以将现有的3 Fragment切换到应用程序中。 这三个中的一个称为“ SimulationFragment”,它扩展了Sceneform的ArFragment。 相应的布局由具有某些元素的根FrameLayout和另一个称为“ ar_frameLayout”的嵌套FrameLayout组成。

在运行时,我通过直接调用super.onCreateView()更改了SimulationFragment的onCreateView的实现,该调用为我提供了ArFragment的基本视图(此调用还初始化了getArSceneView()。getScene()的场景) 。 之后,我将该视图添加到我先前放大的模拟片段的容器视图中,然后将其返回。 像这样:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    View containerView = inflater.inflate(R.layout.fragment_simulation, container, false);
    FrameLayout arCoreFrameLayout = containerView.findViewById(R.id.ar_core_frame_layout);
    // Inflate the layout for this fragment
    View view = super.onCreateView(inflater, container, savedInstanceState);


    arCoreFrameLayout.addView(view);
    return containerView;
}

答案 1 :(得分:0)

ItemOneFragment扩展了ArFragment,但重写了它的onCreateView方法以扩展自己的布局文件。我认为这就是问题所在。 ArFragment无法找到其ArSceneView和其他代码元素,也无法正常工作。

答案 2 :(得分:0)

当我尝试将ArFragment动态添加到活动中时,我遇到了同样的情况。 之所以崩溃,是因为我提交了当时似乎为空的片段后立即尝试访问ArSceneView。

对我有用的解决方案是实现一个完成侦听器,当片段完成对ARSession的配置后,该侦听器将在Activity中提供回调。

下面是基本概念。

public class MyActivity implements MyArFragment.OnCompletionListener{

     @Override
     protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);                  
      getSupportFragmentManager().beginTransaction().add(R.id.fragment_holder,  new 
        MyArFragment(), "my_arfragment").commit();
     }

     @Override
     public void onComplete() {
       ArFragment arFragment = (ArFragment) getSupportFragmentManager().findFragmentByTag("my_arfragment");
       ArSceneView view = arFragment.getArSceneView();
       Scene scene = view.getScene();
       scene.addOnUpdateListener(this::onUpdateFrame);
     }
}

还有片段:

public class MyFragment extends ArFragment{
  public static interface OnCompleteListener {
        public abstract void onComplete();
  }

  private OnCompleteListener mListener;

   @Override
   public void onAttach(Context context) {
      super.onAttach(context);
      try {
         this.mListener = (OnCompleteListener)context;
      }
      catch (final ClassCastException e) {
         throw new ClassCastException(context.toString() + " must implement 
          OnCompleteListener");
      }
   }


   @Override
   protected Config getSessionConfiguration(Session session) {
      //Update session config...
      mListener.onComplete();
      return config;
   }

}

答案 3 :(得分:0)

我真的很喜欢@kdroider的解决方案,但是他忘记删除对onDetach()中活动的引用,这可能非常重要。另外,重新编写Kotlin中的代码:

import android.content.Context
import com.google.ar.core.Config
import com.google.ar.core.Session
import com.google.ar.sceneform.ux.ArFragment

class AsyncArFragment : ArFragment() {
    private var onArReadyListener: OnArReadyListener? = null

    interface OnArReadyListener {
        fun onArReady()
    }

    override fun getSessionConfiguration(session: Session): Config {
        onArReadyListener?.onArReady()
        return super.getSessionConfiguration(session)
    }


    override fun onAttach(context: Context) {
        super.onAttach(context)
        try {
            onArReadyListener = context as OnArReadyListener
        } catch (e: ClassCastException) {
            throw ClassCastException(context.toString() + " must implement OnArReadyListener")
        }
    }

    override fun onDetach() {
        super.onDetach()
        onArReadyListener = null
    }
}

不要忘记实现OnArReadyListener接口。

警告。用交易替换片段

  1. AnotherFragment -> AsyncArFragment正常工作
  2. AsyncArFragment -> AnotherFragment -> AsyncArFragment由于某种原因而无法工作(onResume(),然后立即调用onDestroy())。如果您知道如何解决,请在评论中写。

答案 4 :(得分:0)

对于任何通过谷歌来到这里的人(像我一样):

根据您的用例,可能不需要覆盖 ArFragment - 只需确保在调用 arFragment.setOnSessionInitializationListener 后访问场景。