1.提供两种小球模式:重力模式和手势模式
2.重力模式中,小球跟随重力进行移动
3.手势模式中,小球跟随手指滑动进行移动
4.在设置中,可以调整小球的大小,颜色,玩法模式
5.要求用户每次退出后再打开小球设置和位置为上次关闭时数据
package com.dji.myapplication2;import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.ColorDrawable;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.SeekBar;public class MainActivity extends AppCompatActivity implements SensorEventListener{private ImageView iv;private boolean isGravityEnabled = false;private float mSensorX;private float mSensorY;private float mLastX;private float mLastY;private int defaultSize = 100;private String defaultColor = "红色";private int ballColors = Color.RED;private int GRAVITY = 1;private int ballSize = 100;private BallView ballView;private int requestCode = 1;private static final String PREF_MODE_X = "MyGravityX";private static final String SELECTED_OPTION_KEY_LOCAD_X = "selectedGravityX";private static final String PREF_MODE_Y = "MyGravityY";private static final String SELECTED_OPTION_KEY_LOCAD_Y = "selectedGravityY";private SensorManager sensorManager;private Sensor gravitySensor;@SuppressLint({"MissingInflatedId", "WrongViewCast"})@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);iv = findViewById(R.id.settingsIcon);iv.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(MainActivity.this, SettingsActivity.class);startActivity(intent);Log.i("Tag","1");//将小球位置信息保存到本地SharedPreferences中SharedPreferences.Editor editorX = getSharedPreferences(PREF_MODE_X, Context.MODE_PRIVATE).edit();SharedPreferences.Editor editorY = getSharedPreferences(PREF_MODE_Y, Context.MODE_PRIVATE).edit();if (ballView != null) {editorX.putInt(SELECTED_OPTION_KEY_LOCAD_X, (int) ballView.getX());editorY.putInt(SELECTED_OPTION_KEY_LOCAD_Y, (int) ballView.getY());}editorY.apply();editorX.apply();}});SharedPreferences sharedPreferences = getSharedPreferences("MyPrefs", Context.MODE_PRIVATE);SharedPreferences sharedPreference = getSharedPreferences("reekbar", Context.MODE_PRIVATE);SharedPreferences sharedPreferencess = getSharedPreferences("MyGravity", Context.MODE_PRIVATE);// 在Activity中获取用户设置的数据String ballColor = sharedPreferences.getString("selectedOption", defaultColor);String gravity = sharedPreferencess.getString("selectedGravity", defaultColor);ballSize = sharedPreference.getInt("seekBarSize", defaultSize);Log.i("Tag",gravity);if (gravity.equals("重力模式")) {isGravityEnabled = true;}else {isGravityEnabled = false;}if (ballColor.equals("红色")) {ballColors = Color.RED;}else if (ballColor.equals("蓝色")){ballColors = Color.BLUE;}else if (ballColor.equals("绿色")){ballColors = Color.GREEN;}else if (ballColor.equals("黄色")){ballColors = Color.YELLOW;}else{ballColors = Color.WHITE;}Log.i("Tag",gravity);SharedPreferences sharedPreferenceX = getSharedPreferences("MyGravityX", Context.MODE_PRIVATE);SharedPreferences sharedPreferenceY = getSharedPreferences("MyGravityY", Context.MODE_PRIVATE);int mLastX = sharedPreferenceX.getInt("selectedGravityX", 50);int mLastY = sharedPreferenceY.getInt("selectedGravityY", 50);ballView = new BallView(this);ballView.setImageResource(R.drawable.ball_shape); // 设置小球图片ballView.setColorFilter(ballColors); // 设置小球颜色为红色RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ballSize, ballSize); // 设置小球大小layoutParams.setMargins((int) mLastX, (int) mLastY, 0, 0); // 设置小球初始位置ballView.setLayoutParams(layoutParams);RelativeLayout layout = findViewById(R.id.settingsLayout);layout.addView(ballView);// 获取重力传感器sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);gravitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);// 注册重力传感器监听器sensorManager.registerListener(this, gravitySensor, SensorManager.SENSOR_DELAY_GAME);// 在主Activity中注册广播接收器BroadcastReceiver receiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {if (intent.getAction().equals("refresh_ball")) {refreshBall();}}};registerReceiver(receiver, new IntentFilter("refresh_ball"));}private void refreshBall() {// 重新加载主 activity,可以通过重新启动 activity 或者刷新数据的方式重新加载// 重新启动 activityIntent intent = getIntent();finish();startActivity(intent);}@Overridepublic void onSensorChanged(SensorEvent event) {if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {mSensorX = event.values[0];mSensorY = event.values[1];if (isGravityEnabled && ballView != null) {// 根据重力传感器数据更新小球的位置float newX = ballView.getX() + mSensorX;float newY = ballView.getY() + mSensorY;ballView.setX(newX);ballView.setY(newY);// 确保小球不超出屏幕边界checkBoundaries();}}}private void checkBoundaries() {if (ballView.getX() < 0) {ballView.setX(0);} else if (ballView.getX() > getScreenWidth() - ballSize) {ballView.setX(getScreenWidth() - ballSize);}}private float getScreenWidth() {DisplayMetrics displayMetrics = new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);return displayMetrics.widthPixels;}@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) {// 空实现}@Overrideprotected void onResume() {super.onResume();if (isGravityEnabled) {sensorManager.registerListener(this, gravitySensor, SensorManager.SENSOR_DELAY_GAME);}}@Overrideprotected void onPause() {super.onPause();sensorManager.unregisterListener(this);}@Overridepublic boolean onTouchEvent(MotionEvent event) {if (!isGravityEnabled) {float newX = event.getX();float newY = event.getY();ballView.setX(newX);ballView.setY(newY);checkBoundaries();}return super.onTouchEvent(event);}
}
package com.dji.myapplication2;import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Display;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;import androidx.annotation.Nullable;public class BallView extends androidx.appcompat.widget.AppCompatImageView {private float mLastX;private float mLastY;private float ballRadiu;private int ballColors;private SharedPreferences sharedPreferences ;public BallView(Context context) {super(context);}public BallView(Context context, AttributeSet attrs) {super(context, attrs);}@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:mLastX = event.getX();mLastY = event.getY();break;case MotionEvent.ACTION_MOVE:float dx = event.getX() - mLastX;float dy = event.getY() - mLastY;setX(getX() + dx);setY(getY() + dy);mLastX = event.getX();mLastY = event.getY();break;}return true;}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);// 绘制小球canvas.drawCircle(mLastX, mLastY, ballRadiu,new Paint());}public void redrawBall(float ballX, float ballY, float ballRadius,int ballColor) {// 在这里添加重新绘制小球的逻辑// 例如改变小球的位置或颜色mLastX = ballX;// 新的球的x坐标mLastY = ballY;// 新的球的y坐标ballRadiu = ballRadius;// 新的球的半径ballColors= ballColor;// 重新绘制invalidate();}}
package com.dji.myapplication2;import androidx.appcompat.app.AppCompatActivity;import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import android.content.Context;public class SettingsActivity extends AppCompatActivity {private static final String PREF_NAME = "MyPrefs";private static final String SELECTED_OPTION_KEY = "selectedOption";private static final String PREF_MODE = "MyGravity";private static final String SELECTED_OPTION_KEY_GRAVITY = "selectedGravity";private static final String PREFS_REEKBAR = "reekbar";private static final String SEEK_BAR_SIZE_REEKBAR = "seekBarSize";private Button selectButton,btnGravity, btnSave;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_settings);selectButton = findViewById(R.id.selectButton);btnGravity = findViewById(R.id.btnGravity);btnSave = findViewById(R.id.btnSave);SeekBar seekBar = findViewById(R.id.sizeSeekBar);TextView textView = findViewById(R.id.text);SharedPreferences prefs = getSharedPreferences(PREFS_REEKBAR, MODE_PRIVATE);int savedSeekBarSize = prefs.getInt(SEEK_BAR_SIZE_REEKBAR, 0);seekBar.setProgress(savedSeekBarSize);textView.setText("当前大小为:" + savedSeekBarSize);seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {// 在TextView中实时显示SeekBar的大小textView.setText("当前大小为:" + progress);// 保存SeekBar的当前大小到SharedPreferencesSharedPreferences.Editor editor = getSharedPreferences(PREFS_REEKBAR, MODE_PRIVATE).edit();editor.putInt(SEEK_BAR_SIZE_REEKBAR, progress);editor.apply();}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {// 开始拖动SeekBar时的回调}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {// 停止拖动SeekBar时的回调}});// 恢复用户最近的选择SharedPreferences sharedPreferences = getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);String lastSelectedOption = sharedPreferences.getString(SELECTED_OPTION_KEY, "No selection made");// 恢复用户最近的选择SharedPreferences sharedPreferences1 = getSharedPreferences(PREF_MODE, Context.MODE_PRIVATE);String lastSelectedOption1 = sharedPreferences1.getString(SELECTED_OPTION_KEY_GRAVITY, "No selection made");btnGravity.setText(lastSelectedOption1);btnGravity.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {showSelectionGravityDialog();
// Toast.makeText(SettingsActivity.this, "选择模式当前模式为:手势操作", Toast.LENGTH_SHORT).show();}});selectButton.setText(lastSelectedOption);selectButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {showSelectionDialog();}});btnSave.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Intent intent = new Intent("refresh_ball");sendBroadcast(intent);finish();}});}private void showSelectionGravityDialog() {final String[] items = {"手势操作", "重力模式"};AlertDialog.Builder builder = new AlertDialog.Builder(this);builder.setTitle("选择你的模式");builder.setItems(items, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {String selectedGravity = items[which];Toast.makeText(SettingsActivity.this, "You selected: " + selectedGravity, Toast.LENGTH_SHORT).show();btnGravity.setText(selectedGravity); // 更新按钮文本为所选项// 保存用户选择到SharedPreferencesSharedPreferences sharedPreferences = getSharedPreferences(PREF_MODE, Context.MODE_PRIVATE);SharedPreferences.Editor editor = sharedPreferences.edit();editor.putString(SELECTED_OPTION_KEY_GRAVITY,selectedGravity);editor.apply();dialog.dismiss();}});builder.show();}private void showSelectionDialog() {final String[] items = {"红色", "蓝色", "绿色", "黄色", "白色"};AlertDialog.Builder builder = new AlertDialog.Builder(this);builder.setTitle("选择你的颜色");builder.setItems(items, new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {String selectedOption = items[which];Toast.makeText(SettingsActivity.this, "You selected: " + selectedOption, Toast.LENGTH_SHORT).show();selectButton.setText(selectedOption); // 更新按钮文本为所选项// 保存用户选择到SharedPreferencesSharedPreferences sharedPreferences = getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);SharedPreferences.Editor editor = sharedPreferences.edit();editor.putString(SELECTED_OPTION_KEY,selectedOption);editor.apply();dialog.dismiss();}});builder.show();}@Overridepublic void onBackPressed() {Intent intent = new Intent();intent.putExtra("REPAINT_BALL", false); // 不重新绘制小球setResult(RESULT_OK, intent);finish();}}
在 \res\drawable目录下创建小球样式设置
<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="oval"><solid android:color="#FF0000" /><size android:width="50dp" android:height="50dp" />
</shape>
设置图标布局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"xmlns:app="http://schemas.android.com/apk/res-auto"android:background="#000000"android:id="@+id/settingsLayout"><!-- <ImageView-->
<!-- android:id="@+id/ball"-->
<!-- android:layout_width="50dp"-->
<!-- android:layout_height="50dp"-->
<!-- android:src="@drawable/ball_shape"-->
<!-- android:layout_marginStart="50dp"-->
<!-- android:layout_marginTop="50dp" />--><ImageViewandroid:id="@+id/settingsIcon"android:layout_width="20dp"android:layout_height="20dp"android:src="@drawable/ball_shape"android:layout_alignParentEnd="true"android:layout_marginTop="30dp"android:layout_marginEnd="30dp" /></RelativeLayout>
设置相关的布局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:id="@+id/selectButton"android:layout_marginTop="20dp"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="红色"></Button><TextViewandroid:id="@+id/text"android:text="当前大小为:50"android:layout_marginTop="20dp"android:layout_below="@+id/selectButton"android:layout_width="match_parent"android:layout_height="wrap_content"/><SeekBarandroid:id="@+id/sizeSeekBar"android:max="100"android:progress="50"android:layout_width="match_parent"android:layout_height="wrap_content"android:thumb="@drawable/ball_shape"android:layout_below="@+id/text"/><Buttonandroid:id="@+id/btnGravity"android:layout_below="@+id/sizeSeekBar"android:text="手势操作"android:layout_marginTop="20dp"android:layout_width="match_parent"android:layout_height="wrap_content"/><Buttonandroid:id="@+id/btnSave"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_alignParentBottom="true"android:text="Save"android:layout_margin="10dp" /></RelativeLayout>