Android
下面那些都是很久之前寫的東西
現在的話用 Kotlin + Jetpack Compose 吧
Index:
Change landscpe and no action bar when Activity extends AppCompatActivity
Button click event template/sample
Draw pixel art on background full screen
Use normal layout and custom View at same time
Use immersive sticky mode (no navigation bar, state bar)
Get width, height when using immersive sticky mode
Activity flow with surfaceview and navigation button press.
You can't restart thread, you should new a instance to use.
Set Color relate to /res/value/color.xml
Change project name on Android Studio
0001
Change landscpe and no action bar when Activity extends AppCompatActivity
add following code to AndroidManifest.xml
in activity
tag
//<activity ..
android:screenOrientation="landscape"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
tools:ignore="LockedOrientationActivity"
// ... >
0002
Button click event template/sample
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
Button btnStart;
Button btnExit;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnStart = findViewById(R.id.btnStart);
btnExit = findViewById(R.id.btnExit);
btnStart.setOnClickListener(this);
btnExit.setOnClickListener(this);
}
@Override
public void onClick(View v) {
if(v == btnStart){
Log.i("", "btnStart click");
}else if(v == btnExit){
Log.i("", "btnExit click");
}
/*
switch(v.getId()){
case R.id.btnStart:
break;
case R.id.btnExit:
break;
}
*/
}
}
https://spicyboyd.blogspot.com/2018/04/apponclick5.html
Button should not assign before setContentView(R.layout.activity_main)
0003
Draw pixel art on background full screen
remember background.png
put on drawable-nodpi
folder
public class MenuBackground extends View {
Bitmap bitmap;
Paint paint = new Paint();
int width;
int height;
public MenuBackground(Context context) {
super(context);
bitmap = BitmapFactory.decodeResource(this.getResources(), R.drawable.background);
paint.setAntiAlias(false);
paint.setDither(true);
paint.setFilterBitmap(false);
width = bitmap.getWidth();
height = bitmap.getHeight();
}
@Override
protected void onDraw(Canvas canvas) {
canvas.scale(getWidth() / (float)width , getHeight() / (float)height);
canvas.drawBitmap(bitmap,0,0, paint);
super.onDraw(canvas);
}
}
https://stackoverflow.com/questions/46028774/disable-anti-aliasing-on-android-imageview
http://www.41post.com/4241/programming/android-disabling-anti-aliasing-for-pixel-art
0004
Use normal layout and custom View at same time
get layout class and use addView()
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
root = findViewById(R.id.root);
root.addView(new MenuBackground(this));
}
0005
Use immersive sticky mode (no navigation bar, state bar)
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
static void setImmersiveSticky(Activity activity){
int option = View.SYSTEM_UI_FLAG_LOW_PROFILE
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
activity.getWindow().getDecorView().setSystemUiVisibility(option);
}
https://developer.android.google.cn/training/system-ui/immersive?hl=zh-cn
https://www.jianshu.com/p/11a2b780fd9b
0006
Get width, height when using immersive sticky mode
DisplayMetrics displaymetrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getRealMetrics(displaymetrics);
screenWidth = displaymetrics.widthPixels;
screenHeight = displaymetrics.heightPixels;
0007
Open another activity
Intent intent = new Intent(this, GameActivity.class);
startActivity(intent);
0008
Navigation back button click
override this:
@Override
public void onBackPressed() {
super.onBackPressed();
}
if you delete super.onBackPressed();
,
You can't exit or back to upper activity by click navigation back button.
it is good and we can control the behavior of navigation back button.
Also, there are tutorial for press Back button two times and back :
https://www.youtube.com/watch?v=1Nmy88n7CZ8
0009
Navigation Home Press
No, you can't.
You can't override Home button.
https://stackoverflow.com/questions/4783960/call-method-when-home-button-pressed
https://stackoverflow.com/questions/8881951/detect-home-button-press-in-android/8883447#8883447
0010
Activity flow with surfaceview and navigation button press.
there show three flow line:
[1] : onStart -> onResume -> sufaceCreated -> surfaceChanged
[2] : onPause -> surfaceDestroyed
[3] : onBackPressed -> [2]
and flow event:
Start app -> [1]
[1] -> Press Home or Overview(the third/right one) -> [2]
[2] -> Back to app -> [1]
[1] -> press Back(the left one) -> [3]
You can control press back behaviour by override onBackPressed : 0008
https://source.android.com/devices/graphics/arch-sv-glsv
https://blog.csdn.net/ttmxh/article/details/7530531
0011
You can't restart thread, you should new a instance to use.
0012
Set Color relate to /res/value/color.xml
int color = ContextCompat.getColor(context, R.color.white);
paint.setColor(color);
https://stackoverflow.com/questions/12899428/how-to-set-paint-setcolorr-color-white
0013
Change Bitmap Color
Paint p = new Paint();
ColorFilter filter = new LightingColorFilter(Color.RED, 0);
p.setColorFilter(filter);
https://gamedev.stackexchange.com/questions/5393/how-do-i-blend-a-bitmap-with-a-color
https://stackoverflow.com/questions/5699810/how-to-change-bitmap-image-color-in-android
On the other hand, you can change pixel by pixel
https://stackoverflow.com/questions/11449687/android-change-the-color-of-a-bitmap
https://stackoverflow.com/a/55204374/11693034
0014
Play Sound
MediaPlayer mediaPlayer;
mediaPlayer = MediaPlayer.create(<Context>, R.raw.xxx);
// Start
mediaPlayer.start();
// Stop (can not restart)
mediaPlayer.stop();
// Releases resources
mediaPlayer.release();
// Reset (can restart) //
mediaPlayer.pause();
mediaPlayer.seekTo(0);
// Looping
mediaPlayer.setLooping(true);
https://developer.android.com/guide/topics/media/mediaplayer
0015
Change project name on Android Studio
- Close Android Studio
- Change project root directory name
- Open Android Studio
- Open the project (not from local history but by browsing to it)
- Clean project
If your settings.gradle
contains the below line, either delete it or update it to the new name.
rootProject.name = 'Your project name'
Rebuild Project
Click File -> Sync Project with Gradle Files
https://stackoverflow.com/questions/18276872/change-project-name-on-android-studio
0016
Play Video
videoView = findViewById(R.id.videoView);
String path = "android.resource://" + getPackageName() + "/" + R.raw.samplevideo;
Uri uri = Uri.parse(path);
videoView.setVideoURI(uri);
// Start
videoView.start();
// Pause
videoView.pause();
// Reset (can restart) //
videoView.pause();
videoView.seekTo(0);
// I don't know how to use resume(), stop()
https://developer.android.com/reference/android/widget/VideoView.html
0017
Sensor Orientation
package com.example.motionsensorstest;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity implements SensorEventListener{
SensorManager sensorManager;
private Sensor accelerometer;
private Sensor magnetometer;
float[] accelerometerValues = new float[3];
float[] magneticFieldValues = new float[3];
float[] values = new float[3];
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
assert sensorManager != null;
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
magnetometer = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
}
protected void onResume() {
super.onResume();
sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_UI);
sensorManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_UI);
}
@Override
protected void onPause() {
super.onPause();
sensorManager.unregisterListener(this);
}
public void onSensorChanged(SensorEvent sensorEvent) {
switch (sensorEvent.sensor.getType()) {
case Sensor.TYPE_MAGNETIC_FIELD:
magneticFieldValues = sensorEvent.values;
break;
case Sensor.TYPE_ACCELEROMETER:
accelerometerValues = sensorEvent.values;
break;
}
updateOrientation();
Log.i("","z: " + values[0] + "\tx: " + values[1] + "\ty: " + values[2]);
}
private void updateOrientation() {
float[] R = new float[9];
SensorManager.getRotationMatrix(R, null, accelerometerValues, magneticFieldValues);
SensorManager.getOrientation(R, values);
values[0] = (float) Math.toDegrees(values[0]);
values[1] = (float) Math.toDegrees(values[1]);
values[2] = (float) Math.toDegrees(values[2]);
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
Log.i("", "onAccuracyChanged()");
}
}
Package to be a class MyOrientationSensorManager
:
package com.example.motionsensorstest;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.Log;
public class MyOrientationSensorManager implements SensorEventListener {
public Context context;
public SensorManager sensorManager;
public Sensor accelerometer;
public Sensor magnetometer;
public float[] accelerometerValues = new float[3];
public float[] magneticFieldValues = new float[3];
public float[] values = new float[3];
MyOrientationSensorManager(Context context){
this.context = context;
sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
assert sensorManager != null;
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
magnetometer = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
}
public void reset(){
sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_UI);
sensorManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_UI);
}
public void cancel(){
sensorManager.unregisterListener(this);
}
public void onSensorChanged(SensorEvent sensorEvent) {
switch (sensorEvent.sensor.getType()) {
case Sensor.TYPE_MAGNETIC_FIELD:
magneticFieldValues = sensorEvent.values;
break;
case Sensor.TYPE_ACCELEROMETER:
accelerometerValues = sensorEvent.values;
break;
}
updateOrientation();
Log.i("","z: " + values[0] + "\tx: " + values[1] + "\ty: " + values[2]);
}
private void updateOrientation() {
float[] R = new float[9];
SensorManager.getRotationMatrix(R, null, accelerometerValues, magneticFieldValues);
SensorManager.getOrientation(R, values);
values[0] = (float) Math.toDegrees(values[0]);
values[1] = (float) Math.toDegrees(values[1]);
values[2] = (float) Math.toDegrees(values[2]);
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
Log.i("", "onAccuracyChanged()");
}
}