kotlin绘图程序图纸消失

问题描述 投票:0回答:1

我正在用 Kotlin 语言制作一个绘画应用程序。绘图、着色、撤消、清除、保存等一切正常。但是当我在画画时改变形式时,我画的画就消失了。我想画一点,切换到另一种形式再回来,但我的画不应该被删除。

package com.coding.curvedbottomnavigationapp

import android.content.Context
import android.graphics.*
import android.os.Environment
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.widget.Toast // Toast kütüphanesi eklendi
import java.io.File
import java.io.FileOutputStream
import java.io.IOException

class PaintView(context: Context, attrs: AttributeSet) : View(context, attrs) {

    private var currentPaint = Paint().apply {
        isAntiAlias = true
        style = Paint.Style.STROKE
        strokeJoin = Paint.Join.ROUND
        strokeCap = Paint.Cap.ROUND
        strokeWidth = 10f
        color = Color.BLACK // Varsayılan renk siyah
    }

    private var strokeWidth = 10f
    private var paintColor = Color.BLACK

    // Her bir çizim yolunu ve ona karşılık gelen Paint nesnesini saklayacağımız yapı
    private val paths = mutableListOf<Pair<Path, Paint>>()
    private var currentPath: Path? = null

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        // Tüm yolları ve onların kendi boyama stillerini çiz
        for ((path, paint) in paths) {
            canvas.drawPath(path, paint)
        }

        // Halen çizilmekte olan yolu çiz
        currentPath?.let { canvas.drawPath(it, currentPaint) }
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        val point = PointF(event.x, event.y)
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                // Yeni bir yol oluştur ve onu mevcut boyama ayarlarıyla başlat
                currentPath = Path().apply {
                    moveTo(point.x, point.y)
                }
                return true
            }
            MotionEvent.ACTION_MOVE -> {
                // Yolu güncelle
                currentPath?.lineTo(point.x, point.y)
            }
            MotionEvent.ACTION_UP -> {
                // Çizim bitince yolu ve boyama ayarlarını sakla
                currentPath?.let {
                    paths.add(Pair(it, Paint(currentPaint))) // Paint nesnesini kopyalayarak sakla
                    currentPath = null
                }
            }
        }
        invalidate() // Ekranı güncelle
        return true
    }

    // Renk değiştirme fonksiyonu
    fun setPaintColor(color: Int) {
        paintColor = color
        currentPaint.color = color // Mevcut boyama stiline yeni rengi uygula
        invalidate()
    }

    // Kalem genişliği değiştirme fonksiyonu
    fun setStrokeWidth(width: Float) {
        strokeWidth = width
        currentPaint.strokeWidth = width // Mevcut boyama stiline yeni kalem genişliğini uygula
        invalidate()
    }

    // Geri alma fonksiyonu
    fun undo() {
        if (paths.isNotEmpty()) {
            paths.removeAt(paths.size - 1)
            invalidate()
        }
    }

    // Tüm çizimleri temizleme fonksiyonu
    fun clear() {
        paths.clear()
        invalidate()
    }

    // Çizimi kaydetme fonksiyonu
    fun saveDrawing() {
        // Çizimi bitmap olarak oluştur
        val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bitmap)
        draw(canvas) // Çizimi bitmape çiz

        // Kaydetme işlemi
        val file = File(context.getExternalFilesDir(null), "drawing_${System.currentTimeMillis()}.png")
        try {
            FileOutputStream(file).use { output ->
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, output)
                Toast.makeText(context, "Çizim kaydedildi: ${file.absolutePath}", Toast.LENGTH_LONG).show()
            }
        } catch (e: IOException) {
            e.printStackTrace()
            Toast.makeText(context, "Kaydetme işlemi başarısız.", Toast.LENGTH_SHORT).show()
        }
    }
}
package com.coding.curvedbottomnavigationapp.fragments

import android.Manifest
import android.content.pm.PackageManager
import android.graphics.Color
import android.os.Bundle
import android.speech.tts.TextToSpeech
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.SeekBar
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import com.coding.curvedbottomnavigationapp.MainActivity
import com.coding.curvedbottomnavigationapp.R
import com.coding.curvedbottomnavigationapp.PaintView
import java.util.*


class HomeFragment : Fragment(), TextToSpeech.OnInitListener {

    private lateinit var paintView: PaintView
    private lateinit var buttonUndo: Button
    private lateinit var buttonClear: Button
    private lateinit var buttonSave: Button
    private lateinit var seekBarStrokeWidth: SeekBar
    private lateinit var tts: TextToSpeech // TTS tanımlandı

    companion object {
        private const val STORAGE_PERMISSION_CODE = 1001
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_home, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        paintView = view.findViewById(R.id.paintView)
        buttonUndo = view.findViewById(R.id.buttonUndo)
        buttonClear = view.findViewById(R.id.buttonClear)
        buttonSave = view.findViewById(R.id.buttonSave)
        seekBarStrokeWidth = view.findViewById(R.id.seekBarStrokeWidth)

        // Text-to-Speech başlatma
        tts = TextToSpeech(context, this)

        // İzinleri kontrol et
        requestStoragePermissions()

        // Geri alma işlemi
        buttonUndo.setOnClickListener {
            paintView.undo()
            playColorExplanation("Çizim geri alındı")
        }

        // Temizleme işlemi
        buttonClear.setOnClickListener {
            paintView.clear()
            playColorExplanation("Ekran temizlendi")
        }

        // Kalem kalınlığını ayarlama
        seekBarStrokeWidth.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                paintView.setStrokeWidth(progress.toFloat())
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) {}
            override fun onStopTrackingTouch(seekBar: SeekBar?) {}
        })

        // Kaydetme işlemi
        buttonSave.setOnClickListener {
            paintView.saveDrawing() // Çizimi kaydet
            playColorExplanation("Muhteşem bir resim kaydettin")
        }

        // Renk seçimi butonları için tıklama olaylarını ekleme
        view.findViewById<Button>(R.id.buttonRed).setOnClickListener {
            paintView.setPaintColor(Color.RED)
            playColorExplanation("Kırmızı renk seçildi") // Sesli uyarı
        }

        view.findViewById<Button>(R.id.buttonGreen).setOnClickListener {
            paintView.setPaintColor(Color.GREEN)
            playColorExplanation("Yeşil renk seçildi") // Sesli uyarı
        }

        view.findViewById<Button>(R.id.buttonBlue).setOnClickListener {
            paintView.setPaintColor(Color.BLUE)
            playColorExplanation("Mavi renk seçildi") // Sesli uyarı
        }

        view.findViewById<Button>(R.id.buttonYellow).setOnClickListener {
            paintView.setPaintColor(Color.YELLOW)
            playColorExplanation("Sarı renk seçildi") // Sesli uyarı
        }

        view.findViewById<Button>(R.id.buttonBlack).setOnClickListener {
            paintView.setPaintColor(Color.BLACK)
            playColorExplanation("Siyah renk seçildi") // Sesli uyarı
        }
    }

    // TTS başlatıldığında bu fonksiyon çalışır
    override fun onInit(status: Int) {
        if (status == TextToSpeech.SUCCESS) {
            // Dil olarak Türkçe seçiyoruz
            val result = tts.setLanguage(Locale("tr", "TR"))
            if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
                speakOut("Bu dil desteklenmiyor")
            }
        } else {
            speakOut("Text to Speech başlatılamadı")
        }
    }

    // Sesli mesaj oynatma fonksiyonu
    private fun speakOut(message: String) {
        tts.speak(message, TextToSpeech.QUEUE_FLUSH, null, "")
    }

    // Text-to-Speech ile renk seçimi açıklaması yaparken müziği durdurma ve yeniden başlatma
    private fun playColorExplanation(message: String) {
        (activity as? MainActivity)?.let { mainActivity ->
            val wasPlaying = mainActivity.isMusicPlaying() // mediaPlayer yerine getter kullanılıyor
            mainActivity.pauseMusic()
            speakOut(message)

            tts.setOnUtteranceCompletedListener {
                // Eğer müzik başlangıçta çalıyorduysa tekrar başlat
                if (wasPlaying) {
                    mainActivity.playMusic()
                }
            }
        }
    }

    override fun onDestroy() {
        // TTS kaynağını serbest bırak
        if (tts != null) {
            tts.stop()
            tts.shutdown()
        }
        super.onDestroy()
    }

    private fun requestStoragePermissions() {
        if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(requireActivity(), arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), STORAGE_PERMISSION_CODE)
        }
    }
}

大家好,我正在用Kotlin语言制作一个绘画绘图应用程序。绘图、着色、撤消、清除、保存等一切正常。但是当我在画画时改变形式时,我画的画就消失了。我想画一点,切换到另一种形式再回来,但我的画不应该被删除。

package com.coding.curvedbottomnavigationapp

import android.content.Context
import android.graphics.*
import android.os.Environment
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.widget.Toast // Toast kütüphanesi eklendi
import java.io.File
import java.io.FileOutputStream
import java.io.IOException

class PaintView(context: Context, attrs: AttributeSet) : View(context, attrs) {

    private var currentPaint = Paint().apply {
        isAntiAlias = true
        style = Paint.Style.STROKE
        strokeJoin = Paint.Join.ROUND
        strokeCap = Paint.Cap.ROUND
        strokeWidth = 10f
        color = Color.BLACK // Varsayılan renk siyah
    }

    private var strokeWidth = 10f
    private var paintColor = Color.BLACK

    // Her bir çizim yolunu ve ona karşılık gelen Paint nesnesini saklayacağımız yapı
    private val paths = mutableListOf<Pair<Path, Paint>>()
    private var currentPath: Path? = null

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)

        // Tüm yolları ve onların kendi boyama stillerini çiz
        for ((path, paint) in paths) {
            canvas.drawPath(path, paint)
        }

        // Halen çizilmekte olan yolu çiz
        currentPath?.let { canvas.drawPath(it, currentPaint) }
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        val point = PointF(event.x, event.y)
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                // Yeni bir yol oluştur ve onu mevcut boyama ayarlarıyla başlat
                currentPath = Path().apply {
                    moveTo(point.x, point.y)
                }
                return true
            }
            MotionEvent.ACTION_MOVE -> {
                // Yolu güncelle
                currentPath?.lineTo(point.x, point.y)
            }
            MotionEvent.ACTION_UP -> {
                // Çizim bitince yolu ve boyama ayarlarını sakla
                currentPath?.let {
                    paths.add(Pair(it, Paint(currentPaint))) // Paint nesnesini kopyalayarak sakla
                    currentPath = null
                }
            }
        }
        invalidate() // Ekranı güncelle
        return true
    }

    // Renk değiştirme fonksiyonu
    fun setPaintColor(color: Int) {
        paintColor = color
        currentPaint.color = color // Mevcut boyama stiline yeni rengi uygula
        invalidate()
    }

    // Kalem genişliği değiştirme fonksiyonu
    fun setStrokeWidth(width: Float) {
        strokeWidth = width
        currentPaint.strokeWidth = width // Mevcut boyama stiline yeni kalem genişliğini uygula
        invalidate()
    }

    // Geri alma fonksiyonu
    fun undo() {
        if (paths.isNotEmpty()) {
            paths.removeAt(paths.size - 1)
            invalidate()
        }
    }

    // Tüm çizimleri temizleme fonksiyonu
    fun clear() {
        paths.clear()
        invalidate()
    }

    // Çizimi kaydetme fonksiyonu
    fun saveDrawing() {
        // Çizimi bitmap olarak oluştur
        val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bitmap)
        draw(canvas) // Çizimi bitmape çiz

        // Kaydetme işlemi
        val file = File(context.getExternalFilesDir(null), "drawing_${System.currentTimeMillis()}.png")
        try {
            FileOutputStream(file).use { output ->
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, output)
                Toast.makeText(context, "Çizim kaydedildi: ${file.absolutePath}", Toast.LENGTH_LONG).show()
            }
        } catch (e: IOException) {
            e.printStackTrace()
            Toast.makeText(context, "Kaydetme işlemi başarısız.", Toast.LENGTH_SHORT).show()
        }
    }
}
package com.coding.curvedbottomnavigationapp.fragments

import android.Manifest
import android.content.pm.PackageManager
import android.graphics.Color
import android.os.Bundle
import android.speech.tts.TextToSpeech
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.SeekBar
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import com.coding.curvedbottomnavigationapp.MainActivity
import com.coding.curvedbottomnavigationapp.R
import com.coding.curvedbottomnavigationapp.PaintView
import java.util.*


class HomeFragment : Fragment(), TextToSpeech.OnInitListener {

    private lateinit var paintView: PaintView
    private lateinit var buttonUndo: Button
    private lateinit var buttonClear: Button
    private lateinit var buttonSave: Button
    private lateinit var seekBarStrokeWidth: SeekBar
    private lateinit var tts: TextToSpeech // TTS tanımlandı

    companion object {
        private const val STORAGE_PERMISSION_CODE = 1001
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_home, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        paintView = view.findViewById(R.id.paintView)
        buttonUndo = view.findViewById(R.id.buttonUndo)
        buttonClear = view.findViewById(R.id.buttonClear)
        buttonSave = view.findViewById(R.id.buttonSave)
        seekBarStrokeWidth = view.findViewById(R.id.seekBarStrokeWidth)

        // Text-to-Speech başlatma
        tts = TextToSpeech(context, this)

        // İzinleri kontrol et
        requestStoragePermissions()

        // Geri alma işlemi
        buttonUndo.setOnClickListener {
            paintView.undo()
            playColorExplanation("Çizim geri alındı")
        }

        // Temizleme işlemi
        buttonClear.setOnClickListener {
            paintView.clear()
            playColorExplanation("Ekran temizlendi")
        }

        // Kalem kalınlığını ayarlama
        seekBarStrokeWidth.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
            override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
                paintView.setStrokeWidth(progress.toFloat())
            }

            override fun onStartTrackingTouch(seekBar: SeekBar?) {}
            override fun onStopTrackingTouch(seekBar: SeekBar?) {}
        })

        // Kaydetme işlemi
        buttonSave.setOnClickListener {
            paintView.saveDrawing() // Çizimi kaydet
            playColorExplanation("Muhteşem bir resim kaydettin")
        }

        // Renk seçimi butonları için tıklama olaylarını ekleme
        view.findViewById<Button>(R.id.buttonRed).setOnClickListener {
            paintView.setPaintColor(Color.RED)
            playColorExplanation("Kırmızı renk seçildi") // Sesli uyarı
        }

        view.findViewById<Button>(R.id.buttonGreen).setOnClickListener {
            paintView.setPaintColor(Color.GREEN)
            playColorExplanation("Yeşil renk seçildi") // Sesli uyarı
        }

        view.findViewById<Button>(R.id.buttonBlue).setOnClickListener {
            paintView.setPaintColor(Color.BLUE)
            playColorExplanation("Mavi renk seçildi") // Sesli uyarı
        }

        view.findViewById<Button>(R.id.buttonYellow).setOnClickListener {
            paintView.setPaintColor(Color.YELLOW)
            playColorExplanation("Sarı renk seçildi") // Sesli uyarı
        }

        view.findViewById<Button>(R.id.buttonBlack).setOnClickListener {
            paintView.setPaintColor(Color.BLACK)
            playColorExplanation("Siyah renk seçildi") // Sesli uyarı
        }
    }

    // TTS başlatıldığında bu fonksiyon çalışır
    override fun onInit(status: Int) {
        if (status == TextToSpeech.SUCCESS) {
            // Dil olarak Türkçe seçiyoruz
            val result = tts.setLanguage(Locale("tr", "TR"))
            if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
                speakOut("Bu dil desteklenmiyor")
            }
        } else {
            speakOut("Text to Speech başlatılamadı")
        }
    }

    // Sesli mesaj oynatma fonksiyonu
    private fun speakOut(message: String) {
        tts.speak(message, TextToSpeech.QUEUE_FLUSH, null, "")
    }

    // Text-to-Speech ile renk seçimi açıklaması yaparken müziği durdurma ve yeniden başlatma
    private fun playColorExplanation(message: String) {
        (activity as? MainActivity)?.let { mainActivity ->
            val wasPlaying = mainActivity.isMusicPlaying() // mediaPlayer yerine getter kullanılıyor
            mainActivity.pauseMusic()
            speakOut(message)

            tts.setOnUtteranceCompletedListener {
                // Eğer müzik başlangıçta çalıyorduysa tekrar başlat
                if (wasPlaying) {
                    mainActivity.playMusic()
                }
            }
        }
    }

    override fun onDestroy() {
        // TTS kaynağını serbest bırak
        if (tts != null) {
            tts.stop()
            tts.shutdown()
        }
        super.onDestroy()
    }

    private fun requestStoragePermissions() {
        if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(requireActivity(), arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE), STORAGE_PERMISSION_CODE)
        }
    }
}

大家好,我正在用Kotlin语言制作一个绘画绘图应用程序。绘图、着色、撤消、清除、保存等一切正常。但是当我在画画时改变形式时,我画的画就消失了。我想画一点,切换到另一种形式再回来,但我的画不应该被删除。

提前感谢您的回答。

android kotlin paint
1个回答
0
投票

从这里开始:

https://developer.android.com/guide/fragments/ saving-state

我在这里建议一种方法。

Fragment
类有一个名为
onSaveInstanceState
的方法,您可以重写该方法来跟踪 UI 状态。 实现
Parcelable
(Android 世界的
Serializable
)的类可以以在重建时可以恢复的方式保存。

当您实现将

onSaveInstanceState
状态置于
Parcelable
中的
Bundle
覆盖时,您可以在
onCreateView
onViewCreated
等方法中再次使用该数据作为
savedInstanceState
参数。 在其中一种方法中,您检查
savedInstanceState
是否存在数据,如果存在,您可以使用该数据重新创建视图的状态。

编码中最困难的部分是获取绘图数据的重要值——您的

List<Pair<Path, Paint>>
属性——并创建
Parcelable
实现来保存这些值,例如路径形状、路径坐标、油漆颜色、描边等

但是一旦你有了这些类,你的实现可能是这样的:

  • 给你的
    PaintView
    一个访问当前路径-绘制对列表(getter)的方法
  • 还在
    PaintView
    上编写一个方法来获取路径绘制对数据的列表,设置当前列表并渲染所有这些路径(setter)
  • 覆盖片段的
    onSaveInstanceState
    以调用视图的 getter 并创建列表的
    Parcelable
    表示并将其保存在包中
  • 检查
    savedInstanceState
    片段创建。 如果有已保存的数据,请反转操作并从
    Parcelable
    数据创建绘画路径对列表,并调用
    PaintView
    上的设置器以重新渲染绘图。

这种

savedInstanceState
方法仅适用于简单的绘图;对于复杂的绘图,持久数据对于状态包来说可能太大。

“使用片段保存状态”页面还讨论了使用

ViewModel
,它可以保留较大绘图的状态。

© www.soinside.com 2019 - 2024. All rights reserved.