3

如何在 TouchEvent 或 TrackBallMoveEvent 上使用文本旋转圆圈。

  1. 我如何创建这样的圈子?

    我创建了一个圆圈并旋转它,但它总是从 0 度开始。

  2. 有没有其他选择来创建这种圈子?

每个圆圈都有不同的文字,每个圆圈都可以独立移动

在此处输入图像描述

4

1 回答 1

7

所以,这绝对是不完整的,但我认为这是你最需要的。

限制/假设

  1. 到目前为止,我只实现了触摸处理,因为我认为这更困难。如果我以后有时间,我会回来添加轨迹球处理。
  2. 我没有给旋转的圆盘任何动力。用户的手指离开光盘后,光盘停止旋转。
  3. 我不确定光盘之间的焦点转换是否 100% 正确。你必须做一些测试。至少,他们大多是对的。
  4. 当您在标题中提到Canvas时,我认为这并不意味着您需要它来使用J2ME Canvas。使用 RIM UI 库编写 BlackBerry 应用程序几乎是我所做的全部工作。

解决方案

本质上,我创建了一个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));
   }
}

结果

在此处输入图像描述

于 2012-12-05T13:04:29.083 回答