Last active
March 21, 2022 02:00
-
-
Save MobiDevelop/5540815 to your computer and use it in GitHub Desktop.
A LibGDX ScrollPane with page support. It center-locks on pages after scrolling.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.badlogic.gdx.tests.examples; | |
import com.badlogic.gdx.math.MathUtils; | |
import com.badlogic.gdx.scenes.scene2d.Actor; | |
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane; | |
import com.badlogic.gdx.scenes.scene2d.ui.Skin; | |
import com.badlogic.gdx.scenes.scene2d.ui.Table; | |
import com.badlogic.gdx.utils.Array; | |
import com.esotericsoftware.tablelayout.Cell; | |
public class PagedScrollPane extends ScrollPane { | |
private float pickAmountX; | |
private float pickDifferenceX = -1; | |
private boolean wasPanDragFling = false; | |
private float scrollToPageSpeed = 1000; | |
private float pageSpacing; | |
private Table content; | |
public PagedScrollPane () { | |
super(null); | |
content = new Table(); | |
content.defaults().space(50); | |
setWidget(content); | |
} | |
public PagedScrollPane (Skin skin) { | |
super(null, skin); | |
content = new Table(); | |
content.defaults().space(50); | |
setWidget(content); | |
} | |
public PagedScrollPane (Skin skin, String styleName) { | |
super(null, skin, styleName); | |
content = new Table(); | |
content.defaults().space(50); | |
setWidget(content); | |
} | |
public PagedScrollPane (Actor widget, ScrollPaneStyle style) { | |
super(null, style); | |
content = new Table(); | |
content.defaults().space(50); | |
setWidget(content); | |
} | |
public void addPages (Actor... pages) { | |
for (Actor page : pages) { | |
content.add(page).expandY().fillY(); | |
} | |
} | |
public void addPage (Actor page) { | |
content.add(page).expandY().fillY(); | |
} | |
@Override | |
public void act (float delta) { | |
super.act(delta); | |
if (wasPanDragFling && !isPanning() && !isDragging() && !isFlinging()) { | |
wasPanDragFling = false; | |
scrollToPage(); | |
} else { | |
if (isPanning() || isDragging() || isFlinging()) { | |
wasPanDragFling = true; | |
} | |
} | |
} | |
@Override | |
public void setWidth (float width) { | |
super.setWidth(width); | |
if (content != null) { | |
for (Cell cell : content.getCells()) { | |
cell.width(width); | |
} | |
content.invalidate(); | |
} | |
} | |
public void setPageSpacing (float pageSpacing) { | |
if (content != null) { | |
content.defaults().space(pageSpacing); | |
for (Cell cell : content.getCells()) { | |
cell.space(pageSpacing); | |
} | |
content.invalidate(); | |
} | |
} | |
private void scrollToPage () { | |
final float width = getWidth(); | |
final float scrollX = getScrollX(); | |
final float maxX = getMaxX(); | |
if (scrollX >= maxX || scrollX <= 0) return; | |
Array<Actor> pages = content.getChildren(); | |
float pageX = 0; | |
float pageWidth = 0; | |
if (pages.size > 0) { | |
for (Actor a : pages) { | |
pageX = a.getX(); | |
pageWidth = a.getWidth(); | |
if (scrollX < (pageX + pageWidth * 0.5)) { | |
break; | |
} | |
} | |
setScrollX(MathUtils.clamp(pageX - (width - pageWidth) / 2, 0, maxX)); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/******************************************************************************* | |
* Copyright 2011 See AUTHORS file. | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
******************************************************************************/ | |
package com.badlogic.gdx.tests.examples; | |
import com.badlogic.gdx.Gdx; | |
import com.badlogic.gdx.graphics.Color; | |
import com.badlogic.gdx.graphics.GL10; | |
import com.badlogic.gdx.math.MathUtils; | |
import com.badlogic.gdx.scenes.scene2d.Actor; | |
import com.badlogic.gdx.scenes.scene2d.InputEvent; | |
import com.badlogic.gdx.scenes.scene2d.InputListener; | |
import com.badlogic.gdx.scenes.scene2d.Stage; | |
import com.badlogic.gdx.scenes.scene2d.ui.Button; | |
import com.badlogic.gdx.scenes.scene2d.ui.Button.ButtonStyle; | |
import com.badlogic.gdx.scenes.scene2d.ui.Image; | |
import com.badlogic.gdx.scenes.scene2d.ui.Label; | |
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane; | |
import com.badlogic.gdx.scenes.scene2d.ui.Skin; | |
import com.badlogic.gdx.scenes.scene2d.ui.Slider; | |
import com.badlogic.gdx.scenes.scene2d.ui.Table; | |
import com.badlogic.gdx.scenes.scene2d.ui.TextButton; | |
import com.badlogic.gdx.scenes.scene2d.ui.Skin.TintedDrawable; | |
import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle; | |
import com.badlogic.gdx.scenes.scene2d.utils.Align; | |
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener; | |
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener; | |
import com.badlogic.gdx.scenes.scene2d.utils.Drawable; | |
import com.badlogic.gdx.tests.utils.GdxTest; | |
import com.esotericsoftware.tablelayout.Value; | |
public class PagedScrollPaneTest extends GdxTest { | |
private Skin skin; | |
private Stage stage; | |
private Table container; | |
public void create () { | |
stage = new Stage(0, 0, false); | |
skin = new Skin(Gdx.files.internal("data/uiskin.json")); | |
Gdx.input.setInputProcessor(stage); | |
container = new Table(); | |
stage.addActor(container); | |
container.setFillParent(true); | |
PagedScrollPane scroll = new PagedScrollPane(); | |
scroll.setFlingTime(0.1f); | |
scroll.setPageSpacing(25); | |
int c = 1; | |
for (int l = 0; l < 10; l++) { | |
Table levels = new Table().pad(50); | |
levels.defaults().pad(20, 40, 20, 40); | |
for (int y = 0; y < 3; y++) { | |
levels.row(); | |
for (int x = 0; x < 4; x++) { | |
levels.add(getLevelButton(c++)).expand().fill(); | |
} | |
} | |
scroll.addPage(levels); | |
} | |
container.add(scroll).expand().fill(); | |
} | |
public void render () { | |
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT); | |
stage.act(Gdx.graphics.getDeltaTime()); | |
stage.draw(); | |
Table.drawDebug(stage); | |
} | |
public void resize (int width, int height) { | |
stage.setViewport(width, height, false); | |
} | |
public void dispose () { | |
stage.dispose(); | |
skin.dispose(); | |
} | |
public boolean needsGL20 () { | |
return false; | |
} | |
/** | |
* Creates a button to represent the level | |
* | |
* @param level | |
* @return The button to use for the level | |
*/ | |
public Button getLevelButton(int level) { | |
Button button = new Button(skin); | |
ButtonStyle style = button.getStyle(); | |
style.up = style.down = null; | |
Label label = new Label(Integer.toString(level), skin); | |
label.setFontScale(2f); | |
label.setAlignment(Align.center); | |
button.stack(new Image(skin.newDrawable("default-round-large", Color.RED)), label).expand().fill(); | |
skin.add("star-filled", skin.newDrawable("white", Color.YELLOW), Drawable.class); | |
skin.add("star-unfilled", skin.newDrawable("white", Color.GRAY), Drawable.class); | |
int stars = MathUtils.random(-1, +3); | |
Table starTable = new Table(); | |
starTable.defaults().pad(5); | |
if (stars >= 0) { | |
for (int star = 0; star < 3; star++) { | |
if (stars > star) { | |
starTable.add(new Image(skin.getDrawable("star-filled"))).width(20).height(20); | |
} else { | |
starTable.add(new Image(skin.getDrawable("star-unfilled"))).width(20).height(20); | |
} | |
} | |
} | |
button.row(); | |
button.add(starTable).height(30); | |
button.setName("Level" + Integer.toString(level)); | |
button.addListener(levelClickListener); | |
return button; | |
} | |
/** | |
* Handle the click - in real life, we'd go to the level | |
*/ | |
public ClickListener levelClickListener = new ClickListener() { | |
@Override | |
public void clicked (InputEvent event, float x, float y) { | |
System.out.println("Click: " + event.getListenerActor().getName()); | |
} | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Nice idea, thanks a lot!