android游戏开发框架libgdx的使用(五)--舞台和常用UI类
转载声明:http://www.cnblogs.com/htynkn/archive/2011/11/16/libgdx_5.html
常用的UI类包括标签,按钮,勾选框,下拉框,图片,输入框,列表,滑动面板,滑条,分割面板。它们都在com.badlogic.gdx.scenes.scene2d.ui包中,都属于Actor,可以方便的纳入舞台的管理中。
其实仔细看看UI类的实现代码不难发现其实它们都是大部分继承自Widget或者Table,如果需要自定义UI可以继承以上两个类(它们继承自Actor),这里要说明一下libgdx的布局部分使用了TWL,有兴趣的朋友可以去看看。
在介绍每个控件之前我们先来看一下NinePatch,这是最近的一个比较重大的更新。
何为NinePatch?其实android原生即有NinePatch类,常在按钮中使用。
如图,将图片分成九份。中间部分可以根据需要扩大,使按钮的大小内容变动不受图片的限制。
而在libgdx的NinePatch其实就是九个TextureRegion对象。
常用的实例化方法有两个:
1 public NinePatch (Texture texture, int left, int right, int top, int bottom) 2 3 public NinePatch (TextureRegion region, int left, int right, int top, int bottom)
关于其中的四个int型参数如何取值我们可以参考一下源码:
1 public NinePatch (TextureRegion region, int left, int right, int top, int bottom) { 2 int middleWidth = region.getRegionWidth() - left - right; 3 int middleHeight = region.getRegionHeight() - top - bottom; 4 this.patches = new TextureRegion[] {new TextureRegion(region, 0, 0, left, top), 5 new TextureRegion(region, left, 0, middleWidth, top), new TextureRegion(region, left + middleWidth, 0, right, top), 6 new TextureRegion(region, 0, top, left, middleHeight), new TextureRegion(region, left, top, middleWidth, middleHeight), 7 new TextureRegion(region, left + middleWidth, top, right, middleHeight), 8 new TextureRegion(region, 0, top + middleHeight, left, bottom), 9 new TextureRegion(region, left, top + middleHeight, middleWidth, bottom), 10 new TextureRegion(region, left + middleWidth, top + middleHeight, right, bottom)}; 11 }
先计算中间部分的宽度和高度。然后开始切图,首先取顶部的最左边的那个,即图中编号1的那块,然后去它右边的,然后再右边的。
取完最上边的那行,然后取中间的那行,然后取最后一行的。
由上自下,由左自右。
而在绘制时又是如何处理的呢?看源码:
1 public void draw (SpriteBatch batch, float x, float y, float width, float height) { 2 float centerColumnX = x; 3 if (patches[BOTTOM_LEFT] != null) 4 centerColumnX += patches[BOTTOM_LEFT].getRegionWidth(); 5 else if (patches[MIDDLE_LEFT] != null) 6 centerColumnX += patches[MIDDLE_LEFT].getRegionWidth(); 7 else if (patches[TOP_LEFT] != null) // 8 centerColumnX += patches[TOP_LEFT].getRegionWidth(); 9 10 float rightColumnX = x + width; 11 if (patches[BOTTOM_RIGHT] != null) 12 rightColumnX -= patches[BOTTOM_RIGHT].getRegionWidth(); 13 else if (patches[MIDDLE_RIGHT] != null) 14 rightColumnX += patches[MIDDLE_RIGHT].getRegionWidth(); 15 else if (patches[TOP_RIGHT] != null) // 16 rightColumnX += patches[TOP_RIGHT].getRegionWidth(); 17 18 float middleRowY = y; 19 if (patches[TOP_LEFT] != null) 20 middleRowY += patches[TOP_LEFT].getRegionHeight(); 21 else if (patches[TOP_CENTER] != null) 22 middleRowY += patches[TOP_CENTER].getRegionHeight(); 23 else if (patches[TOP_RIGHT] != null) // 24 middleRowY += patches[TOP_RIGHT].getRegionHeight(); 25 26 float topRowY = y + height; 27 if (patches[TOP_LEFT] != null) 28 topRowY -= patches[TOP_LEFT].getRegionHeight(); 29 else if (patches[TOP_CENTER] != null) 30 topRowY -= patches[TOP_CENTER].getRegionHeight(); 31 else if (patches[TOP_RIGHT] != null) // 32 topRowY -= patches[TOP_RIGHT].getRegionHeight(); 33 34 // Bottom row 35 if (patches[BOTTOM_LEFT] != null) batch.draw(patches[BOTTOM_LEFT], x, y, centerColumnX - x, middleRowY - y); 36 if (patches[BOTTOM_CENTER] != null) 37 batch.draw(patches[BOTTOM_CENTER], centerColumnX, y, rightColumnX - centerColumnX, middleRowY - y); 38 if (patches[BOTTOM_RIGHT] != null) 39 batch.draw(patches[BOTTOM_RIGHT], rightColumnX, y, x + width - rightColumnX, middleRowY - y); 40 41 // Middle row 42 if (patches[MIDDLE_LEFT] != null) batch.draw(patches[MIDDLE_LEFT], x, middleRowY, centerColumnX - x, topRowY - middleRowY); 43 if (patches[MIDDLE_CENTER] != null) 44 batch.draw(patches[MIDDLE_CENTER], centerColumnX, middleRowY, rightColumnX - centerColumnX, topRowY - middleRowY); 45 if (patches[MIDDLE_RIGHT] != null) 46 batch.draw(patches[MIDDLE_RIGHT], rightColumnX, middleRowY, x + width - rightColumnX, topRowY - middleRowY); 47 48 // Top row 49 if (patches[TOP_LEFT] != null) batch.draw(patches[TOP_LEFT], x, topRowY, centerColumnX - x, y + height - topRowY); 50 if (patches[TOP_CENTER] != null) 51 batch.draw(patches[TOP_CENTER], centerColumnX, topRowY, rightColumnX - centerColumnX, y + height - topRowY); 52 if (patches[TOP_RIGHT] != null) 53 batch.draw(patches[TOP_RIGHT], rightColumnX, topRowY, x + width - rightColumnX, y + height - topRowY); 54 }
先计算左右栏的宽度,在计算中间和顶部的高度。然后从下自上的绘制。说实话我觉得这段代码看着很好玩的。
现在来说说几个常用的控件的使用吧。先构建一个舞台。
先来试试Label吧,label是有缓存的,所以替换显示内容不是用setText方法,而是使用setWrappedText方法。
代码如下:
1 package com.cnblogs.htynkn.listener; 2 3 import com.badlogic.gdx.ApplicationListener; 4 import com.badlogic.gdx.Gdx; 5 import com.badlogic.gdx.graphics.GL10; 6 import com.badlogic.gdx.graphics.g2d.BitmapFont; 7 import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment; 8 import com.badlogic.gdx.scenes.scene2d.Stage; 9 import com.badlogic.gdx.scenes.scene2d.actors.Label; 10 11 public class FirstGame implements ApplicationListener { 12 13 private Stage stage; 14 Label label; 15 16 @Override 17 public void create() { 18 stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), 19 true); 20 label = new Label("fpsLabel", new BitmapFont(Gdx.files.internal("cf.fnt"),Gdx.files.internal("cf.png"),false), "label1"); 21 label.x=5; 22 label.y=Gdx.graphics.getHeight()-label.height-5; 23 stage.addActor(label); 24 Gdx.input.setInputProcessor(stage); 25 } 26 27 @Override 28 public void dispose() { 29 stage.dispose(); 30 } 31 32 @Override 33 public void pause() { 34 // TODO Auto-generated method stub 35 36 } 37 38 @Override 39 public void render() { 40 Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT); 41 label.setWrappedText("FPS: "+Gdx.graphics.getFramesPerSecond(), 42 HAlignment.CENTER); 43 stage.act(Gdx.graphics.getDeltaTime()); 44 stage.draw(); 45 } 46 47 @Override 48 public void resize(int width, int height) { 49 // TODO Auto-generated method stub 50 51 } 52 53 @Override 54 public void resume() { 55 // TODO Auto-generated method stub 56 57 } 58 }
效果:
然后再看看Button吧,实例化需要一个ButtonStyle,定义了按钮三种状态对应的图片样式,按下和松开时的X,Y偏移还有Button中文字绘制所需的BitmapFont和Color。
按钮的三种状态的图片我就省了,只用一张图片。
修改代码如下:
1 package com.cnblogs.htynkn.listener; 2 3 import com.badlogic.gdx.ApplicationListener; 4 import com.badlogic.gdx.Gdx; 5 import com.badlogic.gdx.graphics.Color; 6 import com.badlogic.gdx.graphics.GL10; 7 import com.badlogic.gdx.graphics.Texture; 8 import com.badlogic.gdx.graphics.g2d.BitmapFont; 9 import com.badlogic.gdx.graphics.g2d.NinePatch; 10 import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment; 11 import com.badlogic.gdx.scenes.scene2d.Stage; 12 import com.badlogic.gdx.scenes.scene2d.actors.Label; 13 import com.badlogic.gdx.scenes.scene2d.ui.Button; 14 import com.badlogic.gdx.scenes.scene2d.ui.Button.ButtonStyle; 15 16 public class FirstGame implements ApplicationListener { 17 18 private Stage stage; 19 Label label; 20 Texture texture; 21 Button button; 22 23 @Override 24 public void create() { 25 stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), 26 true); 27 texture = new Texture(Gdx.files.internal("06.png")); 28 NinePatch n1 = new NinePatch(texture, 7, 7, 9, 9); 29 BitmapFont bitmapFont = new BitmapFont(Gdx.files.internal("cf.fnt"), 30 Gdx.files.internal("cf.png"), false); 31 label = new Label("fpsLabel", bitmapFont, "label1"); 32 label.x = 5; 33 label.y = Gdx.graphics.getHeight() - label.height - 5; 34 stage.addActor(label); 35 button = new Button("button", new ButtonStyle(n1, n1, n1, 0f, 0f, 0f, 36 0f, bitmapFont, new Color(1, 1, 0, 0.5f)), "button"); 37 button.x=10; 38 button.y=10; 39 button.width=100f; 40 button.height=32f; 41 stage.addActor(button); 42 Gdx.input.setInputProcessor(stage); 43 } 44 45 @Override 46 public void dispose() { 47 stage.dispose(); 48 } 49 50 @Override 51 public void pause() { 52 // TODO Auto-generated method stub 53 54 } 55 56 @Override 57 public void render() { 58 Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT); 59 label.setWrappedText("FPS: " + Gdx.graphics.getFramesPerSecond(), 60 HAlignment.CENTER); 61 stage.act(Gdx.graphics.getDeltaTime()); 62 stage.draw(); 63 } 64 65 @Override 66 public void resize(int width, int height) { 67 // TODO Auto-generated method stub 68 69 } 70 71 @Override 72 public void resume() { 73 // TODO Auto-generated method stub 74 75 } 76 }
效果:
按钮自然应该有点击事件,通过setClickListener来设置
1 button.setClickListener(new ClickListener() { 2 @Override 3 public void click(Actor actor) { 4 Gdx.app.log("Info", "点击事件触发了"); 5 } 6 });
然后再看看CheckBox。CheckBox的样式定义在CheckBoxStyle中,需要4个参数,两种状态的各一张图片,一个BitmapFont和Color。
这里我再添加一张图片
原理差不多,直接贴代码了。
1 package com.cnblogs.htynkn.listener; 2 3 import android.graphics.Paint.Align; 4 5 import com.badlogic.gdx.ApplicationListener; 6 import com.badlogic.gdx.Gdx; 7 import com.badlogic.gdx.graphics.Color; 8 import com.badlogic.gdx.graphics.GL10; 9 import com.badlogic.gdx.graphics.Texture; 10 import com.badlogic.gdx.graphics.g2d.BitmapFont; 11 import com.badlogic.gdx.graphics.g2d.NinePatch; 12 import com.badlogic.gdx.graphics.g2d.TextureRegion; 13 import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment; 14 import com.badlogic.gdx.scenes.scene2d.Actor; 15 import com.badlogic.gdx.scenes.scene2d.Stage; 16 import com.badlogic.gdx.scenes.scene2d.actors.Label; 17 import com.badlogic.gdx.scenes.scene2d.ui.Button; 18 import com.badlogic.gdx.scenes.scene2d.ui.CheckBox; 19 import com.badlogic.gdx.scenes.scene2d.ui.ClickListener; 20 import com.badlogic.gdx.scenes.scene2d.ui.Button.ButtonStyle; 21 import com.badlogic.gdx.scenes.scene2d.ui.CheckBox.CheckBoxStyle; 22 23 public class FirstGame implements ApplicationListener { 24 25 private Stage stage; 26 Label label; 27 Texture texture1; 28 Texture texture2; 29 CheckBox checkBox; 30 31 @Override 32 public void create() { 33 stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), 34 true); 35 texture1 = new Texture(Gdx.files.internal("06.png")); 36 texture2 = new Texture(Gdx.files.internal("07.png")); 37 NinePatch n1 = new NinePatch(texture1, 7, 7, 9, 9); 38 BitmapFont bitmapFont = new BitmapFont(Gdx.files.internal("cf.fnt"), 39 Gdx.files.internal("cf.png"), false); 40 label = new Label("fpsLabel", bitmapFont, "label1"); 41 label.x = 5; 42 label.y = Gdx.graphics.getHeight() - label.height - 5; 43 CheckBoxStyle style = new CheckBoxStyle(new TextureRegion(texture1), 44 new TextureRegion(texture2), bitmapFont, new Color(1, 1, 1, 45 0.5f)); 46 47 checkBox = new CheckBox("checkbox", style, "checkbox"); 48 checkBox.x = 100; 49 checkBox.y = 100; 50 checkBox.width = 158f; 51 checkBox.height = 32f; 52 checkBox.setText("Yes"); 53 checkBox.setClickListener(new ClickListener() { 54 55 @Override 56 public void click(Actor actor) { 57 if (checkBox.isChecked) { 58 checkBox.setText("Yes"); 59 } else { 60 checkBox.setText("NO"); 61 } 62 } 63 }); 64 stage.addActor(checkBox); 65 stage.addActor(label); 66 Gdx.input.setInputProcessor(stage); 67 } 68 69 @Override 70 public void dispose() { 71 stage.dispose(); 72 } 73 74 @Override 75 public void pause() { 76 // TODO Auto-generated method stub 77 78 } 79 80 @Override 81 public void render() { 82 Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT); 83 label.setWrappedText("FPS: " + Gdx.graphics.getFramesPerSecond(), 84 HAlignment.CENTER); 85 stage.act(Gdx.graphics.getDeltaTime()); 86 stage.draw(); 87 } 88 89 @Override 90 public void resize(int width, int height) { 91 // TODO Auto-generated method stub 92 93 } 94 95 @Override 96 public void resume() { 97 // TODO Auto-generated method stub 98 99 } 100 }
效果:
其他的UI大致用法差不多,显示的样式在对应的Style或者Skin中定义。但是要注意有些UI类需要手动设置width和height,不然有些显示会很奇怪的。
最后说一下Slider的用法。
SliderStyle需要一个NinePath和Texture,我最初没有想通为什么不是两个NinePath,仔细看一下源码才了解到,NinePath是作为背景,而Texture那个是中间的那个滑动的方块。
关于用配置文件设置Style的问题,google code的wiki上似乎没有写,但是在libgdx的论坛里面有,比如
1 somePatch1: [ 2 { height: 13, width: 9, x: 761, y: 78 }, 3 { height: 13, width: 1, x: 770, y: 78 }, 4 { height: 13, width: 9, x: 771, y: 78 }, 5 { height: 1, width: 9, x: 761, y: 91 }, 6 { height: 1, width: 1, x: 770, y: 91 }, 7 { height: 1, width: 9, x: 771, y: 91 }, 8 { height: 13, width: 9, x: 761, y: 92 }, 9 { height: 13, width: 1, x: 770, y: 92 }, 10 { height: 13, width: 9, x: 771, y: 92 } 11 ]
或者
1 somePatch2: [ 2 { height: 13, width: 9, x: 761, y: 78 }, 3 ]








浙公网安备 33010602011771号