【问题标题】:How to take a screenshot of a current Activity and then share it?如何截取当前活动的屏幕截图然后分享?
【发布时间】:2015-07-23 16:28:49
【问题描述】:

我需要截取Activity 的屏幕截图(没有标题栏,用户不应该看到屏幕截图实际上已被截取),然后通过操作菜单按钮“共享”进行共享。我已经尝试了一些解决方案,但它们对我不起作用。有什么想法吗?

【问题讨论】:

标签: android android-studio share screenshot


【解决方案1】:

这就是我捕获屏幕并分享它的方式。

首先,从当前活动中获取根视图:

View rootView = getWindow().getDecorView().findViewById(android.R.id.content);

第二,捕获根视图:

 public static Bitmap getScreenShot(View view) {
       View screenView = view.getRootView();
       screenView.setDrawingCacheEnabled(true);
       Bitmap bitmap = Bitmap.createBitmap(screenView.getDrawingCache());
       screenView.setDrawingCacheEnabled(false);
       return bitmap;
 }

第三,将Bitmap存入SDCard:

public static void store(Bitmap bm, String fileName){
    final static String dirPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Screenshots";
    File dir = new File(dirPath);
    if(!dir.exists())
        dir.mkdirs();
    File file = new File(dirPath, fileName);
    try {
        FileOutputStream fOut = new FileOutputStream(file);
        bm.compress(Bitmap.CompressFormat.PNG, 85, fOut);
        fOut.flush();
        fOut.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

最后分享一下当前Activity的截图:

private void shareImage(File file){
    Uri uri = Uri.fromFile(file);
    Intent intent = new Intent();
    intent.setAction(Intent.ACTION_SEND);
    intent.setType("image/*");

    intent.putExtra(android.content.Intent.EXTRA_SUBJECT, "");
    intent.putExtra(android.content.Intent.EXTRA_TEXT, "");
    intent.putExtra(Intent.EXTRA_STREAM, uri);
    try {
        startActivity(Intent.createChooser(intent, "Share Screenshot"));
    } catch (ActivityNotFoundException e) {
        Toast.makeText(context, "No App Available", Toast.LENGTH_SHORT).show();
    }
}

我希望你会受到我的代码的启发。

更新:

将以下权限添加到您的AndroidManifest.xml

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

因为它在外部存储中创建和访问文件。

更新:

从 Android 7.0 Nougat 开始禁止共享文件链接。要解决这个问题,您必须实现 FileProvider 并共享“content://”uri 而不是“file://”uri。

Here 很好地描述了如何操作。

【讨论】:

  • 当我检查设备存储时,它截取屏幕截图但没有显示在画廊中
  • 不可能。捕获ActivityNotFoundExceptionstartActivity(Intent.createChooser(intent, "Share Screenshot")); 和之后的Toast.makeText(context, "No App Available", Toast.LENGTH_SHORT).show();
  • java.io.FileNotFoundException: /storage/emulated/0/Screenshots/image: 打开失败:ENOENT(没有这样的文件或目录)
  • 有一些错误的地方。在 store() 方法中,String 和 File 都具有相同的名称(dir),因此编译器显然会报错。只需更改其中一个名称。其次,在 shareImage() 方法中,您传递了一个 String 参数,但随后您使用该 String 参数调用了 Uri.fromFile(),这显然是错误的,因为最后一种方法需要一个文件而不是字符串。只需传递文件而不是字符串。最后,store() 方法应该返回写入的文件,因此您可以将其作为参数传递给 shareImage() 方法。
  • 工作就像一个魅力,但如果你想使用这个代码,你应该擅长编码!
【解决方案2】:

点击监听器创建分享按钮

    share = (Button)findViewById(R.id.share);
    share.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Bitmap bitmap = takeScreenshot();
            saveBitmap(bitmap);
            shareIt();
        }
    });

添加两个方法

    public Bitmap takeScreenshot() {
    View rootView = findViewById(android.R.id.content).getRootView();
    rootView.setDrawingCacheEnabled(true);
    return rootView.getDrawingCache();
    }

public void saveBitmap(Bitmap bitmap) {
    imagePath = new File(Environment.getExternalStorageDirectory() + "/screenshot.png");
    FileOutputStream fos;
    try {
        fos = new FileOutputStream(imagePath);
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
        fos.flush();
        fos.close();
    } catch (FileNotFoundException e) {
        Log.e("GREC", e.getMessage(), e);
    } catch (IOException e) {
        Log.e("GREC", e.getMessage(), e);
    }
}

分享屏幕截图。在这里分享实现

    private void shareIt() {
    Uri uri = Uri.fromFile(imagePath);
    Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
    sharingIntent.setType("image/*");
    String shareBody = "In Tweecher, My highest score with screen shot";
    sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "My Tweecher score");
    sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, shareBody);
    sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);

    startActivity(Intent.createChooser(sharingIntent, "Share via"));
    }

【讨论】:

    【解决方案3】:

    此方法无需存储和检索屏幕截图以再次共享。 只需调用方法,您就可以共享屏幕截图。

    private Bitmap screenShot(View view) {
        Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),view.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        view.draw(canvas);
        return bitmap;
    }
    
    private void share(Bitmap bitmap){
        String pathofBmp=
                MediaStore.Images.Media.insertImage(ctx.getContentResolver(),
                        bitmap,"title", null);
        Uri uri = Uri.parse(pathofBmp);
        Intent shareIntent = new Intent(Intent.ACTION_SEND);
        shareIntent.setType("image/*");
        shareIntent.putExtra(Intent.EXTRA_SUBJECT, "Star App");
        shareIntent.putExtra(Intent.EXTRA_TEXT, "");
        shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
        ctx.startActivity(Intent.createChooser(shareIntent, "hello hello"));
    }
    

    这样调用这个方法

    share(screenShot(view));
    

    在没有读写权限的情况下使用此直接共享屏幕截图

    【讨论】:

    • 很好的解决方案,但不推荐使用 MediaStore.Images.Media.insertImage
    • @VLeonovs 如果您可以改进我的回答,即无需在设备上存储屏幕截图并要求存储权限,那将是一件好事。
    • @SarveshHon 如何将整个屏幕作为视图。你能描述一下吗?因为我想分享整个屏幕截图。
    • @MR.Robot 只需为您的父布局分配一个 ID 并将该 ID 提供为视图。
    【解决方案4】:

    您可以使用下面的代码来获取您在屏幕上看到的视图的位图您可以指定创建位图的视图。

        public static Bitmap getScreenShot(View view) {
               View screenView = view.getRootView();
               screenView.setDrawingCacheEnabled(true);
               Bitmap bitmap = Bitmap.createBitmap(screenView.getDrawingCache());
               screenView.setDrawingCacheEnabled(false);
               return bitmap;
         }
    

    【讨论】:

      【解决方案5】:

      在我添加之前,我无法让 Silent Knight's answer 工作

      <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
      <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
      

      致我的AndroidManifest.xml

      【讨论】:

        【解决方案6】:

        您可以截取视图的任何部分。您只需要您想要截取的布局的参考。例如,在您的情况下,您想要活动的屏幕截图。假设您的活动根布局是线性布局。

           // find the reference of the layout which screenshot is required
        
             LinearLayout LL = (LinearLayout) findViewById(R.id.yourlayout);
              Bitmap screenshot = getscreenshot(LL);
        
             //use this method to get the bitmap
              private Bitmap getscreenshot(View view) {
                View v = view;
                v.setDrawingCacheEnabled(true);
                Bitmap bitmap = Bitmap.createBitmap(v.getDrawingCache());
                return bitmap;
              }
        

        【讨论】:

        • 这会抛出这个错误:java.lang.NullPointerException: Attempt to invoke virtual method 'int android.graphics.Bitmap.getWidth()' on a null object reference
        • @bonafernando 看来您正在传递一个空视图。请检查您的布局参考是否为空。
        • 我正在通过该视图的 LinearLayout,我已经仔细检查过......但没关系。我已经把它转过屏幕拍摄滚动视图。
        【解决方案7】:

        截图

         public Bitmap takeScreenshot() {
            View rootView = findViewById(android.R.id.content).getRootView();
            rootView.setDrawingCacheEnabled(true);
            return rootView.getDrawingCache();
        }
        

        保存截图

        private void saveBitmap(Bitmap bitmap) {
            imagePath = new File(Environment.getExternalStorageDirectory() + "/scrnshot.png"); ////File imagePath
            FileOutputStream fos;
            try {
                fos = new FileOutputStream(imagePath);
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
                fos.flush();
                fos.close();
            } catch (FileNotFoundException e) {
                Log.e("GREC", e.getMessage(), e);
            } catch (IOException e) {
                Log.e("GREC", e.getMessage(), e);
            }
        }
        

        为了分享

        private void shareIt() {
            Uri uri = Uri.fromFile(imagePath);
            Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND);
            sharingIntent.setType("image/*");
            String shareBody = "My highest score with screen shot";
            sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, "My Catch score");
            sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, shareBody);
            sharingIntent.putExtra(Intent.EXTRA_STREAM, uri);
        
            startActivity(Intent.createChooser(sharingIntent, "Share via"));
        }
        

        只需在onclick 中即可调用这些方法

        shareScoreCatch.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Bitmap bitmap = takeScreenshot();
                saveBitmap(bitmap);
                shareIt();
           }
        });
        

        【讨论】:

          【解决方案8】:

          对于所有 Xamarin 用户:

          Xamarin.Android 代码:

          创建一个外部类(我为每个平台都有一个接口,我从android平台实现了以下3个功能):

              public static Bitmap TakeScreenShot(View view)
              {
                  View screenView = view.RootView;
                  screenView.DrawingCacheEnabled = true;
                  Bitmap bitmap = Bitmap.CreateBitmap(screenView.DrawingCache);
                  screenView.DrawingCacheEnabled = false;
                  return bitmap;
              }
              public static Java.IO.File StoreScreenShot(Bitmap picture)
              {
                  var folder = Android.OS.Environment.ExternalStorageDirectory + Java.IO.File.Separator + "MyFolderName";
                  var extFileName = Android.OS.Environment.ExternalStorageDirectory +
                                    Java.IO.File.Separator +
                                    Guid.NewGuid() + ".jpeg";
                  try
                  {
                      if (!Directory.Exists(folder))
                          Directory.CreateDirectory(folder);
          
                      Java.IO.File file = new Java.IO.File(extFileName);
          
                      using (var fs = new FileStream(extFileName, FileMode.OpenOrCreate))
                      {
                          try
                          {
                              picture.Compress(Bitmap.CompressFormat.Jpeg, 100, fs);
                          }
                          finally
                          {
                              fs.Flush();
                              fs.Close();
                          }
                          return file;
                      }
                  }
                  catch (UnauthorizedAccessException ex)
                  {
                      Log.Error(LogPriority.Error.ToString(), "-------------------" + ex.Message.ToString());
                      return null;
                  }
                  catch (Exception ex)
                  {
                      Log.Error(LogPriority.Error.ToString(), "-------------------" + ex.Message.ToString());
                      return null;
                  }
              }
              public static void ShareImage(Java.IO.File file, Activity activity, string appToSend, string subject, string message)
              {
                  //Push to Whatsapp to send
                  Android.Net.Uri uri = Android.Net.Uri.FromFile(file);
                  Intent i = new Intent(Intent.ActionSendMultiple);
                  i.SetPackage(appToSend); // so that only Whatsapp reacts and not the chooser
                  i.AddFlags(ActivityFlags.GrantReadUriPermission);
                  i.PutExtra(Intent.ExtraSubject, subject);
                  i.PutExtra(Intent.ExtraText, message);
                  i.PutExtra(Intent.ExtraStream, uri);
                  i.SetType("image/*");
                  try
                  {
                      activity.StartActivity(Intent.CreateChooser(i, "Share Screenshot"));
                  }
                  catch (ActivityNotFoundException ex)
                  {
                      Toast.MakeText(activity.ApplicationContext, "No App Available", ToastLength.Long).Show();
                  }
              }`
          

          现在,从您的 Activity 中,您可以像这样运行上述代码:

                              RunOnUiThread(() =>
                          {
                              //take silent screenshot
                              View rootView = Window.DecorView.FindViewById(Resource.Id.ActivityLayout);
                              Bitmap tmpPic = ShareHandler.TakeScreenShot(this.CurrentFocus); //TakeScreenShot(this);
                              Java.IO.File imageSaved = ShareHandler.StoreScreenShot(tmpPic);
                              if (imageSaved != null)
                              {
                                  ShareHandler.ShareImage(imageSaved, this, "com.whatsapp", "", "ScreenShot Taken from: " + "Somewhere");
                              }
                          });
          

          希望对大家有用。

          【讨论】:

            【解决方案9】:

            您可以尝试以下代码来捕获当前屏幕的屏幕截图,并在没有任何 LIBRARYPERMISSION 的情况下分享该图像。我已经测试了它的工作原理。

            复制粘贴即可。

            1. 在 MainAtivity.java 中

               public class MainActivity extends AppCompatActivity implements View.OnClickListener {
              
                  private Button fullPageScreenshot, customPageScreenshot;
                  private LinearLayout rootContent;
                  private ImageView imageView;
                  private TextView hiddenText;
              
                  @Override
                  protected void onCreate(Bundle savedInstanceState) {
                      super.onCreate(savedInstanceState);
                      setContentView(R.layout.activity_main);
              
                      StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder(); StrictMode.setVmPolicy(builder.build());
                      findViews();
                      implementClickEvents();
                  }
                  /*  Find all views Ids  */
                  private void findViews() {
                      fullPageScreenshot = (Button) findViewById(R.id.full_page_screenshot);
                      customPageScreenshot = (Button) findViewById(R.id.custom_page_screenshot);
                      rootContent = (LinearLayout) findViewById(R.id.root_content);
                      imageView = (ImageView) findViewById(R.id.image_view);
                      hiddenText = (TextView) findViewById(R.id.hidden_text);
                  }
                  /*  Implement Click events over Buttons */
                  private void implementClickEvents() {
                      fullPageScreenshot.setOnClickListener(this);
                      customPageScreenshot.setOnClickListener(this);
                  }
                  @Override
                  public void onClick(View v) {
                      switch (v.getId()) {
                          case R.id.full_page_screenshot:
                              takeScreenshot(ScreenshotType.FULL);
                              break;
                          case R.id.custom_page_screenshot:
                              takeScreenshot(ScreenshotType.CUSTOM);
                              break;
                      }
                  }
              
                  /*  Method which will take screenshot on Basis of Screenshot Type ENUM  */
                  private void takeScreenshot(ScreenshotType screenshotType) {
                      Bitmap b = null;
                      switch (screenshotType) {
                          case FULL:
                              //If Screenshot type is FULL take full page screenshot i.e our root content.
                              b = ScreenshotUtils.getScreenShot(rootContent);
                              break;
                          case CUSTOM:
                              //If Screenshot type is CUSTOM
                              fullPageScreenshot.setVisibility(View.INVISIBLE);//set the visibility to INVISIBLE of first button
                              hiddenText.setVisibility(View.VISIBLE);//set the visibility to VISIBLE of hidden text
                               b = ScreenshotUtils.getScreenShot(rootContent);
                              //After taking screenshot reset the button and view again
                              fullPageScreenshot.setVisibility(View.VISIBLE);//set the visibility to VISIBLE of first button again
                              hiddenText.setVisibility(View.INVISIBLE);//set the visibility to INVISIBLE of hidden text
                              //NOTE:  You need to use visibility INVISIBLE instead of GONE to remove the view from frame else it wont consider the view in frame and you will not get screenshot as you required.
                              break;
                      }
                      //If bitmap is not null
                      if (b != null) {
                          showScreenShotImage(b);//show bitmap over imageview
                          File saveFile = ScreenshotUtils.getMainDirectoryName(this);//get the path to save screenshot
                          File file = ScreenshotUtils.store(b, "screenshot" + screenshotType + ".jpg", saveFile);//save the screenshot to selected path
                          shareScreenshot(file);//finally share screenshot
                      } else
                          //If bitmap is null show toast message
                          Toast.makeText(this, R.string.screenshot_take_failed, Toast.LENGTH_SHORT).show();
                  }
                  /*  Show screenshot Bitmap */
                  private void showScreenShotImage(Bitmap b) {
                      imageView.setImageBitmap(b);
                  }
                  /*  Share Screenshot  */
                  private void shareScreenshot(File file) {
                      Uri uri = Uri.fromFile(file);//Convert file path into Uri for sharing
                      Intent intent = new Intent();
                      intent.setAction(Intent.ACTION_SEND);
                      intent.setType("image/*");
                      intent.putExtra(android.content.Intent.EXTRA_SUBJECT, "");
                      intent.putExtra(android.content.Intent.EXTRA_TEXT, getString(R.string.sharing_text));
                      intent.putExtra(Intent.EXTRA_STREAM, uri);//pass uri here
                      startActivity(Intent.createChooser(intent, getString(R.string.share_title)));
                  }
              }
              
              1. ScreenshotType.java

                public enum ScreenshotType {
                    FULL, CUSTOM;
                }
                
              2. ScreenshotUtils.java

                公共类 ScreenshotUtils {

                /*  Method which will return Bitmap after taking screenshot. We have to pass the view which we want to take screenshot.  */
                public static Bitmap getScreenShot(View view) {
                    View screenView = view.getRootView();
                    screenView.setDrawingCacheEnabled(true);
                    Bitmap bitmap = Bitmap.createBitmap(screenView.getDrawingCache());
                    screenView.setDrawingCacheEnabled(false);
                    return bitmap;
                }
                
                
                /*  Create Directory where screenshot will save for sharing screenshot  */
                public static File getMainDirectoryName(Context context) {
                    //Here we will use getExternalFilesDir and inside that we will make our Demo folder
                    //benefit of getExternalFilesDir is that whenever the app uninstalls the images will get deleted automatically.
                    File mainDir = new File(
                            context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "Demo");
                
                    //If File is not present create directory
                    if (!mainDir.exists()) {
                        if (mainDir.mkdir())
                            Log.e("Create Directory", "Main Directory Created : " + mainDir);
                    }
                    return mainDir;
                }
                
                /*  Store taken screenshot into above created path  */
                public static File store(Bitmap bm, String fileName, File saveFilePath) {
                    File dir = new File(saveFilePath.getAbsolutePath());
                    if (!dir.exists())
                        dir.mkdirs();
                    File file = new File(saveFilePath.getAbsolutePath(), fileName);
                    try {
                        FileOutputStream fOut = new FileOutputStream(file);
                        bm.compress(Bitmap.CompressFormat.JPEG, 85, fOut);
                        fOut.flush();
                        fOut.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    return file;
                
                
                
                }
                

                }

            4.activity_main.xml

            <?xml version="1.0" encoding="utf-8"?>
            <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                xmlns:tools="http://schemas.android.com/tools"
                android:id="@+id/root_content"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical"
                android:padding="10dp"
                tools:context="com.takescreenshot_demo.MainActivity">
            
                <!--  Button which will take full page screenshot  -->
                <Button
                    android:id="@+id/full_page_screenshot"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="@string/full_page_screenshot"
                    android:textColor="@android:color/white"
                    android:textSize="14sp" />
            
                <!--   Hidden Text which will shown when taking screenshot from below Button  -->
                <TextView
                    android:id="@+id/hidden_text"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="center"
                    android:text="@string/hidden_text"
                    android:textColor="@android:color/white"
                    android:textSize="14sp"
                    android:visibility="invisible" />
            
                <!--  Button which will take screenshot after hiding some view and showing some view  -->
                <Button
                    android:id="@+id/custom_page_screenshot"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="@string/custom_page_screenshot"
                    android:textColor="@android:color/white"
                    android:textSize="14sp" />
            
            
                <!--  ImageView to show taken Screenshot  -->
                <ImageView
                    android:id="@+id/image_view"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent"
                    android:scaleType="fitCenter"
                    android:src="@mipmap/ic_launcher" />
            
            </LinearLayout>
            

            【讨论】:

              【解决方案10】:

              合并的复制和粘贴代码:

              private void takeScreenshot() {
                      Date now = new Date();
                      android.text.format.DateFormat.format("yyyy-MM-dd_hh:mm:ss", now);
              
                      try {
                          // image naming and path  to include sd card  appending name you choose for file
                          String mPath = Environment.getExternalStorageDirectory().toString() + "/" + now + ".jpg";
                          String screenshotPath = mPath;
              
                          // create bitmap screen capture
                          View v1 = getWindow().getDecorView().getRootView();
                          v1.setDrawingCacheEnabled(true);
                          Bitmap bitmap = Bitmap.createBitmap(v1.getDrawingCache());
                          v1.setDrawingCacheEnabled(false);
              
                          File imageFile = new File(mPath);
              
                          FileOutputStream outputStream = new FileOutputStream(imageFile);
                          int quality = 100;
                          bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);
                          outputStream.flush();
                          outputStream.close();
              
              //            openScreenshot(imageFile);
                      } catch (Throwable e) {
                          // Several error may come out with file handling or DOM
                          e.printStackTrace();
                      }
                  }
              
              
              
                  //Function to share Screenshot
                  private void shareScreenshots(File file){
                      Uri uri = Uri.fromFile(file);
                      Intent intent = new Intent();
                      intent.setAction(Intent.ACTION_SEND);
                      intent.setType("image/*");
              
                      intent.putExtra(android.content.Intent.EXTRA_SUBJECT, "");
                      intent.putExtra(android.content.Intent.EXTRA_TEXT, "");
                      intent.putExtra(Intent.EXTRA_STREAM, uri);
                      try {
                          startActivity(Intent.createChooser(intent, "Share Screenshot"));
                      } catch (ActivityNotFoundException e) {
                          Toast.makeText(this, "No App Available", Toast.LENGTH_SHORT).show();
                      }
                  }
              
                  //Function to open screenshot
                  private void openScreenshot(File imageFile) {
                      Intent intent = new Intent();
                      intent.setAction(Intent.ACTION_VIEW);
                      Uri uri = Uri.fromFile(imageFile);
                      intent.setDataAndType(uri, "image/*");
                      startActivity(intent);
                  }
              
              

              【讨论】:

                【解决方案11】:

                截至 2021 年,这里是完整的答案,您只需复制过去的代码,它应该可以正常工作,它还使用所有新 API,包括权限启动器和 android q 保存图像的方式
                我将再添加一项功能,即像这样保存在图片文件夹中的文件夹内

                /Pictures/MyAppName/photos.png
                

                此代码还支持 android

                我正在截屏并将其保存到桌面以获取图像的 uri,以便以后分享。

                首先,android上需要权限启动器

                val requestStoragePermissionLauncher =
                    registerForActivityResult(
                        ActivityResultContracts.RequestMultiplePermissions()
                    ) { permissions ->
                        var saveImageFlag = true
                        permissions.entries.forEach {
                            saveImageFlag = it.value
                        }
                        if (saveImageFlag) {
                            shareScreenShootResult()
                        } else {
                            showMessage(getString(R.string.cant_share_ScreenShoot))
                        }
                    }
                
                val permissionListener: () -> Boolean = {
                    if (ContextCompat.checkSelfPermission(
                            requireContext(),
                            Manifest.permission.READ_EXTERNAL_STORAGE
                        ) == PackageManager.PERMISSION_GRANTED &&
                        ContextCompat.checkSelfPermission(
                            requireContext(),
                            Manifest.permission.WRITE_EXTERNAL_STORAGE
                        ) == PackageManager.PERMISSION_GRANTED
                    ) {
                        true
                    } else {
                        requestStoragePermissionLauncher.launch(
                            arrayOf(
                                Manifest.permission.READ_EXTERNAL_STORAGE,
                                Manifest.permission.WRITE_EXTERNAL_STORAGE
                            )
                        )
                        false
                    }
                }
                

                然后next方法给出图片名称并设置目录然后分享图片

                private fun shareScreenShootResult() {
                    val dateFormatter by lazy {
                        SimpleDateFormat(
                            "yyyy.MM.dd 'at' HH:mm:ss z", Locale.getDefault()
                        )
                    }
                    val filename = "${getString(R.string.my_ScreenShoot)}${dateFormatter.format(Date())}.png"
                    val ScreenShootFolderPath = File.separator + requireContext().getAppName()
                
                    val uri = binding.rootLayout.makeScreenShot()
                        .saveScreenShot(requireContext(), filename, ScreenShootFolderPath, permissionListener)
                        ?: return
                
                    dispatchShareImageIntent(uri)
                }
                
                private fun dispatchShareImageIntent(screenShotUri: Uri) {
                    val intent = Intent(Intent.ACTION_SEND)
                    intent.type = "image/png"
                    intent.putExtra(Intent.EXTRA_STREAM, screenShotUri)
                    startActivity(Intent.createChooser(intent, "Share"))
                }
                

                getAppName 是一个扩展函数,你可以将它添加到项目中的任何位置,然后在上下文中调用它,不要忘记导入它。

                fun Context.getAppName(): String {
                    var appName: String = ""
                    val applicationInfo = applicationInfo
                    val stringId = applicationInfo.labelRes
                    appName = if (stringId == 0) {
                        applicationInfo.nonLocalizedLabel.toString()
                    } else {
                        getString(stringId)
                    }
                    return appName
                }
                

                这个方法makeScreenShot是视图上的扩展函数 您最好将所有扩展功能添加到不同的文件中。

                fun View.makeScreenShot(): Bitmap {
                    setBackgroundColor(Color.WHITE)
                    val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
                    val canvas = Canvas(bitmap)
                    draw(canvas)
                    return bitmap
                }
                

                它返回我正在调用saveScreenShot 的位图,这是另一个扩展函数

                fun Bitmap.saveScreenShot(
                    requireContext: Context,
                    filename: String,
                    ScreenShootFolderPath: String,
                    permissionListener: () -> Boolean,
                ): Uri? {
                    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
                        saveImageInQ(this, filename, ScreenShootFolderPath, requireContext.contentResolver)
                    else
                        legacySave(this, filename, ScreenShootFolderPath, permissionListener)
                }
                
                private fun saveImageInQ(
                    bitmap: Bitmap,
                    filename: String,
                    parentFileName: String,
                    contentResolver: ContentResolver
                ): Uri? {
                    val fos: OutputStream?
                    val uri: Uri?
                    val contentValues = ContentValues()
                    contentValues.apply {
                        put(MediaStore.MediaColumns.DISPLAY_NAME, filename)
                        put(MediaStore.Files.FileColumns.MIME_TYPE, "image/png")
                        put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_PICTURES + parentFileName)
                        put(MediaStore.MediaColumns.IS_PENDING, 1)
                    }
                
                    uri =
                        contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
                    uri?.let { contentResolver.openOutputStream(it) }.also { fos = it }
                
                    fos?.use { bitmap.compress(Bitmap.CompressFormat.PNG, 100, it) }
                    fos?.flush()
                    fos?.close()
                
                    contentValues.clear()
                    contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0)
                    uri?.let {
                        contentResolver.update(it, contentValues, null, null)
                    }
                    return uri
                }
                
                private fun legacySave(
                    bitmap: Bitmap,
                    filename: String,
                    parentFileName: String,
                    permissionListener: () -> Boolean,
                ): Uri? {
                    val fos: OutputStream?
                    if (!permissionListener()) {
                        return null
                    }
                
                    val path =
                        Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString() +
                                parentFileName + File.separator + filename
                    val imageFile = File(path)
                    if (imageFile.parentFile?.exists() == false) {
                        imageFile.parentFile?.mkdir()
                    }
                    imageFile.createNewFile()
                    fos = FileOutputStream(imageFile)
                    val uri: Uri = Uri.fromFile(imageFile)
                
                    fos.use { bitmap.compress(Bitmap.CompressFormat.PNG, 100, it) }
                    fos.flush()
                    fos.close()
                
                    return uri
                }
                

                【讨论】:

                • 如果图像有相同的名称,它会像 image.png , imge(1).png 一样保存,然后继续如何检查图像是否已经存在
                【解决方案12】:

                这就是我捕获屏幕并共享它的方式。有兴趣的可以看看。

                public Bitmap takeScreenshot() {
                  View rootView = findViewById(android.R.id.content).getRootView();
                  rootView.setDrawingCacheEnabled(true);
                  return rootView.getDrawingCache();
                 }
                

                以及将位图图像保存到外部存储的方法:

                public void saveBitmap(Bitmap bitmap) {
                File imagePath = new File(Environment.getExternalStorageDirectory() + "/screenshot.png");
                FileOutputStream fos;
                try {
                    fos = new FileOutputStream(imagePath);
                    bitmap.compress(CompressFormat.JPEG, 100, fos);
                    fos.flush();
                    fos.close();
                } catch (FileNotFoundException e) {
                    Log.e("GREC", e.getMessage(), e);
                } catch (IOException e) {
                    Log.e("GREC", e.getMessage(), e);
                 }}
                

                查看更多:https://www.youtube.com/watch?v=LRCRNvzamwY&feature=youtu.be

                【讨论】:

                  【解决方案13】:

                  如果有人得到 java.io.FileNotFoundException,遵循 SilengKnight 的解决方案,问题可能是不允许写入存储(尽管我们在清单中添加了用户权限)。我通过在创建新的 FileOutputStream 之前在 store 函数中添加它来解决它。

                  if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                              != PackageManager.PERMISSION_GRANTED) {
                          //Permission was denied
                          //Request for permission
                          ActivityCompat.requestPermissions(MainActivity.this,
                                  new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                                  MY_PERMISSIONS_CODE_EXTERNAL_STORAGE);
                      }
                  

                  【讨论】:

                    【解决方案14】:

                    创建帮助类来创建和共享屏幕截图

                    public class share {
                    private final Context c;
                    public share(Context c) {
                        this.c = c;
                    }
                    public void shareInt(Bitmap bitmap, String msg, String name) {
                        Uri uri = getmageToShare(bitmap, name);
                        Intent intent = new Intent(Intent.ACTION_SEND);
                        intent.putExtra(Intent.EXTRA_STREAM, uri);
                        intent.putExtra(Intent.EXTRA_TEXT, msg);
                        intent.setType("*/*");
                        c.startActivity(Intent.createChooser(intent, "Share Via").addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
                    }
                    
                    // Retrieving the url to share
                    private Uri getmageToShare(Bitmap bitmap, String name) {
                        File imagefolder = new File(c.getCacheDir(), "images");
                        Uri uri = null;
                        try {
                            imagefolder.mkdirs();
                            File file = new File(imagefolder, name+".png");
                            FileOutputStream outputStream = new FileOutputStream(file);
                            bitmap.compress(Bitmap.CompressFormat.PNG, 70, outputStream);
                            outputStream.flush();
                            outputStream.close();
                            uri = FileProvider.getUriForFile(c, "com.yourapp.fileprovider", file);
                        } catch (Exception e) {
                            Toast.makeText(c, "" + e.getMessage(), Toast.LENGTH_LONG).show();
                        }
                        return uri;
                       }
                    }
                    

                    现在从您想要截屏和分享的任何活动中调用此帮助程序类

                    CardView mainView = findViewById(R.id.mainView);
                    new share(c).shareInt(new getBitmap().screenShot(mainView), "msg", "randomstring");
                    

                    这里的mainView就是你要抓拍的那个view,jzt pass view reference。

                    不需要运行时权限,因为我们使用的是缓存目录

                    【讨论】:

                    • "new getBitmap().screenShot(binding.calMainView)" 也许你忘了提供这个类的实现
                    • new share(c).shareInt(new getBitmap().screenShot(mainView), "msg", "randomstring");这里实现类@PRANAVSINGH
                    【解决方案15】:

                    这是我用来截屏的。上述解决方案适用于 API

                    我在 MainActivity.java 中放置了以下方法:

                    public class MainActivity {
                    
                    ...
                    
                    String[] permissions = new String[]{"android.permission.READ_EXTERNAL_STORAGE", "android.permission.WRITE_EXTERNAL_STORAGE"};
                    View sshotView;
                    
                    ...
                    
                    private boolean checkPermission() {
                    List arrayList = new ArrayList();
                    for (String str : this.permissions) {
                    if (ContextCompat.checkSelfPermission(this, str) != 0) {
                    arrayList.add(str);
                    }
                    }
                    if (arrayList.isEmpty()) {
                    return true;
                    }
                    ActivityCompat.requestPermissions(this, (String[]) arrayList.toArray(new String[arrayList.size()]), 100);
                    return false;
                    }
                    
                    protected void onCreate(Bundle savedInstanceState) {
                    ...
                    
                    this.sshotView = getWindow().getDecorView().findViewById(R.id.parent);
                    ...
                    
                    }
                    
                    @Override
                    public boolean onOptionsItemSelected(MenuItem item) {
                    
                    int id = item.getItemId();
                    switch (id) {
                    
                    
                    case R.id.action_shareScreenshot:
                    boolean checkPermission = checkPermission();
                    Bitmap screenShot = getScreenShot(this.sshotView);
                    if (!checkPermission) {
                    return true;
                    }
                    shareScreenshot(store(screenShot));
                    return true;
                    
                    case R.id.option2:      
                    ...    
                    return true;
                    }
                    
                    return false;
                    }
                    
                    private void shareScreenshot(File file) {
                    Parcelable fromFile = FileProvider.getUriForFile(MainActivity.this,
                    BuildConfig.APPLICATION_ID + ".com.redtiger.applehands.provider", file);
                    Intent intent = new Intent();
                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                    intent.setAction("android.intent.action.SEND");
                    intent.setType("image/*");
                    intent.putExtra("android.intent.extra.SUBJECT", XmlPullParser.NO_NAMESPACE);
                    intent.putExtra("android.intent.extra.TEXT", XmlPullParser.NO_NAMESPACE);
                    intent.putExtra("android.intent.extra.STREAM", fromFile);
                    try {
                    startActivity(Intent.createChooser(intent, "Share Screenshot"));
                    } catch (ActivityNotFoundException e) {
                    Toast.makeText(getApplicationContext(), "No Communication Platform Available", Toast.LENGTH_SHORT).show();
                    }
                    }
                    
                    public static Bitmap getScreenShot(View view) {
                    View rootView = view.getRootView();
                    rootView.setDrawingCacheEnabled(true);
                    Bitmap createBitmap = Bitmap.createBitmap(rootView.getDrawingCache());
                    rootView.setDrawingCacheEnabled(false);
                    return createBitmap;
                    
                    public File store(Bitmap bitmap) {
                    String str = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Pictures/Screenshots";
                    File file = new File(str);
                    if (!file.exists()) {
                    file.mkdirs();
                    }
                    file = new File(str + "/sshot.png");
                    try {
                    OutputStream fileOutputStream = new FileOutputStream(file);
                    bitmap.compress(Bitmap.CompressFormat.PNG, 80, fileOutputStream);
                    fileOutputStream.flush();
                    fileOutputStream.close();
                    } catch (Exception e) {
                    e.printStackTrace();
                    Toast.makeText(getApplicationContext(), "External Storage Permission Is Required", Toast.LENGTH_LONG).show();
                    }
                    return file;
                    }
                    }
                    

                    我在我的 AndroidManifest.xml 中放置了以下权限和提供程序:

                    <?xml version="1.0" encoding="utf-8"?>
                    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
                    package="com.redtiger.applehands">
                    
                    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
                    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
                    <uses-permission android:name="android.permission.INTERNET" />
                    
                    <application
                    
                    ...
                    
                    <provider
                    android:name="com.redtiger.applehands.util.GenericFileProvider"
                    android:authorities="${applicationId}.com.redtiger.applehands.provider"
                    android:exported="false"
                    android:grantUriPermissions="true">
                    <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/provider_paths"/>
                    </provider>
                    
                    ...
                    
                    </application>
                    
                    </manifest>
                    

                    我创建了一个名为 provider_paths.xml 的文件(请参见下文)来指示 FileProvider 将屏幕截图保存在何处。该文件包含一个指向外部目录根的简单标记。

                    该文件被放置在资源文件夹 res/xml 中(如果您在此处没有 xml 文件夹,只需创建一个并将您的文件放在那里)。

                    provider_paths.xml:

                    <?xml version="1.0" encoding="utf-8"?>
                    <paths>
                    <external-path name="external_files" path="."/>
                    </paths>
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2018-12-09
                      相关资源
                      最近更新 更多