Add support for ContentMode, Update builder API

This commit is contained in:
Denis Andrasec 2024-07-10 15:11:59 +02:00
parent 6729f8bbce
commit 6a89fd9813
4 changed files with 85 additions and 16 deletions

View File

@ -25,6 +25,7 @@ import androidx.navigation.NavHostController
import com.badlogic.gdx.math.Vector2 import com.badlogic.gdx.math.Vector2
import com.esotericsoftware.spine.android.SpineController import com.esotericsoftware.spine.android.SpineController
import com.esotericsoftware.spine.android.SpineView import com.esotericsoftware.spine.android.SpineView
import com.esotericsoftware.spine.android.bounds.Alignment
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable
@ -100,7 +101,9 @@ fun IKFollowing(nav: NavHostController) {
"spineboy-pro.json", "spineboy-pro.json",
context, context,
controller controller
) ).apply {
alignment = Alignment.CENTER_LEFT
}
} }
) )
} }

View File

@ -33,6 +33,7 @@ import com.badlogic.gdx.utils.Array;
import com.esotericsoftware.spine.android.bounds.Alignment; import com.esotericsoftware.spine.android.bounds.Alignment;
import com.esotericsoftware.spine.android.bounds.Bounds; import com.esotericsoftware.spine.android.bounds.Bounds;
import com.esotericsoftware.spine.android.bounds.BoundsProvider; import com.esotericsoftware.spine.android.bounds.BoundsProvider;
import com.esotericsoftware.spine.android.bounds.ContentMode;
import com.esotericsoftware.spine.android.bounds.SetupPoseBounds; import com.esotericsoftware.spine.android.bounds.SetupPoseBounds;
import com.esotericsoftware.spine.android.utils.AndroidSkeletonDrawableLoader; import com.esotericsoftware.spine.android.utils.AndroidSkeletonDrawableLoader;
@ -58,8 +59,13 @@ public class SpineView extends View implements Choreographer.FrameCallback {
private String skeletonFileName; private String skeletonFileName;
private File atlasFile; private File atlasFile;
private File skeletonFile; private File skeletonFile;
private URL atlasUrl;
private URL skeletonUrl;
private File targetDirectory;
private AndroidSkeletonDrawable drawable;
private BoundsProvider boundsProvider = new SetupPoseBounds(); private BoundsProvider boundsProvider = new SetupPoseBounds();
private Alignment alignment = Alignment.CENTER; private Alignment alignment = Alignment.CENTER;
private ContentMode contentMode = ContentMode.FIT;
public Builder(Context context, SpineController controller) { public Builder(Context context, SpineController controller) {
this.context = context; this.context = context;
@ -78,11 +84,28 @@ public class SpineView extends View implements Choreographer.FrameCallback {
return this; return this;
} }
public Builder setLoadFromHttp(URL atlasUrl, URL skeletonUrl, File targetDirectory) {
this.atlasUrl = atlasUrl;
this.skeletonUrl = skeletonUrl;
this.targetDirectory = targetDirectory;
return this;
}
public Builder setLoadFromDrawable(AndroidSkeletonDrawable drawable) {
this.drawable = drawable;
return this;
}
public Builder setBoundsProvider(BoundsProvider boundsProvider) { public Builder setBoundsProvider(BoundsProvider boundsProvider) {
this.boundsProvider = boundsProvider; this.boundsProvider = boundsProvider;
return this; return this;
} }
public Builder setContentMode(ContentMode contentMode) {
this.contentMode = contentMode;
return this;
}
public Builder setAlignment(Alignment alignment) { public Builder setAlignment(Alignment alignment) {
this.alignment = alignment; this.alignment = alignment;
return this; return this;
@ -92,10 +115,15 @@ public class SpineView extends View implements Choreographer.FrameCallback {
SpineView spineView = new SpineView(context, controller); SpineView spineView = new SpineView(context, controller);
spineView.boundsProvider = boundsProvider; spineView.boundsProvider = boundsProvider;
spineView.alignment = alignment; spineView.alignment = alignment;
spineView.contentMode = contentMode;
if (atlasFileName != null && skeletonFileName != null) { if (atlasFileName != null && skeletonFileName != null) {
spineView.loadFromAsset(atlasFileName, skeletonFileName); spineView.loadFromAsset(atlasFileName, skeletonFileName);
} else if (atlasFile != null && skeletonFile != null) { } else if (atlasFile != null && skeletonFile != null) {
spineView.loadFromFile(atlasFile, skeletonFile); spineView.loadFromFile(atlasFile, skeletonFile);
} else if (atlasUrl != null && skeletonUrl != null && targetDirectory != null) {
spineView.loadFromHttp(atlasUrl, skeletonUrl, targetDirectory);
} else if (drawable != null) {
spineView.loadFromDrawable(drawable);
} }
return spineView; return spineView;
} }
@ -109,15 +137,13 @@ public class SpineView extends View implements Choreographer.FrameCallback {
private float scaleY = 1; private float scaleY = 1;
private float x = 0; private float x = 0;
private float y = 0; private float y = 0;
private final SkeletonRenderer renderer = new SkeletonRenderer(); private final SkeletonRenderer renderer = new SkeletonRenderer();
private Bounds computedBounds = new Bounds(); private Bounds computedBounds = new Bounds();
SpineController controller; private SpineController controller;
private BoundsProvider boundsProvider = new SetupPoseBounds();
BoundsProvider boundsProvider = new SetupPoseBounds(); private Alignment alignment = Alignment.CENTER;
private ContentMode contentMode = ContentMode.FIT;
Alignment alignment = Alignment.CENTER;
public SpineView (Context context, SpineController controller) { public SpineView (Context context, SpineController controller) {
super(context); super(context);
@ -158,10 +184,6 @@ public class SpineView extends View implements Choreographer.FrameCallback {
return spineView; return spineView;
} }
public void setController(SpineController controller) {
this.controller = controller;
}
public void loadFromAsset(String atlasFileName, String skeletonFileName) { public void loadFromAsset(String atlasFileName, String skeletonFileName) {
loadFrom(() -> AndroidSkeletonDrawable.fromAsset(atlasFileName, skeletonFileName, getContext())); loadFrom(() -> AndroidSkeletonDrawable.fromAsset(atlasFileName, skeletonFileName, getContext()));
} }
@ -178,6 +200,41 @@ public class SpineView extends View implements Choreographer.FrameCallback {
loadFrom(() -> drawable); loadFrom(() -> drawable);
} }
public SpineController getController() {
return controller;
}
public void setController(SpineController controller) {
this.controller = controller;
}
public Alignment getAlignment() {
return alignment;
}
public void setAlignment(Alignment alignment) {
this.alignment = alignment;
updateCanvasTransform();
}
public ContentMode getContentMode() {
return contentMode;
}
public void setContentMode(ContentMode contentMode) {
this.contentMode = contentMode;
updateCanvasTransform();
}
public BoundsProvider getBoundsProvider() {
return boundsProvider;
}
public void setBoundsProvider(BoundsProvider boundsProvider) {
this.boundsProvider = boundsProvider;
updateCanvasTransform();
}
private void loadFrom(AndroidSkeletonDrawableLoader loader) { private void loadFrom(AndroidSkeletonDrawableLoader loader) {
Handler mainHandler = new Handler(Looper.getMainLooper()); Handler mainHandler = new Handler(Looper.getMainLooper());
Thread backgroundThread = new Thread(() -> { Thread backgroundThread = new Thread(() -> {
@ -230,9 +287,14 @@ public class SpineView extends View implements Choreographer.FrameCallback {
x = (float) (-computedBounds.getX() - computedBounds.getWidth() / 2.0 - (alignment.getX() * computedBounds.getWidth() / 2.0)); 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)); y = (float) (-computedBounds.getY() - computedBounds.getHeight() / 2.0 - (alignment.getY() * computedBounds.getHeight() / 2.0));
// contain switch (contentMode) {
scaleX = scaleY = (float) Math.min(getWidth() / computedBounds.getWidth(), getHeight() / computedBounds.getHeight()); case FIT:
scaleX = scaleY = (float) Math.min(getWidth() / computedBounds.getWidth(), getHeight() / computedBounds.getHeight());
break;
case FILL:
scaleX = scaleY = (float) Math.max(getWidth() / computedBounds.getWidth(), getHeight() / computedBounds.getHeight());
break;
}
offsetX = (float) (getWidth() / 2.0 + (alignment.getX() * getWidth() / 2.0)); offsetX = (float) (getWidth() / 2.0 + (alignment.getX() * getWidth() / 2.0));
offsetY = (float) (getHeight() / 2.0 + (alignment.getY() * getHeight() / 2.0)); offsetY = (float) (getHeight() / 2.0 + (alignment.getY() * getHeight() / 2.0));

View File

@ -0,0 +1,6 @@
package com.esotericsoftware.spine.android.bounds;
public enum ContentMode {
FIT,
FILL;
}

View File

@ -2,8 +2,6 @@ package com.esotericsoftware.spine.android.utils;
import android.os.Build; import android.os.Build;
import com.esotericsoftware.spine.android.AndroidTextureAtlas;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;