


آموزش گرفتن اسکرین شات با کاتلین در اندروید
یکی از کاربردی ترین عملکردها , اسکرین شات گرفتن از صفحه موبایل هست که کد نویسی چندان پیچیده ای هم نداره ! امروز ما گرفتن اسکرین شات با کاتلین در اندروید به همراه سورس کد گرفتن 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'
در انتها کافیه پروژه رو ران کنید و خروجی بگیرید !