android游戏开发框架libgdx的使用(五)--舞台和常用UI类

转自:http://www.apkbus.com/forum.php?mod=viewthread&tid=19751&extra=page%3D1%26filter%3Dauthor%26orderby%3Ddateline%26orderby%3Ddateline

 

常用的UI类包括标签,按钮,勾选框,下拉框,图片,输入框,列表,滑动面板,滑条,分割面板。它们都在com.badlogic.gdx.scenes.scene2d.ui包中,都属于Actor,可以方便的纳入舞台的管理中。

其实仔细看看UI类的实现代码不难发现其实它们都是大部分继承自Widget或者Table,如果需要自定义UI可以继承以上两个类(它们继承自Actor),这里要说明一下libgdx的布局部分使用了TWL,有兴趣的朋友可以去看看。

在介绍每个控件之前我们先来看一下NinePatch,这是最近的一个比较重大的更新。

何为NinePatch?其实android原生即有NinePatch类,常在按钮中使用。

1.jpg

 

2012-1-17 11:57 上传
下载附件(11.45 KB)

如图,将图片分成九份。中间部分可以根据需要扩大,使按钮的大小内容变动不受图片的限制。

而在libgdx的NinePatch其实就是九个TextureRegion对象。

常用的实例化方法有两个:


 

  1. public NinePatch (Texture texture, int left, int right, int top, int bottom)

  2. 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. float rightColumnX = x + width;
  10. if (patches[BOTTOM_RIGHT] != null)
  11. rightColumnX -= patches[BOTTOM_RIGHT].getRegionWidth();
  12. else if (patches[MIDDLE_RIGHT] != null)
  13. rightColumnX += patches[MIDDLE_RIGHT].getRegionWidth();
  14. else if (patches[TOP_RIGHT] != null) //
  15. rightColumnX += patches[TOP_RIGHT].getRegionWidth();

  16. float middleRowY = y;
  17. if (patches[TOP_LEFT] != null)
  18. middleRowY += patches[TOP_LEFT].getRegionHeight();
  19. else if (patches[TOP_CENTER] != null)
  20. middleRowY += patches[TOP_CENTER].getRegionHeight();
  21. else if (patches[TOP_RIGHT] != null) //
  22. middleRowY += patches[TOP_RIGHT].getRegionHeight();

  23. float topRowY = y + height;
  24. if (patches[TOP_LEFT] != null)
  25. topRowY -= patches[TOP_LEFT].getRegionHeight();
  26. else if (patches[TOP_CENTER] != null)
  27. topRowY -= patches[TOP_CENTER].getRegionHeight();
  28. else if (patches[TOP_RIGHT] != null) //
  29. topRowY -= patches[TOP_RIGHT].getRegionHeight();

  30. // Bottom row
  31. if (patches[BOTTOM_LEFT] != null) batch.draw(patches[BOTTOM_LEFT], x, y, centerColumnX - x, middleRowY - y);
  32. if (patches[BOTTOM_CENTER] != null)
  33. batch.draw(patches[BOTTOM_CENTER], centerColumnX, y, rightColumnX - centerColumnX, middleRowY - y);
  34. if (patches[BOTTOM_RIGHT] != null)
  35. batch.draw(patches[BOTTOM_RIGHT], rightColumnX, y, x + width - rightColumnX, middleRowY - y);

  36. // Middle row
  37. if (patches[MIDDLE_LEFT] != null) batch.draw(patches[MIDDLE_LEFT], x, middleRowY, centerColumnX - x, topRowY - middleRowY);
  38. if (patches[MIDDLE_CENTER] != null)
  39. batch.draw(patches[MIDDLE_CENTER], centerColumnX, middleRowY, rightColumnX - centerColumnX, topRowY - middleRowY);
  40. if (patches[MIDDLE_RIGHT] != null)
  41. batch.draw(patches[MIDDLE_RIGHT], rightColumnX, middleRowY, x + width - rightColumnX, topRowY - middleRowY);

  42. // Top row
  43. if (patches[TOP_LEFT] != null) batch.draw(patches[TOP_LEFT], x, topRowY, centerColumnX - x, y + height - topRowY);
  44. if (patches[TOP_CENTER] != null)
  45. batch.draw(patches[TOP_CENTER], centerColumnX, topRowY, rightColumnX - centerColumnX, y + height - topRowY);
  46. if (patches[TOP_RIGHT] != null)
  47. batch.draw(patches[TOP_RIGHT], rightColumnX, topRowY, x + width - rightColumnX, y + height - topRowY);
  48. }
复制代码
先计算左右栏的宽度,在计算中间和顶部的高度。然后从下自上的绘制。说实话我觉得这段代码看着很好玩的。
现在来说说几个常用的控件的使用吧。先构建一个舞台。
先来试试Label吧,label是有缓存的,所以替换显示内容不是用setText方法,而是使用setWrappedText方法。
代码如下:


 

  1. package com.cnblogs.htynkn.listener;

  2. import com.badlogic.gdx.ApplicationListener;
  3. import com.badlogic.gdx.Gdx;
  4. import com.badlogic.gdx.graphics.GL10;
  5. import com.badlogic.gdx.graphics.g2d.BitmapFont;
  6. import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment;
  7. import com.badlogic.gdx.scenes.scene2d.Stage;
  8. import com.badlogic.gdx.scenes.scene2d.actors.Label;

  9. public class FirstGame implements ApplicationListener {

  10. private Stage stage;
  11. Label label;

  12. @Override
  13. public void create() {
  14. stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(),
  15. true);
  16. label = new Label("fpsLabel", new BitmapFont(Gdx.files.internal("cf.fnt"),Gdx.files.internal("cf.png"),false), "label1");
  17. label.x=5;
  18. label.y=Gdx.graphics.getHeight()-label.height-5;
  19. stage.addActor(label);
  20. Gdx.input.setInputProcessor(stage);
  21. }

  22. @Override
  23. public void dispose() {
  24. stage.dispose();
  25. }

  26. @Override
  27. public void pause() {
  28. // TODO Auto-generated method stub

  29. }

  30. @Override
  31. public void render() {
  32. Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
  33. label.setWrappedText("FPS: "+Gdx.graphics.getFramesPerSecond(),
  34. HAlignment.CENTER);
  35. stage.act(Gdx.graphics.getDeltaTime());
  36. stage.draw();
  37. }

  38. @Override
  39. public void resize(int width, int height) {
  40. // TODO Auto-generated method stub

  41. }

  42. @Override
  43. public void resume() {
  44. // TODO Auto-generated method stub

  45. }
  46. }
复制代码

效果:
2.jpg

2012-1-17 11:57 上传
下载附件(14.04 KB)



然后再看看Button吧,实例化需要一个ButtonStyle,定义了按钮三种状态对应的图片样式,按下和松开时的X,Y偏移还有Button中文字绘制所需的BitmapFont和Color。按钮的三种状态的图片我就省了,只用一张图片。

3.png

2012-1-17 12:02 上传
下载附件(23.81 KB)



修改代码如下:

  1. package com.cnblogs.htynkn.listener;

  2. import com.badlogic.gdx.ApplicationListener;
  3. import com.badlogic.gdx.Gdx;
  4. import com.badlogic.gdx.graphics.Color;
  5. import com.badlogic.gdx.graphics.GL10;
  6. import com.badlogic.gdx.graphics.Texture;
  7. import com.badlogic.gdx.graphics.g2d.BitmapFont;
  8. import com.badlogic.gdx.graphics.g2d.NinePatch;
  9. import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment;
  10. import com.badlogic.gdx.scenes.scene2d.Stage;
  11. import com.badlogic.gdx.scenes.scene2d.actors.Label;
  12. import com.badlogic.gdx.scenes.scene2d.ui.Button;
  13. import com.badlogic.gdx.scenes.scene2d.ui.Button.ButtonStyle;

  14. public class FirstGame implements ApplicationListener {

  15. private Stage stage;
  16. Label label;
  17. Texture texture;
  18. Button button;

  19. @Override
  20. public void create() {
  21. stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(),
  22. true);
  23. texture = new Texture(Gdx.files.internal("06.png"));
  24. NinePatch n1 = new NinePatch(texture, 7, 7, 9, 9);
  25. BitmapFont bitmapFont = new BitmapFont(Gdx.files.internal("cf.fnt"),
  26. Gdx.files.internal("cf.png"), false);
  27. label = new Label("fpsLabel", bitmapFont, "label1");
  28. label.x = 5;
  29. label.y = Gdx.graphics.getHeight() - label.height - 5;
  30. stage.addActor(label);
  31. button = new Button("button", new ButtonStyle(n1, n1, n1, 0f, 0f, 0f,
  32. 0f, bitmapFont, new Color(1, 1, 0, 0.5f)), "button");
  33. button.x=10;
  34. button.y=10;
  35. button.width=100f;
  36. button.height=32f;
  37. stage.addActor(button);
  38. Gdx.input.setInputProcessor(stage);
  39. }

  40. @Override
  41. public void dispose() {
  42. stage.dispose();
  43. }

  44. @Override
  45. public void pause() {
  46. // TODO Auto-generated method stub

  47. }

  48. @Override
  49. public void render() {
  50. Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
  51. label.setWrappedText("FPS: " + Gdx.graphics.getFramesPerSecond(),
  52. HAlignment.CENTER);
  53. stage.act(Gdx.graphics.getDeltaTime());
  54. stage.draw();
  55. }

  56. @Override
  57. public void resize(int width, int height) {
  58. // TODO Auto-generated method stub

  59. }

  60. @Override
  61. public void resume() {
  62. // TODO Auto-generated method stub

  63. }
  64. }
复制代码

效果:

4.jpg

2012-1-17 12:02 上传
下载附件(13.01 KB)



按钮自然应该有点击事件,通过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。这里我再添加一张图片

5.png

2012-1-17 12:02 上传
下载附件(7.78 KB)



原理差不多,直接贴代码了。

  1. package com.cnblogs.htynkn.listener;

  2. import android.graphics.Paint.Align;

  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.TextureRegion;
  11. import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment;
  12. import com.badlogic.gdx.scenes.scene2d.Actor;
  13. import com.badlogic.gdx.scenes.scene2d.Stage;
  14. import com.badlogic.gdx.scenes.scene2d.actors.Label;
  15. import com.badlogic.gdx.scenes.scene2d.ui.Button;
  16. import com.badlogic.gdx.scenes.scene2d.ui.CheckBox;
  17. import com.badlogic.gdx.scenes.scene2d.ui.ClickListener;
  18. import com.badlogic.gdx.scenes.scene2d.ui.Button.ButtonStyle;
  19. import com.badlogic.gdx.scenes.scene2d.ui.CheckBox.CheckBoxStyle;

  20. public class FirstGame implements ApplicationListener {

  21. private Stage stage;
  22. Label label;
  23. Texture texture1;
  24. Texture texture2;
  25. CheckBox checkBox;

  26. @Override
  27. public void create() {
  28. stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(),
  29. true);
  30. texture1 = new Texture(Gdx.files.internal("06.png"));
  31. texture2 = new Texture(Gdx.files.internal("07.png"));
  32. NinePatch n1 = new NinePatch(texture1, 7, 7, 9, 9);
  33. BitmapFont bitmapFont = new BitmapFont(Gdx.files.internal("cf.fnt"),
  34. Gdx.files.internal("cf.png"), false);
  35. label = new Label("fpsLabel", bitmapFont, "label1");
  36. label.x = 5;
  37. label.y = Gdx.graphics.getHeight() - label.height - 5;
  38. CheckBoxStyle style = new CheckBoxStyle(new TextureRegion(texture1),
  39. new TextureRegion(texture2), bitmapFont, new Color(1, 1, 1,
  40. 0.5f));

  41. checkBox = new CheckBox("checkbox", style, "checkbox");
  42. checkBox.x = 100;
  43. checkBox.y = 100;
  44. checkBox.width = 158f;
  45. checkBox.height = 32f;
  46. checkBox.setText("Yes");
  47. checkBox.setClickListener(new ClickListener() {

  48. @Override
  49. public void click(Actor actor) {
  50. if (checkBox.isChecked) {
  51. checkBox.setText("Yes");
  52. } else {
  53. checkBox.setText("NO");
  54. }
  55. }
  56. });
  57. stage.addActor(checkBox);
  58. stage.addActor(label);
  59. Gdx.input.setInputProcessor(stage);
  60. }

  61. @Override
  62. public void dispose() {
  63. stage.dispose();
  64. }

  65. @Override
  66. public void pause() {
  67. // TODO Auto-generated method stub

  68. }

  69. @Override
  70. public void render() {
  71. Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
  72. label.setWrappedText("FPS: " + Gdx.graphics.getFramesPerSecond(),
  73. HAlignment.CENTER);
  74. stage.act(Gdx.graphics.getDeltaTime());
  75. stage.draw();
  76. }

  77. @Override
  78. public void resize(int width, int height) {
  79. // TODO Auto-generated method stub

  80. }

  81. @Override
  82. public void resume() {
  83. // TODO Auto-generated method stub

  84. }
  85. }
复制代码

效果:

6.jpg

2012-1-17 11:58 上传
下载附件(4.04 KB)

7.jpg

2012-1-17 11:57 上传
下载附件(5.17 KB)



其他的UI大致用法差不多,显示的样式在对应的Style或者Skin中定义。但是要注意有些UI类需要手动设置width和height,不然有些显示会很奇怪的。最后说一下Slider的用法。SliderStyle需要一个NinePath和Texture,我最初没有想通为什么不是两个NinePath,仔细看一下源码才了解到,NinePath是作为背景,而Texture那个是中间的那个滑动的方块。关于用配置文件设置Style的问题,google code的wiki上似乎没有写,但是在libgdx的论坛里面有,比如

somePatch1: [
{ height: 13, width: 9, x: 761, y: 78 },
{ height: 13, width: 1, x: 770, y: 78 },
{ height: 13, width: 9, x: 771, y: 78 },
{ height: 1, width: 9, x: 761, y: 91 },
{ height: 1, width: 1, x: 770, y: 91 },
{ height: 1, width: 9, x: 771, y: 91 },
{ height: 13, width: 9, x: 761, y: 92 },
{ height: 13, width: 1, x: 770, y: 92 },
{ height: 13, width: 9, x: 771, y: 92 }
]


或者

somePatch2: [
{ height: 13, width: 9, x: 761, y: 78 },
]

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值