我正在使用ScrollPane,因为它内置了输入和fling处理。我有一个分为14个部分的滚轮图像,滚动窗口本身是两个部分更短,所以右边有一个部分,左侧可以向任一方向滚动。一旦滚动位置到达任一方向的末端,我想将滚动位置重置回中心。一遍又一遍地这样做会产生无限滚轮的幻觉(希望如此)。
我遇到的问题是如何在代码中放置ScrollPane,以便在图像到达任一端时重置图像。到目前为止,我没有试图设置滚动位置。我尝试过setScrollX()和scrollTo()方法。我也尝试将滚动窗格的大小设置为各种尺寸(与图像大小相同,两个部分比图像小)。我已经尝试在滚动窗格上调用布局,无效和打包,以确保在设置滚动值之前它已正确布局。我认为updateVisualScroll()可能会强制它更新滚动位置,但这也没有效果。
无论我做什么,它都会忽略我改变滚动位置的所有调用,所以我显然错过了一些东西。在下面的代码中,我试图让滚轮从图像的中心开始,而不是它的起始位置一直在左边。
我还需要能够获取当前滚动位置以检测它何时到达任何一端。我尝试重写act()方法并打印出scrollPane.getX(),但即使我手动点击并拖动它以滚动ScrollPane,此值也始终为“0”。
滚动功能在手动点击和拖动时确实有效,所以我相信ScrollPane设置正确,我无法让它在代码中滚动。
这是我的代码,为简单起见,我将所有实验代码都删除了,因为我的实验都没有。
public class MyScrollWheel extends Container<ScrollPane> {
private ScrollPane scrollPane;
private Image image;
private int scrollOffset;
public MyScrollWheel(){
Texture texture = new Texture(Gdx.files.internal("internal/scrollwheel.png"));
image = new Image(texture);
scrollOffset = (int)(image.getWidth()/14);
scrollPane = new ScrollPane(image);
scrollPane.setOverscroll(false, false);
setActor(scrollPane);
size(image.getWidth()-(scrollOffset*2), image.getHeight());
scrollPane.setScrollX(scrollOffset); // << this doesn't scroll
scrollPane.updateVisualScroll();
}
}
答案 0 :(得分:2)
好吧,我希望能够得到你可以建立的东西。我简单地做的是扩展actor并让它接受一个纹理,这样我就可以使用Texture.wrap并使用SpriteBatch.draw()
进行绘制。我现在可以继续滚动它,并根据滚动增量你可以弄清楚它滚动了多远。我没有看到任何重置轮子的需要,但如果你真的想要,你可以wheel.setScroll(0);
。
一个限制是,它不是Drawable
,因此无法像NinePatch
那样进行缩放。你必须给它一个普通的轮子纹理画你想要它的大小,你可以添加正常的缩放,并手动保持宽高比。然后添加边并可能在那些边上叠加渐变以创建深度。
滚轮:
public class ScrollWheel extends Actor {
Texture wheelTexture;
private int scroll = 0;
public int getScroll() {
return scroll;
}
public void setScroll(int scroll) {
this.scroll = scroll;
}
public ScrollWheel(Texture texture)
{
wheelTexture = texture;
wheelTexture.setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.ClampToEdge);
setWidth(texture.getWidth());
setHeight(texture.getHeight());
}
@Override
public void draw(Batch batch, float parentAlpha) {
super.draw(batch, parentAlpha);
batch.draw(wheelTexture, getX(), getY(), scroll, 0,
wheelTexture.getWidth(), wheelTexture.getHeight());
}
}
屏幕中的用法:
public class TestScreen implements Screen {
Stage stage;
ScrollWheel wheel;
public TestScreen() {
stage = new Stage();
Table t = new Table();
t.setFillParent(true);
stage.addActor(t);
wheel = new ScrollWheel(new Texture("hud/wheel_part.png"));
wheel.addListener(new DragListener() {
@Override
public void drag(InputEvent event, float x, float y, int pointer) {
super.drag(event, x, y, pointer);
wheel.setScroll(wheel.getScroll() + (int)getDeltaX());
}
});
t.add(wheel);
Gdx.input.setInputProcessor(stage);
}
@Override
public void render(float delta) {
Gdx.gl.glClearColor(.3f, .36f, .42f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act();
stage.draw();
}
//...Other mandatory screen methods...
}
因此,只需创建一个可填充的轮子纹理,并将其包含在ScrollWheel构造函数中。如果你使用这个确切的代码,它会在屏幕的中心绘制轮子。
scroll
变量基本上保存了滚动量,因此如果您想要将此值限制在0到100之间,则只需在setScroll()
中添加此功能。
if (scroll > 100) scroll = 100;
else if (scroll < 0) scroll = 0;
然后您可以为其添加一个步骤。因此,如果您想使用滑块旋转图像,可以按scroll * 3,6f
或scroll * (maxScroll / maxStep)
我真的很喜欢这个结果,我将来会用它作为我的滑块:D。我已经对它进行了扩展和修改,你可以在这里看到我的实现:https://youtu.be/RNLk5B-VfYg
答案 1 :(得分:2)
扩展Menno Gouw的滚轮,我添加了更多功能:
注意: 出于我的目的,我在构造函数中使用了Label,但如果您不希望它被绑定,可以轻松更改到标签。
以下是我在手机上录制滚动滚轮的视频。
https://www.youtube.com/watch?v=RwVrez4BZsY&feature=youtu.be
- 编辑1:布局错误现已修复(希望如此)。它现在在ScrollPane中移动时更新其位置,并且Drawables被剪切到Actor的边界。
- 编辑2:添加了对阴影的固定绘图和更改滚轮方向的方法的支持(setRightPositiveDirection())。
public class ScrollWheel extends Actor {
private Drawable wheelDrawable, wheelShading;
private Label label;
private int unscaledScrollValueX=0, scrollValueX=0;
private boolean isNotEdge;
private int precision=40;
private int direction=1;
private int minValue=Integer.MIN_VALUE, maxValue=Integer.MAX_VALUE;
// MANUAL SCROLL
private int separator;
private int wheelWidth;
// FLING
private float flingTimer, flingTime=1f;
private float velocityX;
public ScrollWheel(Drawable wheelDrawable, Drawable wheelShading, Label label) {
this.wheelDrawable = wheelDrawable;
this.wheelShading = wheelShading;
this.label = label;
wheelWidth = (int)wheelDrawable.getMinWidth();
separator = wheelWidth;
setWidth(wheelDrawable.getMinWidth());
setHeight(wheelDrawable.getMinHeight());
// stops ScrollPane from overriding input events
InputListener stopTouchDown = new InputListener() {
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
event.stop();
return false;
}
};
addListener(stopTouchDown);
ActorGestureListener flickScrollListener = new ActorGestureListener() {
public void pan (InputEvent event, float x, float y, float deltaX, float deltaY) {
updateScroll(deltaX);
}
public void fling (InputEvent event, float x, float y, int button) {
if (Math.abs(x) > 150) {
flingTimer = flingTime;
velocityX = x;
}
}
public boolean handle (Event event) {
if (super.handle(event)) {
if (((InputEvent)event).getType() == InputEvent.Type.touchDown) flingTimer = 0;
return true;
}
return false;
}
};
addListener(flickScrollListener);
}
private void updateScroll(float delta){
unscaledScrollValueX += (delta * direction);
scrollValueX = (int)(unscaledScrollValueX / precision);
isNotEdge = true;
if (scrollValueX <= minValue){
scrollValueX = minValue;
unscaledScrollValueX = minValue * precision;
isNotEdge = false;
}
else if (scrollValueX >= maxValue){
scrollValueX = maxValue;
unscaledScrollValueX = maxValue * precision;
isNotEdge = false;
}
if (isNotEdge){
separator += delta;
if (separator <= 0){
separator = wheelWidth;
}
else if (separator >= wheelWidth) {
separator = 0;
}
}
updateLabel();
}
private void updateLabel(){
label.setText("" + scrollValueX);
}
public void setMinValue(int minValue){ this.minValue = minValue; }
public void setMinValueToNone(){ minValue=Integer.MIN_VALUE; }
public void setMaxValue(int maxValue){ this.maxValue = maxValue; }
public void setMaxValueToNone(){ minValue=Integer.MAX_VALUE; }
public void setFlingTime(float flingTime){ this.flingTime = flingTime; }
public void setPrecision(int precision){ this.precision = precision; }
public void setRightPositiveDirection(boolean rightPositive){ direction = (rightPositive) ? 1 : -1; }
@Override
public void act(float delta){
super.act(delta);
boolean animating = false;
if (flingTimer > 0) {
float alpha = flingTimer / flingTime;
updateScroll(velocityX * alpha * delta);
flingTimer -= delta;
if (flingTimer <= 0) {
velocityX = 0;
}
animating = true;
}
if (animating) {
Stage stage = getStage();
if (stage != null && stage.getActionsRequestRendering()){
Gdx.graphics.requestRendering();
}
}
}
@Override
public void draw(Batch batch, float parentAlpha){
super.draw(batch, parentAlpha);
batch.flush();
if (clipBegin(getX(), getY(), getWidth(), getHeight())){
wheelDrawable.draw(batch, getX() + separator - wheelWidth, getY(), wheelDrawable.getMinWidth(), wheelDrawable.getMinHeight());
wheelDrawable.draw(batch, getX() + separator, getY(), wheelDrawable.getMinWidth(), wheelDrawable.getMinHeight());
wheelShading.draw(batch, getX(), getY(), wheelShading.getMinWidth(), wheelShading.getMinHeight());
batch.flush();
clipEnd();
}
}
}