Android绘图画布添加悬浮保存按钮实现方案咨询
Hey there! Adding a floating action button (FAB) for saving your drawing is totally doable—let's break down two straightforward approaches to make this work, along with the save functionality.
Approach 1: Use an XML Layout (Recommended for Flexibility)
Right now you're setting the MyDrawView directly as the content view, which doesn't leave room for other UI elements like a FAB. Instead, create a root layout that holds both your drawing view and the FAB.
Step 1: Create an XML Layout File
Make a new layout file named activity_draw_image.xml (res/layout/activity_draw_image.xml) with a ConstraintLayout as the root:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <!-- Your custom drawing view, takes full screen --> <com.yourpackage.MyDrawView android:id="@+id/draw_view" android:layout_width="match_parent" android:layout_height="match_parent" /> <!-- Save FAB, positioned at bottom-right --> <com.google.android.material.floatingactionbutton.FloatingActionButton android:id="@+id/save_fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="16dp" android:src="@drawable/ic_save" <!-- Use a save icon from your drawables --> app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
Note: Replace com.yourpackage with your actual app package name, and add a save icon to your drawable resources (you can use Android Studio's vector asset generator for this).
Step 2: Update Your DrawImage Activity
Modify your DrawImage class to inflate this layout instead of setting the view directly:
public class DrawImage extends FragmentActivity { private MyDrawView mDrawView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_draw_image); // Get reference to your drawing view mDrawView = findViewById(R.id.draw_view); // Set up the save FAB FloatingActionButton saveFab = findViewById(R.id.save_fab); saveFab.setOnClickListener(v -> saveDrawing()); } private void saveDrawing() { // Call the save method from your MyDrawView boolean saved = mDrawView.saveBitmapToGallery(this); if (saved) { Toast.makeText(this, "Drawing saved!", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "Failed to save drawing", Toast.LENGTH_SHORT).show(); } } }
Step 3: Add Save Functionality to MyDrawView
Add a method to MyDrawView that handles saving the bitmap to the device's gallery:
public boolean saveBitmapToGallery(Context context) { if (mBitmap == null) return false; String fileName = "MyDrawing_" + System.currentTimeMillis() + ".png"; OutputStream outputStream = null; // For Android 10+ (API 29+), use MediaStore if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { ContentValues values = new ContentValues(); values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName); values.put(MediaStore.Images.Media.MIME_TYPE, "image/png"); values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + "/MyDrawings"); Uri uri = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); if (uri != null) { try { outputStream = context.getContentResolver().openOutputStream(uri); mBitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream); return true; } catch (IOException e) { e.printStackTrace(); } finally { try { if (outputStream != null) outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } else { // For older Android versions, use external storage (requires WRITE_EXTERNAL_STORAGE permission) String directoryPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/MyDrawings"; File directory = new File(directoryPath); if (!directory.exists()) directory.mkdirs(); File file = new File(directory, fileName); try { outputStream = new FileOutputStream(file); mBitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream); // Notify gallery of new image MediaScannerConnection.scanFile(context, new String[]{file.getAbsolutePath()}, null, null); return true; } catch (IOException e) { e.printStackTrace(); } finally { try { if (outputStream != null) outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } return false; }
Step 4: Handle Permissions (For Android < 10)
If you're supporting Android versions below 10, add the WRITE_EXTERNAL_STORAGE permission to your AndroidManifest.xml:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" />
And request the permission dynamically in your DrawImage activity before saving (you can add a check in the saveDrawing() method).
Approach 2: Create Layout Programmatically (No XML)
If you prefer to avoid XML, you can build the root layout and FAB entirely in code:
public class DrawImage extends FragmentActivity { private MyDrawView mDrawView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Create root RelativeLayout RelativeLayout rootLayout = new RelativeLayout(this); rootLayout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); // Add your drawing view mDrawView = new MyDrawView(this); RelativeLayout.LayoutParams drawViewParams = new RelativeLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); rootLayout.addView(mDrawView, drawViewParams); // Create and add the FAB FloatingActionButton saveFab = new FloatingActionButton(this); RelativeLayout.LayoutParams fabParams = new RelativeLayout.LayoutParams( ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); fabParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); fabParams.addRule(RelativeLayout.ALIGN_PARENT_END); fabParams.setMargins(0, 0, 16, 16); // Margin in dp (convert to pixels if needed) saveFab.setImageResource(R.drawable.ic_save); saveFab.setOnClickListener(v -> saveDrawing()); rootLayout.addView(saveFab, fabParams); setContentView(rootLayout); } // saveDrawing() method same as Approach 1 private void saveDrawing() { boolean saved = mDrawView.saveBitmapToGallery(this); Toast.makeText(this, saved ? "Drawing saved!" : "Save failed", Toast.LENGTH_SHORT).show(); } }
Key Notes:
- Make sure you've added the Material Components dependency to your
build.gradle(Module level) if usingFloatingActionButton:implementation 'com.google.android.material:material:1.9.0' // Use latest version - Test the save functionality on both older and newer Android versions to ensure compatibility.
- You can also add a clear button (using another FAB or a menu item) by calling the existing
clear()method inMyDrawView.
内容的提问来源于stack exchange,提问作者lessthanmediocre

