diff --git a/spine-android/app/build.gradle.kts b/spine-android/app/build.gradle.kts
index d3fa4cbee..bb87218aa 100644
--- a/spine-android/app/build.gradle.kts
+++ b/spine-android/app/build.gradle.kts
@@ -60,6 +60,7 @@ dependencies {
implementation(libs.androidx.ui.tooling.preview)
implementation(libs.androidx.material3)
implementation(libs.androidx.navigation.compose)
+ implementation(libs.appcompat)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
diff --git a/spine-android/app/src/main/AndroidManifest.xml b/spine-android/app/src/main/AndroidManifest.xml
index 20ac444d9..35fd26c4b 100644
--- a/spine-android/app/src/main/AndroidManifest.xml
+++ b/spine-android/app/src/main/AndroidManifest.xml
@@ -24,6 +24,11 @@
+
+
+
+
diff --git a/spine-android/app/src/main/java/com/esotericsoftware/spine/MainActivity.kt b/spine-android/app/src/main/java/com/esotericsoftware/spine/MainActivity.kt
index 28074fdfc..320041933 100644
--- a/spine-android/app/src/main/java/com/esotericsoftware/spine/MainActivity.kt
+++ b/spine-android/app/src/main/java/com/esotericsoftware/spine/MainActivity.kt
@@ -1,5 +1,6 @@
package com.esotericsoftware.spine
+import android.content.Intent
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
@@ -19,6 +20,7 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
@@ -129,6 +131,10 @@ fun Samples(
.padding(8.dp)
.padding(paddingValues)
) {
+ item {
+ Text(text = "Kotlin + Jetpack Compose", Modifier.padding(8.dp))
+ }
+
samples.forEach {
item {
Card(
@@ -141,6 +147,28 @@ fun Samples(
}
}
}
+
+ item {
+ Text(text = "Java + XML", Modifier.padding(8.dp))
+ }
+
+ item {
+ Card(
+ Modifier
+ .fillMaxWidth()
+ .clickable(onClick = {
+ nav.context.startActivity(
+ Intent(
+ nav.context,
+ SimpleAnimationActivity::class.java
+ )
+ )
+ }),
+ shape = MaterialTheme.shapes.large
+ ) {
+ Text(text = "Simple Animation", Modifier.padding(24.dp))
+ }
+ }
}
}
diff --git a/spine-android/app/src/main/java/com/esotericsoftware/spine/SimpleAnimationActivity.java b/spine-android/app/src/main/java/com/esotericsoftware/spine/SimpleAnimationActivity.java
new file mode 100644
index 000000000..399713ee3
--- /dev/null
+++ b/spine-android/app/src/main/java/com/esotericsoftware/spine/SimpleAnimationActivity.java
@@ -0,0 +1,49 @@
+package com.esotericsoftware.spine;
+
+import android.os.Bundle;
+import android.view.MenuItem;
+
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
+
+import com.esotericsoftware.spine.android.SpineController;
+import com.esotericsoftware.spine.android.SpineView;
+
+public class SimpleAnimationActivity extends AppCompatActivity {
+ /** @noinspection FieldCanBeLocal*/
+ private SpineView spineView;
+ /** @noinspection FieldCanBeLocal*/
+ private SpineController spineController;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_simple_animation);
+
+ // Set up the toolbar
+ Toolbar toolbar = findViewById(R.id.toolbar);
+ setSupportActionBar(toolbar);
+ if (getSupportActionBar() != null) {
+ getSupportActionBar().setTitle("Simple Animation");
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setDisplayShowHomeEnabled(true);
+ }
+
+ spineView = findViewById(R.id.spineView);
+ spineController = new SpineController( controller ->
+ controller.getAnimationState().setAnimation(0, "walk", true)
+ );
+
+ spineView.setController(spineController);
+ spineView.loadFromAsset("spineboy.atlas","spineboy-pro.json");
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == android.R.id.home) {
+ finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+}
diff --git a/spine-android/app/src/main/res/layout/activity_simple_animation.xml b/spine-android/app/src/main/res/layout/activity_simple_animation.xml
new file mode 100644
index 000000000..b49d6a405
--- /dev/null
+++ b/spine-android/app/src/main/res/layout/activity_simple_animation.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
diff --git a/spine-android/gradle/libs.versions.toml b/spine-android/gradle/libs.versions.toml
index 54793659d..c971f0f64 100644
--- a/spine-android/gradle/libs.versions.toml
+++ b/spine-android/gradle/libs.versions.toml
@@ -11,6 +11,7 @@ composeBom = "2023.08.00"
appcompat = "1.6.1"
material = "1.10.0"
navigationCompose = "2.7.7"
+appcompatVersion = "1.7.0"
[libraries]
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
@@ -30,6 +31,7 @@ androidx-material3 = { group = "androidx.compose.material3", name = "material3"
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" }
+appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompatVersion" }
[plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" }
diff --git a/spine-android/spine-android/src/main/java/com/esotericsoftware/spine/android/SpineView.java b/spine-android/spine-android/src/main/java/com/esotericsoftware/spine/android/SpineView.java
index 77fb0c6ca..1d6174235 100644
--- a/spine-android/spine-android/src/main/java/com/esotericsoftware/spine/android/SpineView.java
+++ b/spine-android/spine-android/src/main/java/com/esotericsoftware/spine/android/SpineView.java
@@ -152,12 +152,12 @@ public class SpineView extends View implements Choreographer.FrameCallback {
public SpineView (Context context, AttributeSet attrs) {
super(context, attrs);
- // TODO Load controller & assets fro attrs
+ // Set properties by view id
}
-
+
public SpineView (Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- // TODO Load controller & assets fro attrs
+ // Set properties by view id
}
public static SpineView loadFromAssets(String atlasFileName, String skeletonFileName, Context context, SpineController controller) {
@@ -253,7 +253,7 @@ public class SpineView extends View implements Choreographer.FrameCallback {
@Override
public void onDraw (@NonNull Canvas canvas) {
super.onDraw(canvas);
- if (!controller.isInitialized()) {
+ if (controller == null || !controller.isInitialized()) {
return;
}
@@ -284,6 +284,9 @@ public class SpineView extends View implements Choreographer.FrameCallback {
}
private void updateCanvasTransform() {
+ if (controller == null) {
+ return;
+ }
x = (float) (-computedBounds.getX() - computedBounds.getWidth() / 2.0 - (alignment.getX() * computedBounds.getWidth() / 2.0));
y = (float) (-computedBounds.getY() - computedBounds.getHeight() / 2.0 - (alignment.getY() * computedBounds.getHeight() / 2.0));