یکی از کاربردی ترین عملکردها , اسکرین شات گرفتن از صفحه موبایل هست که کد نویسی چندان پیچیده ای هم نداره ! امروز ما گرفتن اسکرین شات با کاتلین در اندروید به همراه سورس کد گرفتن screenshot با زبان کاتلین در اندروید را به شما در قالب مثال آموزش خواهیم داد. در این مثال دو نوع اسکرین شات رو آوردیم که خیلی کاربردی تر میشه داستان ! چرا که آزادی عمل بیشتری بدست میاریم.
یک نوع اسکرین شات از لایه (تنها محتویات در لایه ای که شما تصمیم میگیرد چه لایه ای باشه !! فقط کافیه که از نوادگان کلاس View باشه :)) )
و نوع دیگه اسکرین شات از تمام صفحه (که قبلا هم زیاد دیدیم!)
خب بریم سراغ پروژه
محتویات فایل string.xml بصورت زیر هست
<resources> <string name="app_name">Screenshot App</string> <string name="take_screen_shot_activity">شات از صفحه</string> <string name="take_screen_shot_view">شات از لایه</string> <string name="take_save_screen_shot">ذخیره</string> <string name="reset">پاک کردن</string> <string name="toast_message_screenshot">ابتدا یک اسکرین شات بگیرید</string> <string name="toast_message_screenshot_success">اسکرین شات با موفقیت ثبت شد</string> <string name="settings_message">لطفا مجوز دسترسی را در تنظیمات بدهید</string> </resources>
محتویات فایل colors.xml نیز بصورت زیر هست
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorPrimary">#882D60</color> <color name="colorPrimary2">#ac3879</color> <color name="colorPrimaryDark">#440026</color> <color name="colorAccent">#CD88AF</color> <color name="white">#ffffff</color> <color name="gray">#c7c7c7</color> </resources>
خب از حواشی بگذریم الان باید بریم سراغ لایه اصلی اپ یعنی activity_main.xml که بصورت زیر با کانسترینت لیوت (که یه تنه میتونه جای چندین لینر لیوت یا ریلتیو لیوت صفحه رو مدیریت کنه و پیشنهاد میدم حتما بهش مسلط شید) طراحی شده
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/parentView" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="16dp" tools:context=".MainActivity"> <Button android:id="@+id/buttonScreenshotActivity" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="@string/take_screen_shot_activity" android:textAllCaps="false" android:textColor="@color/white" android:background="@color/colorPrimary" app:layout_constraintStart_toStartOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintEnd_toStartOf="@+id/buttonScreenshotView" app:layout_constraintHorizontal_chainStyle="packed" android:layout_marginTop="16dp" app:layout_constraintTop_toTopOf="parent" android:layout_marginEnd="5dp" android:layout_marginRight="5dp"/> <Button android:id="@+id/buttonScreenshotView" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="@string/take_screen_shot_view" android:textAllCaps="false" android:textColor="@color/white" android:background="@color/colorPrimary2" app:layout_constraintStart_toEndOf="@+id/buttonScreenshotActivity" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintEnd_toEndOf="parent" android:layout_marginTop="16dp" app:layout_constraintTop_toTopOf="parent" /> <Button android:id="@+id/buttonSaveScreenshot" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="@string/take_save_screen_shot" android:textAllCaps="false" android:textColor="@color/white" android:background="@color/colorAccent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintEnd_toStartOf="@+id/buttonReset" app:layout_constraintHorizontal_chainStyle="packed" android:layout_marginEnd="5dp" android:layout_marginRight="5dp" android:layout_marginTop="16dp" app:layout_constraintTop_toBottomOf="@+id/buttonScreenshotActivity"/> <Button android:id="@+id/buttonReset" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:text="@string/reset" android:textAllCaps="false" android:textColor="@color/white" android:background="@color/gray" app:layout_constraintStart_toEndOf="@+id/buttonSaveScreenshot" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintEnd_toEndOf="parent" android:layout_marginTop="16dp" app:layout_constraintTop_toBottomOf="@+id/buttonScreenshotView"/> <ImageView android:id="@+id/imageViewShowScreenshot" android:layout_width="0dp" android:layout_height="0dp" app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="8dp" android:layout_marginRight="8dp" app:layout_constraintStart_toStartOf="parent" android:layout_marginLeft="8dp" android:layout_marginStart="8dp" app:layout_constraintTop_toBottomOf="@+id/buttonReset" android:layout_marginBottom="16dp" app:layout_constraintBottom_toBottomOf="parent" android:layout_marginTop="16dp"/> </android.support.constraint.ConstraintLayout>
و حالا یکی از کلاس های اصلی مورد استفاده در این پروژه و (پروژه های دیگر) با عنوان FileUtil.kt که وظیفه مدیریت عکس ایجاد شده رو به عهده داره که در این پروژه فقط کافیه که اون رو ذخیره کنه روی حافظه
package dn.marjan.screenshotapp import android.graphics.Bitmap import java.io.File import java.io.FileNotFoundException import java.io.FileOutputStream import java.io.IOException class FileUtil { /** * Stores the given [Bitmap] to a path on the device. * * @param bitmap The [Bitmap] that needs to be stored * @param filePath The path in which the bitmap is going to be stored. */ fun storeBitmap(bitmap: Bitmap, filePath: String) { val imageFile = File(filePath) imageFile.parentFile.mkdirs() try { val fout = FileOutputStream(imageFile) bitmap.compress(Bitmap.CompressFormat.JPEG, 90, fout) fout.flush() fout.close() } catch (e: FileNotFoundException) { e.printStackTrace() } catch (e: IOException) { e.printStackTrace() } } companion object { private var mInstance: FileUtil? = null fun getInstance():FileUtil{ if (mInstance == null) { synchronized(FileUtil::class.java) { if (mInstance == null) { mInstance = FileUtil() } } } return mInstance!! } } }
کلاس بعدی که باید ایجاد کنیم اصلی ترین کلاس این پروژه ست. مشخصا کلاسی که وظیفه گرفتن اسکرین شات از مختصاتی که مادستور میدیم رو داره و بصورت زیر کدنویسی شده
package dn.marjan.screenshotapp import android.app.Activity import android.graphics.Bitmap import android.view.View.MeasureSpec import android.view.View class ScreenshotUtil { /** * Measures and takes a screenshot of the provided [View]. * * @param view The view of which the screenshot is taken * @return A [Bitmap] for the taken screenshot. */ fun takeScreenshotForView(view: View): Bitmap { view.measure( MeasureSpec.makeMeasureSpec(view.width, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(view.height, MeasureSpec.EXACTLY) ) view.layout( view.x.toInt(), view.y.toInt(), view.x.toInt() + view.measuredWidth, view.y.toInt() + view.measuredHeight ) view.isDrawingCacheEnabled = true view.buildDrawingCache(true) val bitmap = Bitmap.createBitmap(view.drawingCache) view.isDrawingCacheEnabled = false return bitmap } fun takeScreenshotForScreen(activity: Activity): Bitmap { return takeScreenshotForView(activity.window.decorView.rootView) } companion object { private var mInstance: ScreenshotUtil? = null public fun getInstance(): ScreenshotUtil? { if (mInstance == null) { synchronized(ScreenshotUtil::class.java) { if (mInstance == null) { mInstance = dn.marjan.screenshotapp.ScreenshotUtil() } } } return mInstance } } }
و در انتها هم کلاس اکتیویتی اصلی
package dn.marjan.screenshotapp import android.support.v7.app.AppCompatActivity import android.os.Bundle import com.karumi.dexter.PermissionToken import android.widget.Toast import android.Manifest; import android.graphics.Bitmap; import android.os.Environment; import android.view.View; import com.karumi.dexter.Dexter; import com.karumi.dexter.listener.PermissionDeniedResponse; import com.karumi.dexter.listener.PermissionGrantedResponse; import com.karumi.dexter.listener.PermissionRequest; import com.karumi.dexter.listener.single.PermissionListener import kotlinx.android.synthetic.main.activity_main.* class MainActivity : AppCompatActivity(), View.OnClickListener { private val activity = this@MainActivity private var bitmap: Bitmap? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // initializing the listeners initListeners() } /** * method to initialize the listeners */ private fun initListeners() { buttonScreenshotActivity.setOnClickListener(this) buttonScreenshotView.setOnClickListener(this) buttonSaveScreenshot.setOnClickListener(this) buttonReset.setOnClickListener(this) } /** * method for click listener * * @param view */ override fun onClick(view: View) { when (view.id) { // Take ScreenshotUtil for activity R.id.buttonScreenshotActivity -> { bitmap = ScreenshotUtil.getInstance()!! .takeScreenshotForScreen(activity) imageViewShowScreenshot!!.setImageBitmap(bitmap) } // Take ScreenshotUtil for any view R.id.buttonScreenshotView -> { bitmap = ScreenshotUtil.getInstance()!! .takeScreenshotForView(buttonScreenshotView) imageViewShowScreenshot!!.setImageBitmap(bitmap) } R.id.buttonSaveScreenshot -> requestPermissionAndSave() R.id.buttonReset -> { bitmap = null imageViewShowScreenshot!!.setImageBitmap(bitmap) } } } /** * Requesting storage permission * Once the permission granted, screen shot captured * On permanent denial show toast */ private fun requestPermissionAndSave() { Dexter.withActivity(this) .withPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) .withListener(object : PermissionListener { override fun onPermissionGranted(response: PermissionGrantedResponse) { if (bitmap != null) { val path = Environment.getExternalStorageDirectory().toString() + "/test.png" FileUtil.getInstance().storeBitmap(bitmap!!, path) Toast.makeText( activity, getString(R.string.toast_message_screenshot_success) + " " + path, Toast.LENGTH_LONG ).show() } else { Toast.makeText(activity, getString(R.string.toast_message_screenshot) , Toast.LENGTH_LONG).show() } } override fun onPermissionDenied(response: PermissionDeniedResponse) { // check for permanent denial of permission if (response.isPermanentlyDenied) { Toast.makeText(activity, getString(R.string.settings_message) , Toast.LENGTH_LONG).show() } } override fun onPermissionRationaleShouldBeShown(permission: PermissionRequest , token: PermissionToken) { token.continuePermissionRequest() } }).check() } }
درضمن ما از کتابخانه خاصی برای گرفتن دسترسی ران تایم استفاده کردیم که البته میتونید از این کتابخانه هم استفاده نکنید و از درخواست مجوز دیفالت خود اندروید استفاده کنید
implementation 'com.karumi:dexter:5.0.0'
در انتها کافیه پروژه رو ران کنید و خروجی بگیرید !