Я пришел из следующего вопроса (я спросил): Сохранение текущего представления в виде растрового изображения
Я дам максимально возможную информацию, чтобы задать вопрос.
Моя конечная цель - написать представление с некоторой информацией о нем (будет позже из API, вероятно, объекта JSOn с большим количеством текста). До сих пор я делал: 1) Создание пользовательского представления. 2) Рисование в этом пользовательском представлении холста с необходимой мне информацией (canvas.drawText ()). 3) Размещение этого пользовательского представления в activity_main.xml (ссылка на него). 4) Создание этого CustomView на MainActivity.kt (теперь проблема начинается). 5) Преобразование этого CustomView в растровое изображение (с использованием метода расширения. 6) Сохранение преобразованного CustomView на SD-карту
Однако, когда я пытаюсьчтобы спасти ничего не происходит. Папка не создается, ничего в окне LogCat также нет (я проверяю, создаются ли файлы \ папки с помощью Device File Explorer в Android Studio).
После прочтения я понял, что для просмотра нужно иметь ViewTreeObserverдля изменений (например: тогда представление заканчивает рисование). Я добавил это в свой код как метод Extension (найден в SO, но не могу найти ссылку сейчас), но также ничего не изменил.
Чтобы сохранить растровое изображение во внутреннем хранилище, я получил метод отследующая ссылка: https://android - code.blogspot.com/2018/04/android-kotlin-save-image-to-internal.html (я только что адаптировал метод, так как мне нужно было использоватьРастровое изображение не рисуется).
Я что-то упустил? Насколько я вижу, я делаю правильные вещи, чтобы сохранить растровое изображение на SD. (Вопрос большой из-за кода, который я опубликовал) Информация: Использование Android Studio 3.5.1 Kotlin Language
Моя активность_основной.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.example.desenhanota.CustomView
android:id="@+id/MyCustomview"
android:layout_width="match_parent"
android:layout_height="442dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</RelativeLayout>
Метод расширения ViewTreeObserver:
inline fun View.doOnGlobalLayout(crossinline action: (view: View) -> Unit) {
val vto = viewTreeObserver
vto.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
@SuppressLint("ObsoleteSdkInt")
@Suppress("DEPRECATION")
override fun onGlobalLayout() {
action(this@doOnGlobalLayout)
when {
vto.isAlive -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
vto.removeOnGlobalLayoutListener(this)
} else {
vto.removeGlobalOnLayoutListener(this)
}
}
else -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
viewTreeObserver.removeOnGlobalLayoutListener(this)
} else {
viewTreeObserver.removeGlobalOnLayoutListener(this)
}
}
}
}
})
}
Файл CustomView (CustomView.kt)
class CustomView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
): View(context, attrs, defStyleAttr) {
private val textoGeral = Paint()
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
textoGeral.setColor(Color.BLACK)
canvas?.drawText("DRAW TEST ON CANVAS TEST TEST ", 0f, 120f, textoGeral)
}
}
MainActivity
class MainActivity : AppCompatActivity() {
private val TAG = "MainActivity"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val outraView = CustomView(this)
outraView.doOnGlobalLayout {
try {
val bmp = outraView.fromBitmap()
val uri: Uri = saveImageToInternalStorage(bmp)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
private fun saveImageToInternalStorage(bitmap :Bitmap):Uri{
// Get the context wrapper instance
val wrapper = ContextWrapper(applicationContext)
// The bellow line return a directory in internal storage
var file = wrapper.getDir("images", Context.MODE_PRIVATE)
file = File(file, "${UUID.randomUUID()}.jpg")
try {
val stream: OutputStream = FileOutputStream(file)
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream)
stream.flush()
stream.close()
} catch (e: IOException){ // Catch the exception
e.printStackTrace()
}
// Return the saved image uri
return Uri.parse(file.absolutePath)
}
}
РЕДАКТИРОВАТЬ 1: я изменил то, что предложил пользователь mhedman в комментариях. Он упомянул, что я обрабатываю новый экземпляр моего пользовательского представления, а не тот, который уже извлечен из макета активности. Когда я пытался за пределами события ViewTreeObsever, у меня было исключение, говорящее «ширина и высота должны быть> 0». Внутри ViewTreeObserver ничего не происходит (сообщение не отображается).
Обновлен код с предложением:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val outraView = MyCustomView
outraView.doOnGlobalLayout {
val finalBmp = outraView.fromBitmap()
val uri: Uri = saveImageToInternalStorage(finalBmp)
}