如何在 TouchEvent 或 TrackBallMoveEvent 上使用文本旋转圆圈。
我如何创建这样的圈子?
我创建了一个圆圈并旋转它,但它总是从 0 度开始。
有没有其他选择来创建这种圈子?
每个圆圈都有不同的文字,每个圆圈都可以独立移动。
如何在 TouchEvent 或 TrackBallMoveEvent 上使用文本旋转圆圈。
我如何创建这样的圈子?
我创建了一个圆圈并旋转它,但它总是从 0 度开始。
有没有其他选择来创建这种圈子?
每个圆圈都有不同的文字,每个圆圈都可以独立移动。
所以,这绝对是不完整的,但我认为这是你最需要的。
本质上,我创建了一个Field
子类来表示每个光盘。您可以通过传入一个标签数组来创建该字段,这些标签将围绕周长、半径和颜色进行间隔。每个硬编码DiscField
是文本的边缘插图,假设光盘之间存在一定的大小差异。你可能应该让它更有活力。
public class DiscField extends Field {
/** Used to map Manager's TouchEvents into our coordinate system */
private int _offset = 0;
private int _radius;
private int _fillColor;
private double _currentRotation = 0.0;
private double _lastTouchAngle = 0.0;
private boolean _rotating = false;
private String[] _labels;
/** Text inset from outer disc edge */
private static final int INSET = 30;
private DiscField() {
}
public DiscField(String[] labels, int radius, int fillColor) {
super(Field.FOCUSABLE);
_labels = labels;
_radius = radius;
_fillColor = fillColor;
}
protected void layout(int width, int height) {
setExtent(Math.min(width, getPreferredWidth()), Math.min(height, getPreferredHeight()));
}
private void drawFilledCircle(Graphics g, int x, int y, int r) {
// http://stackoverflow.com/a/1186851/119114
g.fillEllipse(x, y, x + r, y, x, y + r, 0, 360);
}
private void drawCircle(Graphics g, int x, int y, int r) {
g.drawEllipse(x, y, x + r, y, x, y + r, 0, 360);
}
protected void paint(Graphics graphics) {
int oldColor = graphics.getColor();
graphics.setColor(_fillColor);
drawFilledCircle(graphics, _radius, _radius, _radius);
graphics.setColor(Color.WHITE);
drawCircle(graphics, _radius, _radius, _radius);
// plot the text around the circle, inset by some 'padding' value
int textColor = (_fillColor == Color.WHITE) ? Color.BLACK : Color.WHITE;
graphics.setColor(textColor);
// equally space the labels around the disc
double interval = (2.0 * Math.PI / _labels.length);
for (int i = 0; i < _labels.length; i++) {
// account for font size when plotting text
int fontOffsetX = getFont().getAdvance(_labels[i]) / 2;
int fontOffsetY = getFont().getHeight() / 2;
int x = _radius + (int) ((_radius - INSET) * Math.cos(i * interval - _currentRotation)) - fontOffsetX;
int y = _radius - (int) ((_radius - INSET) * Math.sin(i * interval - _currentRotation)) - fontOffsetY;
graphics.drawText(_labels[i], x, y);
}
graphics.setColor(oldColor);
}
protected void drawFocus(Graphics graphics, boolean on) {
if (on) {
int oldColor = graphics.getColor();
int oldAlpha = graphics.getGlobalAlpha();
// just draw a white shine to indicate focus
graphics.setColor(Color.WHITE);
graphics.setGlobalAlpha(80);
drawFilledCircle(graphics, _radius, _radius, _radius);
// reset graphics context
graphics.setColor(oldColor);
graphics.setGlobalAlpha(oldAlpha);
}
}
protected void onUnfocus() {
super.onUnfocus();
_rotating = false;
}
protected boolean touchEvent(TouchEvent event) {
switch (event.getEvent()) {
case TouchEvent.MOVE: {
setFocus();
// Get the touch location, within this Field
int x = event.getX(1) - _offset - _radius;
int y = event.getY(1) - _offset - _radius;
if (x * x + y * y <= _radius * _radius) {
double angle = MathUtilities.atan2(y, x);
if (_rotating) {
// _lastTouchAngle only valid if _rotating
_currentRotation += angle - _lastTouchAngle;
// force a redraw (paint) with the new rotation angle
invalidate();
} else {
_rotating = true;
}
_lastTouchAngle = angle;
return true;
}
}
case TouchEvent.UNCLICK:
case TouchEvent.UP: {
_rotating = false;
return true;
}
case TouchEvent.DOWN: {
setFocus();
int x = event.getX(1) - _offset - _radius;
int y = event.getY(1) - _offset - _radius;
if (x * x + y * y <= _radius * _radius) {
_lastTouchAngle = MathUtilities.atan2(y, x);
_rotating = true;
return true;
}
}
default:
break;
}
return super.touchEvent(event);
}
protected boolean trackwheelRoll(int arg0, int arg1, int arg2) {
return super.trackwheelRoll(arg0, arg1, arg2);
// TODO!
}
public int getPreferredHeight() {
return getPreferredWidth();
}
public int getPreferredWidth() {
return 2 * _radius;
}
public String[] getLabels() {
return _labels;
}
public void setLabels(String[] labels) {
this._labels = labels;
}
public int getRadius() {
return _radius;
}
public void setRadius(int radius) {
this._radius = radius;
}
public double getCurrentAngle() {
return _currentRotation;
}
public void setCurrentAngle(double angle) {
this._currentRotation = angle;
}
public int getOffset() {
return _offset;
}
public void setOffset(int offset) {
this._offset = offset;
}
}
包含所有DiscField
对象的是DiscManager
. 它将子元素对齐DiscFields
,并处理触摸事件的适当委托......因为字段重叠,并且不属于其半径(即角)的范围sublayout()
内的触摸应该由更大的圆盘处理。DiscField
/**
* A DiscManager is a container for DiscFields and manages proper delegation
* of touch event handling.
*/
private class DiscManager extends Manager {
private int _maxRadius = 0;
public DiscManager(long style){
super(style);
DiscField outerDisc = new DiscField(new String[] { "1", "2", "3", "4", "5", "6" },
180, Color.BLUE);
_maxRadius = outerDisc.getRadius();
DiscField middleDisc = new DiscField(new String[] { "1", "2", "3", "4", "5" },
120, Color.GRAY);
middleDisc.setOffset(_maxRadius - middleDisc.getRadius());
DiscField innerDisc = new DiscField(new String[] { "1", "2", "3", "4" },
60, Color.RED);
innerDisc.setOffset(_maxRadius - innerDisc.getRadius());
// order matters here:
add(outerDisc);
add(middleDisc);
add(innerDisc);
}
protected void sublayout(int width, int height) {
setExtent(2 * _maxRadius, 2 * _maxRadius);
// each disc needs to have the same x,y center to be concentric
for (int i = 0; i < getFieldCount(); i++) {
if (getField(i) instanceof DiscField) {
DiscField disc = (DiscField) getField(i);
int xCenter = _maxRadius - disc.getRadius();
int yCenter = _maxRadius - disc.getRadius();
setPositionChild(disc, xCenter, yCenter);
layoutChild(disc, 2 * _maxRadius, 2 * _maxRadius);
}
}
}
protected boolean touchEvent(TouchEvent event) {
int eventCode = event.getEvent();
// Get the touch location, within this Manager
int x = event.getX(1);
int y = event.getY(1);
if ((x >= 0) && (y >= 0) && (x < getWidth()) && (y < getHeight())) {
int field = getFieldAtLocation(x, y);
if (field >= 0) {
DiscField df = null;
for (int i = 0; i < getFieldCount(); i++) {
if (getField(field) instanceof DiscField) {
int r = ((DiscField)getField(field)).getRadius();
// (_maxRadius, _maxRadius) is the center of all discs
if ((x - _maxRadius) * (x - _maxRadius) + (y - _maxRadius) * (y - _maxRadius) <= r * r) {
df = (DiscField)getField(field);
} else {
// touch was not within this disc's radius, so the one slightly bigger
// should be passed this touch event
break;
}
}
}
// Let event propagate to child field
return (df != null) ? df.touchEvent(event) : super.touchEvent(event);
} else {
if (eventCode == TouchEvent.DOWN) {
setFocus();
}
// Consume the event
return true;
}
}
// Event wasn't for us, let superclass handle in default manner
return super.touchEvent(event);
}
}
最后,使用它们的屏幕:
public class DiscScreen extends MainScreen {
public DiscScreen() {
super(MainScreen.VERTICAL_SCROLL | MainScreen.VERTICAL_SCROLLBAR);
add(new DiscManager(Field.USE_ALL_WIDTH));
}
}