SceneView / sceneview-android

SceneView is a 3D and AR Android Composable and View with Google Filament and ARCore. This is a Sceneform replacement in Kotlin
Apache License 2.0
813 stars 160 forks source link

I am using ViewNode and I want to do runtime animation and clicks inside ViewNode, I tried below code and clicks are not working. #557

Open dhvani023 opened 3 days ago

dhvani023 commented 3 days ago

I am using implementation 'io.github.sceneview:arsceneview:0.10.0' and implementation("com.google.android.filament:filament-utils-android:1.31.4") these both version are suitable for my project, I can not update the version. Clicks of imgProfile, imgCall and imgEmail are not working

this is the code I did

import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.app.Activity import android.content.Intent import android.content.pm.PackageManager import android.net.Uri import android.os.Bundle import android.os.Handler import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import io.github.sceneview.ar.ArSceneView import io.github.sceneview.ar.node.ArNode import android.view.MotionEvent import android.view.View import android.widget.ImageView import android.widget.LinearLayout import android.widget.Toast import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat import androidx.core.content.res.ResourcesCompat import com.bumptech.glide.Glide import com.google.ar.core.HitResult import com.google.gson.Gson import io.github.sceneview.ar.arcore.position import io.github.sceneview.ar.isFocusable import io.github.sceneview.math.Position import io.github.sceneview.math.Scale import io.github.sceneview.node.ViewNode

data class Employee( val LanId: String, val Name: String, val Email: String, val Department: String, val JobTitle: String, val Manager: Employee, val ManagerLanId: String, val WorkPhone: String?, val OfficeLocation: String, val PhotoURL: String?, val CellPhone: String?, val UserPrincipalName: String, val UserPhoto: String? )

data class ApiResponse( val HaveMore: Boolean, val IsLock: Boolean, val Employees: List, val Count: Int, val Success: Boolean )

class MainActivity1 : AppCompatActivity() {

  lateinit var arSceneView: ArSceneView
  lateinit var viewNode: ViewNode
  var isPlaced = false // Flag to control movement
  private var employee: Employee? = null
  private val CALL_PHONE_PERMISSION_CODE = 1001
  private val originalScale = Scale(0.9f, 0.9f, 0.9f) // Original scale
  private val smallScale = Scale(0.5f, 0.5f, 0.5f) // 50% of the original size

  override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.activity_main)

      arSceneView = findViewById<ArSceneView?>(R.id.sceneView).apply {

      }

      val jsonString = """
  {
"HaveMore": false,
"IsLock": false,
"Employees": [
  {
    "LanId": "XYZ123",
    "Name": "XYZ",
    "Email": "XYZ@ocbc.com",
    "Department": "Group Engineering - Digital Channels",
    "JobTitle": "Assistant Vice President",
    "ManagerLanId": "OCBCGROUP\\ABC123",
    "WorkPhone": "+6561234567",
    "OfficeLocation": "SG",
    "PhotoURL": "https://i.pravatar.cc/50?img=2",
    "CellPhone": "",
    "UserPrincipalName": "XYZ123@OCBCGROUP.OCBC.COM",
    "UserPhoto": "https://i.pravatar.cc/50?img=2"
  }
],
"Count": 1,
"Success": true

} """

      val gson = Gson()
      val apiResponse = gson.fromJson(jsonString, ApiResponse::class.java)
      employee = apiResponse.Employees.getOrNull(0)

// val smallScale = Scale(0.5f, 0.5f, 0.5f) // 50% of the original size

      viewNode = ViewNode(arSceneView.engine).apply {
          loadView(
              applicationContext,
              lifecycle,
              R.layout.center_card_layout,
              onLoaded = { renderableInstance, view ->
                  val imageView =
                      view.findViewById<ImageView>(R.id.profile_image)
                  // Use the employee's image URL
                  employee?.UserPhoto?.let { loadImageFromUrl(imageView, it) }

                  val textView = view.findViewById<TextView>(R.id.profile_name)
                  textView.text = employee?.Name
                  val textViewJob =
                      view.findViewById<TextView>(R.id.profile_designation)
                  textViewJob.text = employee?.JobTitle
                  val txtDepartment =
                      view.findViewById<TextView>(R.id.txtDepartment)
                  txtDepartment.text = employee?.Department
                  val txtEmail =
                      view.findViewById<TextView>(R.id.txtEmail)
                  txtEmail.text = employee?.Email
                  val txtPhone =
                      view.findViewById<TextView>(R.id.txtPhone)
                  txtPhone.text = employee?.WorkPhone
                  val txtLocation =
                      view.findViewById<TextView>(R.id.txtLocation)
                  txtLocation.text = employee?.OfficeLocation

                  var shortAnimationDuration: Int =
                      resources.getInteger(android.R.integer.config_shortAnimTime)
                  val imgCall =
                      view.findViewById<ImageView>(R.id.imgCall)
                  val imgEmail =
                      view.findViewById<ImageView>(R.id.imgEmail)
                  val imgProfile =
                      view.findViewById<ImageView>(R.id.imgProfile)
                  val layData =
                      view.findViewById<LinearLayout>(R.id.layData)
                  imgCall.setOnClickListener {

                  }

                  imgEmail.setOnClickListener {

                  }

                  imgProfile.setOnClickListener {

                  }
              }) // Load your layout
          scale = smallScale // Set the decreased size

      }

      // Attach the ViewNode to the scene
      arSceneView.addChild(viewNode)
      viewNode.isFocusable = true

      // Keep the ViewNode centered with the camera
      arSceneView.onFrame = { frameTime ->
          if (!isPlaced) {
              // Keep the ViewNode at the center of the camera
              val cameraPosition = arSceneView.cameraNode.worldPosition
              viewNode.position = Position(
                  cameraPosition.x,
                  cameraPosition.y - 0.5f,
                  cameraPosition.z - 1f
              ) // Adjust the z-offset as needed
          }
      }

      // Set up tap listener to place the ViewNode at the tap location
      arSceneView.onTapAr = { hitResult, motionEvent ->
          if (!isPlaced) {
              placeNodeAtTap(hitResult, motionEvent)
          } else {

// Toast.makeText(applicationContext, "click on placed node", Toast.LENGTH_LONG) // .show() } } }

  private fun placeNodeAtTap(hitResult: HitResult, motionEvent: MotionEvent) {
      val arNode = ArNode(arSceneView.engine).apply {
          position = hitResult.createAnchor().pose.position
      }
      // Place the ViewNode at the tap location
      arSceneView.addChild(arNode)
      viewNode.position = arNode.position // Move the viewNode to the tapped position
      viewNode.scale = originalScale
      isPlaced = true
      Toast.makeText(applicationContext, "Node placed", Toast.LENGTH_LONG).show()
  }

  private fun loadImageFromUrl(imageView: ImageView, imageUrl: String?) {
      Glide.with(this)
          .load(imageUrl)
          .circleCrop()
          .into(imageView)
  }

  private fun sendEmail(recipient: String, subject: String, message: String) {

  }