Java 如何在代码中滚动滚动窗格?
我正试图在LibGDX中创建一个类似于这样的滚轮组件: 我使用ScrollPane,因为它内置了输入和抛出处理。我有一个滚轮的图像,它分为14个部分,滚动窗格本身缩短了两个部分,因此在左右两侧各有一个部分,可以向任意方向滚动。一旦滚动位置到达任一方向的末端,我想将滚动位置重置回中心。一遍又一遍地这样做会产生一种无限滚动的幻觉(希望如此) 我遇到的问题是如何在代码中定位滚动窗格,以便在图像到达任意一端时重置图像。到目前为止,我尝试设置滚动位置的任何操作都不起作用。我尝试过setScrollX()和scrollTo()方法。我还尝试将滚动窗格的大小设置为各种大小(与图像大小相同,并且比图像小两部分)。在设置滚动值之前,我尝试在滚动窗格上调用layout、invalidate和pack,以确保其布局正确。我认为updateVisualScroll()可能会强制它更新滚动位置,但这也没有效果 无论我做什么,它都会忽略所有更改滚动位置的调用,因此我显然遗漏了一些内容。在下面的代码中,我试图让滚轮从图像的中心开始,相反,它的开始位置一直在左边 我还需要能够得到当前的滚动位置,以检测何时它已达到任一端。我尝试重写act()方法并打印出scrollPane.getX(),但即使手动单击并拖动该值以滚动滚动窗格,该值始终为“0” 手动单击和拖动时,滚动确实有效,因此我相信滚动窗格设置正确,我只是无法让它在代码中滚动 这是我的代码,为了简单起见,我去掉了所有的实验代码,因为我的实验都不起作用Java 如何在代码中滚动滚动窗格?,java,libgdx,Java,Libgdx,我正试图在LibGDX中创建一个类似于这样的滚轮组件: 我使用ScrollPane,因为它内置了输入和抛出处理。我有一个滚轮的图像,它分为14个部分,滚动窗格本身缩短了两个部分,因此在左右两侧各有一个部分,可以向任意方向滚动。一旦滚动位置到达任一方向的末端,我想将滚动位置重置回中心。一遍又一遍地这样做会产生一种无限滚动的幻觉(希望如此) 我遇到的问题是如何在代码中定位滚动窗格,以便在图像到达任意一端时重置图像。到目前为止,我尝试设置滚动位置的任何操作都不起作用。我尝试过setScrollX()
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();
}
}
公共类MyScrollWheel扩展容器{
私有滚动窗格;
私有图像;
私有整数偏移;
公共MyScrollWheel(){
纹理=新纹理(Gdx.files.internal(“internal/scrollwheel.png”);
图像=新图像(纹理);
scrollOffset=(int)(image.getWidth()/14);
滚动窗格=新的滚动窗格(图像);
scrollPane.setOverscroll(false,false);
setActor(滚动窗格);
大小(image.getWidth()-(scrollOffset*2),image.getHeight());
scrollPane.setScrollX(scrollOffset);//好吧,我希望能够得到一些可以构建的东西。我只是扩展了actor,让它接受一个纹理,这样我就可以使用Texture.wrap并让它使用SpriteBatch.draw()进行绘制
。我现在可以继续滚动它,根据滚动增量,您可以计算出它已滚动了多远。我看不出有任何需要重置控制盘,但如果您真的想重置控制盘,您只需执行wheel.setScroll(0);
一个限制是它不是一个可绘制的
,因此不能像NinePatch
那样缩放。你必须给它一个普通的轮子纹理,按照你想要的大小绘制,你可以添加普通的缩放,手动保持纵横比。然后添加边,也许在边上覆盖一个渐变来创建深度
滚轮:
屏幕中的用法:
因此,只需创建一个可耕的滚轮纹理,并将其包含在ScrollWheel构造函数中。如果使用此代码,它将在屏幕中央绘制滚轮
scroll
变量基本上保持滚动量,因此如果您想将其限制在0到100之间,只需在setScroll()
中添加此功能即可
if(scroll>100)scroll=100;
如果(滚动<0)滚动=0,则为else;
然后,您可以添加一个步骤。因此,如果您想使用滑块旋转图像,可以通过scroll*3,6f
或scroll*(maxScroll/maxStep)
我真的很喜欢这种方式,我将在将来使用它作为我的滑块:D。我已经对它进行了一些扩展和修改,您可以在这里看到我的实现:在Menno Gouw的滚轮上扩展,我添加了一些其他功能:
- 带抛投时间设置的抛投支架
- 调整车轮灵敏度的精度设置
- 需要一个可拖动的
- 兼容在滚动窗格内使用
注意:出于我的目的,我在构造函数中使用了一个标签,但是如果您不想将它绑定到标签上,可以很容易地更改它
这是我在手机上录制的演示滚轮的视频
-编辑1:布局错误现在已经修复(希望如此)。当在滚动窗格中移动时,它现在会更新其位置,并且可绘制内容会被剪切到参与者的边框上
-编辑2:添加了对可用于着色的静止绘图的支持,以及更改方向盘方向的方法(setRightPositiveDirection())
public类滚轮扩展了Actor{
私人可牵引车轮可牵引,车轮遮阳;
自有品牌;
私有int unscaledScrollValueX=0,scrollValueX=0;
私有布尔isNotEdge;
专用整数精度=40;
私有int方向=1;
私有int minValue=Integer.MIN\u值,maxValue=Integer.MAX\u值;
//手动卷轴
专用int分隔符;
私家车轮距;
//投掷
专用浮子燧石,燧石=1f;
私人浮动速度x;
公共滚轮(可拉伸滚轮可拉伸、可拉伸滚轮着色、标签){
this.wheelDrawable=wheelDrawable;
this.wheelShading=wheelShading;
this.label=标签;
wheelWidth=(int)wheelDrawable.getMinWidth();
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...
}
if (scroll > 100) scroll = 100;
else if (scroll < 0) scroll = 0;
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();
}
}
}