Android加速度计开发水平仪:靶心原点与气泡边界限制问题
Let’s break down your two challenges and fix them step by step to get your level working exactly how you want it!
1. Setting the Bullseye Center as Accelerometer X:0 Y:0 Origin
Your bullseye is already centered via ConstraintLayout, but we need to map its physical center to the accelerometer’s (0,0) point. Here’s how to do it properly:
Key Steps:
- First, get the bullseye’s actual center coordinates (we can’t do this in
onCreatebecause views haven’t finished rendering yet). - Use those center coordinates as the base for all bubble position calculations.
Code Modifications:
First, add global variables to track critical positions:
private ImageView bullseye; private ImageView bubble; private float bullseyeCenterX; private float bullseyeCenterY; private float maxOffset; // Max distance bubble can move from center
Then, initialize these values once the view is fully drawn (using ViewTreeObserver):
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.your_layout); bullseye = findViewById(R.id.bullseye); bubble = findViewById(R.id.bubble); xview = findViewById(R.id.xview); yview = findViewById(R.id.yview); // Wait for views to render before calculating positions bullseye.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // Remove listener to avoid repeated calls bullseye.getViewTreeObserver().removeOnGlobalLayoutListener(this); // Calculate bullseye's center point bullseyeCenterX = bullseye.getX() + bullseye.getWidth() / 2f; bullseyeCenterY = bullseye.getY() + bullseye.getHeight() / 2f; // Calculate maximum allowed bubble offset (bullseye radius minus bubble radius) float bullseyeRadius = bullseye.getWidth() / 2f; float bubbleRadius = bubble.getWidth() / 2f; maxOffset = bullseyeRadius - bubbleRadius; // Initialize bubble to center resetBubbleToCenter(); } }); }
2. Initialize Bubble to Center & Restrict It to Bullseye Radius
Your current code uses raw accelerometer values to set absolute positions, which causes the bubble to drift endlessly and go outside the bullseye. We’ll fix this by:
- Starting the bubble exactly at the bullseye center
- Scaling accelerometer values to fit within the bullseye’s bounds
- Clamping the bubble’s position so it never leaves the green area
Code for Initialization & Position Clamping:
Add this helper method to reset the bubble to center:
private void resetBubbleToCenter() { // Set bubble's top-left corner so its center matches the bullseye's center float bubbleX = bullseyeCenterX - bubble.getWidth() / 2f; float bubbleY = bullseyeCenterY - bubble.getHeight() / 2f; bubble.setX(bubbleX); bubble.setY(bubbleY); }
Update your onSensorChanged method to use relative offsets instead of absolute values:
@Override public void onSensorChanged(SensorEvent event) { if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) { // Map accelerometer values (-9.8 to 9.8) to our max allowed offset float scaleFactor = maxOffset / 9.8f; // Adjust sign for Y-axis to match screen orientation (tweak if needed for your device) float offsetX = event.values[0] * scaleFactor; float offsetY = -event.values[1] * scaleFactor; // Clamp offsets to keep bubble inside bullseye offsetX = Math.max(-maxOffset, Math.min(maxOffset, offsetX)); offsetY = Math.max(-maxOffset, Math.min(maxOffset, offsetY)); // Calculate bubble's final position (account for bubble's own size) float bubbleX = bullseyeCenterX - bubble.getWidth()/2f + offsetX; float bubbleY = bullseyeCenterY - bubble.getHeight()/2f + offsetY; // Update bubble position bubble.setX(bubbleX); bubble.setY(bubbleY); // Update display values (show offset from center) xview.setText(String.format("X: %.2f", offsetX)); yview.setText(String.format("Y: %.2f", offsetY)); } }
Layout Fix for Bubble:
Your current bubble layout has constraints that might interfere with manual positioning. Update it to be centered in the parent (so initial layout matches our code’s center position):
<ImageView android:id="@+id/bubble" android:layout_width="31dp" android:layout_height="31dp" android:contentDescription="Bubble" android:src="@drawable/ic_bubble" android:scaleType="centerInside" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" />
内容的提问来源于stack exchange,提问作者c63Coupe

