天天看點

深入了解Libgdx中的Skin類

             本文不是直接翻譯。。。本文在Libgdx的官方wiki的基礎上,加上一些自己的了解。是以,難免會一些甚至是很多的了解很片面的東西。寫的不好,還請見諒。。。。

其實

其實,在LibGDX的官方文檔對Skin這個類的介紹中,其主要介紹了以下幾個方面:

1、往Skin裡面添加資源的兩種方式。

2、從Skin中擷取資源的方式。

第一種方式:以atlas為操作對象:

atlas = new TextureAtlas(Gdx.files.internal("meijia.atlas"), Gdx.files.internal(""));
		skin = new Skin();//Skin求是就是一個資源管理類...
		skin.addRegions(atlas);
		region = skin.get("BG1", TextureRegion.class);
           

解析:對于skin.get(name,type)中的name,它與atlas檔案中的資源的名字是一緻的。也就是說他與atlas.findRegion(name)中的name是一樣的。

以下對skin的get(name,type)的源碼進行以下分析:

public <T> T get (String name, Class<T> type) {//根據類型和名字傳回相應的資源
		 //如果name(名字)或者是類型(type)為空,則抛出參數非法異常(IllegalArgumentException)和相應的提示資訊
		if (name == null) throw new IllegalArgumentException("name cannot be null.");
		if (type == null) throw new IllegalArgumentException("type cannot be null.");

        //判斷想要擷取的類型是否是TDNS(TextureRegion、Drawable、NinePatch、Sprite)中的一種,如果是調用相應的getXXX()方法 
		if (type == Drawable.class) return (T)getDrawable(name);
		if (type == TextureRegion.class) return (T)getRegion(name);
		if (type == NinePatch.class) return (T)getPatch(name);
		if (type == Sprite.class) return (T)getSprite(name);

        //如果不是上面的4種類型,則去資源中看一下是否有這種類型(type)及名字(name)的資源存在.
		ObjectMap<String, Object> typeResources = resources.get(type);
		if (typeResources == null) throw new GdxRuntimeException("No " + type.getName() + " registered with name: " + name);
		Object resource = typeResources.get(name);
		if (resource == null) throw new GdxRuntimeException("No " + type.getName() + " registered with name: " + name);
		return (T)resource;
           

小結:也就是說skin.get(name,type)這個函數主要幹了這麼一件事:

1)先看一下參數是否符合,如果不符合則抛出相應的異常及提示資訊。

2)如果參數沒有什麼錯誤的話,就去找找type是否指TDNS(關于這個是什麼意思請看上面的源碼分析)類型,如果是,則直接傳回。

3)否則再去resource中找是否有類型為type,名字為name的這麼一種資源。如果沒有則抛出相應的異常及提示資訊

第二種方式:以普通對象作為操作的基本對象

skin.add("color", Color.RED);
		Color color = skin.getColor("color");
           

解釋:

對于上面的“Color color = skin.getColor("color");”或許寫成Color color1 = skin.get("green", Color.class);會比較符合初學者的心态。嗯嗯,其實getColor(name)函數實作的時候會去調get(name,Color.class)這個函數。也就是說

Libgdx官方wiki中所提到的“Convinience methods(便利方法)”getXXX(name)函數底層都是去調相應的get(name,XXX)函數。事實勝于雄辯,源碼面前無秘密。

以下貼出libgdx中的Skin類中關于這幾個函數的實作。

public Color getColor (String name) {
		return get(name, Color.class);
	}
           
public BitmapFont getFont (String name) {
		return get(name, BitmapFont.class);
	}
           

這個方法其實完成了這麼一件事: 其實這裡面是先取name為XXX的TextureRegion,假如取不到,就嘗試去取name為XXX的Texture,如果能娶到,再通過取到的Texture生成TextureRegion,并存進Skin中。治愈一下的getSprite什麼的,邏輯都類似

/** Returns a registered texture region. If no region is found but a texture exists with the name, a region is created from the
	 * texture and stored in the skin. */
	public TextureRegion getRegion (String name) {
		TextureRegion region = optional(name, TextureRegion.class);
		if (region != null) return region;

		Texture texture = optional(name, Texture.class);
		if (texture == null) throw new GdxRuntimeException("No TextureRegion or Texture registered with name: " + name);
		region = new TextureRegion(texture);
		add(name, region, Texture.class);
		return region;
	}
           
/** Returns a registered tiled drawable. If no tiled drawable is found but a region exists with the name, a tiled drawable is
	 * created from the region and stored in the skin. */
	public TiledDrawable getTiledDrawable (String name) {
		TiledDrawable tiled = optional(name, TiledDrawable.class);
		if (tiled != null) return tiled;

		Drawable drawable = optional(name, Drawable.class);
		if (tiled != null) {
			if (!(drawable instanceof TiledDrawable)) {
				throw new GdxRuntimeException("Drawable found but is not a TiledDrawable: " + name + ", "
					+ drawable.getClass().getName());
			}
			return tiled;
		}

		tiled = new TiledDrawable(getRegion(name));
		add(name, tiled, TiledDrawable.class);
		return tiled;
	}
           
/** Returns a registered ninepatch. If no ninepatch is found but a region exists with the name, a ninepatch is created from the
	 * region and stored in the skin. If the region is an {@link AtlasRegion} then the {@link AtlasRegion#splits} are used,
	 * otherwise the ninepatch will have the region as the center patch. */
	public NinePatch getPatch (String name) {
		NinePatch patch = optional(name, NinePatch.class);
		if (patch != null) return patch;

		try {
			TextureRegion region = getRegion(name);
			if (region instanceof AtlasRegion) {
				int[] splits = ((AtlasRegion)region).splits;
				if (splits != null) {
					patch = new NinePatch(region, splits[0], splits[1], splits[2], splits[3]);
					int[] pads = ((AtlasRegion)region).pads;
					if (pads != null) patch.setPadding(pads[0], pads[1], pads[2], pads[3]);
				}
			}
			if (patch == null) patch = new NinePatch(region);
			add(name, patch, NinePatch.class);
			return patch;
		} catch (GdxRuntimeException ex) {
			throw new GdxRuntimeException("No NinePatch, TextureRegion, or Texture registered with name: " + name);
		}
	}
           
/** Returns a registered sprite. If no sprite is found but a region exists with the name, a sprite is created from the region
	 * and stored in the skin. If the region is an {@link AtlasRegion} then an {@link AtlasSprite} is used if the region has been
	 * whitespace stripped or packed rotated 90 degrees. */
	public Sprite getSprite (String name) {
		Sprite sprite = optional(name, Sprite.class);
		if (sprite != null) return sprite;

		try {
			TextureRegion textureRegion = getRegion(name);
			if (textureRegion instanceof AtlasRegion) {
				AtlasRegion region = (AtlasRegion)textureRegion;
				if (region.rotate || region.packedWidth != region.originalWidth || region.packedHeight != region.originalHeight)
					sprite = new AtlasSprite(region);
			}
			if (sprite == null) sprite = new Sprite(textureRegion);
			add(name, sprite, NinePatch.class);
			return sprite;
		} catch (GdxRuntimeException ex) {
			throw new GdxRuntimeException("No NinePatch, TextureRegion, or Texture registered with name: " + name);
		}
	}
           
/** Returns a registered drawable. If no drawable is found but a region, ninepatch, or sprite exists with the name, then the
	 * appropriate drawable is created and stored in the skin. */
	public Drawable getDrawable (String name) {
		Drawable drawable = optional(name, Drawable.class);
		if (drawable != null) return drawable;

		drawable = optional(name, TiledDrawable.class);
		if (drawable != null) return drawable;

		// Use texture or texture region. If it has splits, use ninepatch. If it has rotation or whitespace stripping, use sprite.
		try {
			TextureRegion textureRegion = getRegion(name);
			if (textureRegion instanceof AtlasRegion) {
				AtlasRegion region = (AtlasRegion)textureRegion;
				if (region.splits != null)
					drawable = new NinePatchDrawable(getPatch(name));
				else if (region.rotate || region.packedWidth != region.originalWidth || region.packedHeight != region.originalHeight)
					drawable = new SpriteDrawable(getSprite(name));
			}
			if (drawable == null) drawable = new TextureRegionDrawable(textureRegion);
		} catch (GdxRuntimeException ignored) {
		}

		// Check for explicit registration of ninepatch, sprite, or tiled drawable.
		if (drawable == null) {
			NinePatch patch = optional(name, NinePatch.class);
			if (patch != null)
				drawable = new NinePatchDrawable(patch);
			else {
				Sprite sprite = optional(name, Sprite.class);
				if (sprite != null)
					drawable = new SpriteDrawable(sprite);
				else
					throw new GdxRuntimeException("No Drawable, NinePatch, TextureRegion, Texture, or Sprite registered with name: "
						+ name);
			}
		}

		add(name, drawable, Drawable.class);
		return drawable;
	}
           

3、Skin在建立UI控件中的使用。

第一種方式:

TextButtonStyle buttonStyle = skin.get("bigButton", TextButtonStyle.class);
TextButton button = new TextButton("Click me!", buttonStyle);
           

第二種方式:

TextButton button = new TextButton("Click me!", skin, "bigButton");
           

當沒有第三個參數的時候j将預設去skin中找名為default的資源

4、拷貝Skin裡面的資源

官方原話:

Resources obtained from the skin are not new instances, the same object is returned each time. If the object is modified, the changes will be reflected throughout the application. If this is not desired, a copy of the object should be made.

The 

newDrawable

 method copies a drawable. The new drawable's size information can be changed without affecting the original. The method can also tint a drawable.

也就是說,Skin裡面的資源都是單例的,如果你在某一處修改了它,那麼它在其他地方也會改變。如果這不是所期望的,那麼可以使用newDrawable(name,type )這個函數來拷貝Skin裡面的資源。

用法:

//修改資源..拷貝(copy)skin裡面的資源
		Drawable pinkDrawable = skin.newDrawable("BG1",Color.PINK);
		image = new Image(pinkDrawable);
           

以下是官方wiki中的部分文字的部分翻譯:其實看懂上面的東西就行了。因為官方wiki基本講的就是這些東西。。

Overview 綜述

The Skin class stores resources for UI widgets to use. It is a convenient container for texture regions, ninepatches, fonts, colors, etc. Skin also provides convenient conversions, such as retrieving a texture region as a ninepatch, sprite, or drawable.

Skin這個類主要是為UI 元件存儲一些資源(Resource).它也提供了一些友善的轉換。如存進去的時候是Texture類型,取出來的時候可以直接當成TextureRegion類型去出來(其實這裡面是先取name為XXX的TextureRegion,假如取不到,就嘗試去取name為XXX的Texture,如果能娶到,再通過取到的Texture生成TextureRegion,并存進Skin中)。

Skin files from the libgdx tests can be used as a starting point. You will need: uiskin.png, uiskin.atlas, uiskin.json, and default.fnt. This enables you to quickly get started using scene2d.ui and replace the skin assets later.

libgdx tests這個項目中(也就是官方提供的Gdx-tests的這個例子)的skin 的相關檔案來作為學習Skin這個類的起點。你将需要 相應的.png

.fnt    、atlas、json檔案來作為學習Skin這個類的起點。他們能幫助你很快的學習Skin。

Resources in a skin typically come from a texture atlas, widget styles and other objects defined using JSON, and objects added to the skin via code. Even when JSON is not used, it is still recommended to use Skin with a texture atlas and objects added via code. This is much more convenient to obtain instances of drawables and serves as a central place to obtain UI resources.

以下是我自己做的一個Demo:

http://download.csdn.net/detail/caihongshijie6/7610309