image.png
package com.mytian.mgarden.stages.other;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.Group;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Touchable;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
public class CircularSeekBar extends Group {
private Texture backgroundT;
private Texture progressT;
private float progress = 0;
private float backgroundX;
private float backgroundY;
private float progressX;
private float progressY;
private float barX;
private float barY;
private float radius;
private Image bar;
private ISeekProgressUpdate iSeekProgressUpdate;
public int duration;
private float[] polygonVertices;
private short[] polygonTriangles;
public void setiSeekProgressUpdate(ISeekProgressUpdate iSeekProgressUpdate) {
this.iSeekProgressUpdate = iSeekProgressUpdate;
}
public interface ISeekProgressUpdate {
void OnSeekProgressUpdate(float progress);
}
public CircularSeekBar(final Texture backgroundT
, final Texture progressT, final Texture barT) {
this.backgroundT = backgroundT;
this.progressT = progressT;
backgroundT.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
progressT.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
barT.setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
setSize(Math.max(backgroundT.getWidth(), progressT.getWidth())
+ barT.getWidth() / 2
, Math.max(backgroundT.getHeight(), progressT.getHeight())
+ barT.getHeight() / 2);
backgroundX = (getWidth() - backgroundT.getWidth()) / 2;
backgroundY = (getHeight() - backgroundT.getHeight()) / 2;
progressX = (getWidth() - progressT.getWidth()) / 2;
progressY = (getHeight() - progressT.getHeight()) / 2;
radius = progressT.getWidth() / 2;
bar = new Image(barT);
barY = (float) (getHeight() / 2 + (getHeight() / 2 - 8)
* Math.cos(Math.toRadians(360 * progress)));
barX = (float) (getWidth() / 2 + (getWidth() / 2 - 8)
* Math.sin(Math.toRadians(360 * progress)));
addActor(bar);
bar.setPosition(barX - bar.getWidth() / 2
, barY - bar.getHeight() / 2);
bar.setTouchable(Touchable.disabled);
addListener(new ClickListener() {
@Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
super.touchDown(event, x, y, pointer, button);
if (bar.getX() + bar.getWidth() > x && x > bar.getX() - bar.getWidth()
&& bar.getY() + bar.getHeight() > y && y > bar.getY() - bar.getHeight()) {
return true;
}
return false;
}
@Override
public void touchDragged(InputEvent event, float x, float y, int pointer) {
super.touchDragged(event, x, y, pointer);
final Vector2 vector21 = new Vector2(0, getHeight() / 2);
final Vector2 vector22 = new Vector2(x - getWidth() / 2
, y - getHeight() / 2);
float m =
(float) ((vector21.x * vector22.x + vector21.y * vector22.y) / (Math.sqrt(vector21.x * vector21.x + vector21.y * vector21.y)
* Math.sqrt(vector22.x * vector22.x + vector22.y * vector22.y)));
float degrees = (float) Math.toDegrees(Math.acos(m));
if (x > getWidth() / 2) {
progress = degrees / 360;
} else {
progress = (360 - degrees) / 360;
}
barY = (float) (getHeight() / 2 + (getHeight() / 2 - 8)
* Math.cos(Math.toRadians(360 * progress)));
barX = (float) (getWidth() / 2 + (getWidth() / 2 - 8)
* Math.sin(Math.toRadians(360 * progress)));
bar.setPosition(barX - bar.getWidth() / 2
, barY - bar.getHeight() / 2);
}
@Override
public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
super.touchUp(event, x, y, pointer, button);
if (null != iSeekProgressUpdate) {
iSeekProgressUpdate
.OnSeekProgressUpdate(progress);
}
}
});
}
public void setProgress(final float progress, final int duration) {
this.progress = Math.min(1, progress);
barY = (float) (getHeight() / 2 + (getHeight() / 2 - 8)
* Math.cos(Math.toRadians(360 * progress)));
barX = (float) (getWidth() / 2 + (getWidth() / 2 - 8)
* Math.sin(Math.toRadians(360 * progress)));
bar.setPosition(barX - bar.getWidth() / 2, barY - bar.getHeight() / 2);
this.duration = duration;
}
static int SPLIT_NUMS = 180;
@Override
protected void positionChanged() {
super.positionChanged();
backgroundX += getX();
backgroundY += getY();
progressX += getX();
progressY += getY();
barY = (float) (getHeight() / 2 + (getHeight() / 2 - 8)
* Math.cos(Math.toRadians(360 * progress)));
barX = (float) (getWidth() / 2 + (getWidth() / 2 - 8)
* Math.sin(Math.toRadians(360 * progress)));
bar.setPosition(barX - bar.getWidth() / 2, barY - bar.getHeight() / 2);
polygonVertices = new float[(SPLIT_NUMS + 1) * 5];
float color = Color.WHITE.toFloatBits();
polygonVertices[0] = radius + progressX;
polygonVertices[1] = radius + progressY;
polygonVertices[2] = color;
polygonVertices[3] = 0.5f;
polygonVertices[4] = 0.5f;
for (int i = 0; i < SPLIT_NUMS; i++) {
polygonVertices[5 * (i + 1)] =
(float) (radius + radius * Math.sin(2 * Math.PI / SPLIT_NUMS * i)) + progressX;
polygonVertices[5 * (i + 1) + 1] =
(float) (radius + radius * Math.cos(2 * Math.PI / SPLIT_NUMS * i)) + progressY;
polygonVertices[5 * (i + 1) + 2] = color;
polygonVertices[5 * (i + 1) + 3] =
(float) (0.5f + 0.5f * Math.sin(2 * Math.PI / SPLIT_NUMS * i));
polygonVertices[5 * (i + 1) + 4] =
(float) (0.5f + 0.5f * Math.cos(2 * Math.PI / SPLIT_NUMS * i));
} // 三角形坐标点,颜色、U、V坐标
polygonTriangles = new short[SPLIT_NUMS * 3];
for (int i = 0; i < SPLIT_NUMS; i++) {
polygonTriangles[3 * i] = 0;
polygonTriangles[3 * i + 1] = (short) (i + 1);
if (i == SPLIT_NUMS - 1) {
polygonTriangles[3 * i + 2] = 1;
} else {
polygonTriangles[3 * i + 2] = (short) (i + 2);
}
} // 画三角形时的顶点索引坐标
}
@Override
public void draw(final Batch batch, final float parentAlpha) {
batch.draw(backgroundT, backgroundX, backgroundY);
if (batch instanceof PolygonSpriteBatch) {
final int nums = (int) (SPLIT_NUMS * progress);
((PolygonSpriteBatch) batch).draw(progressT, polygonVertices
, 0, Math.min((nums + 2) * 5, polygonVertices.length),
polygonTriangles, 0
, Math.min(nums * 3, polygonTriangles.length)); //画圆
}
super.draw(batch, parentAlpha);
}
}
原理是根据OpenGL 画三角形,来生成圆,然后把纹理UV坐标映射到三角形。
网友评论