【问题标题】:Passing Event Information from Custom View to ViewModel将事件信息从自定义视图传递到 ViewModel
【发布时间】:2019-05-20 19:24:18
【问题描述】:

基本上我正在实现一个绘画应用程序,所以我制作了一个自定义视图来处理事件并在画布上绘图。现在我想实时显示在 TextView 上绘制的点的坐标。所以我正在尝试使用带有 LiveData 的 ViewModel 来进行更新。但是我想不出一种将自定义视图中的信息提供给 ViewModel 的方法。你会怎么做?我也尝试过使用 BindingAdapter,但我找不到这样做的方法。

这里是我的自定义视图的代码:

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

    var params: LayoutParams
    private val path : Path = Path()
    private val brush: Paint  = Paint()

    init {
        params = LayoutParams(LayoutParams.MATCH_PARENT, 
        LayoutParams.WRAP_CONTENT)

        brush.isAntiAlias = true
        brush.color = Color.BLACK
        brush.style = Paint.Style.STROKE
        brush.strokeJoin = Paint.Join.ROUND
        brush.strokeWidth = 8f

    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        val pointX = event.x
        val pointY = event.y

        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                path.moveTo(pointX, pointY)
                return true
            }
            MotionEvent.ACTION_MOVE -> {
                path.lineTo(pointX, pointY)
            }
            else -> return false
        }
        postInvalidate()
        return false
    }

    fun clearPath(){
        path.reset()
        invalidate()
    }

    public override fun onDraw(canvas: Canvas) {
        canvas.drawPath(path, brush)
    }
}

这是我在这篇文章之后发现的一个绑定适配器:Android data binding view.onTouchListener。我可以记录点坐标,但我不能将它们发送到我的 ViewModel,所以它现在很空。

@BindingAdapter("touchListener")
fun setTouchListener(self: View, bool: Boolean) {
    self.setOnTouchListener(
        object : View.OnTouchListener {
            override fun onTouch(view: View, event: MotionEvent): Boolean {
                val pointX = event.x
                val pointY = event.y
                when (event.action) {
                    MotionEvent.ACTION_DOWN -> {
                        Log.i("Points", " ($pointX, $pointY)")
                    }
                    MotionEvent.ACTION_MOVE -> {
                        Log.i("Points", " ($pointX, $pointY)")
                    }
                    MotionEvent.ACTION_UP -> {
                        Log.i("Points", " ($pointX, $pointY)")
                    }
                }
                return false
            }
        })
}

【问题讨论】:

  • 您的视图的Context 应该是它所在的活动,或者是包装该活动的ContextWrapper。因此,您可以将 getContext() 转换为 FragmentActivity 并将其传递给 ViewModelProviders.of() 以获取视图模型对象的句柄。

标签: android kotlin


【解决方案1】:

很抱歉在 JAVA 中分享了这个……但我想你可以捕捉到这个想法。

在CustomView上,创建自定义界面:

public class PaintView {

    private OnCoordinateUpdate mCoordinatesListener;

    override fun onTouchEvent(event: MotionEvent): Boolean {
        val pointX = event.x
        val pointY = event.y
        ....
        if(listener != null) {
            listener.onUpdate(pointX, pointY);
        }
    }
    ...

    public void setCoordinatesListener(OnCoordinateUpdate listener) {
        mCoordinatesListener = listener;
    }

    public interface OnCoordinateUpdate {
        void onUpdate(int x, int y);
    }
}

那么,关于你的活动:

public class MainActivity {
    ...
    mPaintView.setCoordinatesListener(new PaintView.OnCoordinateUpdate {
        @Override
        void onUpdate(int x, int y) {
            if(mTextView != null) {
                mTextView.setText("X: " + x + " Y: " + y);
            }
        }
    });
}

这样,您的PaintView 可以随时调用onUpdate。然后,在您的活动中,每次调用 onUpdate 时,TextView 都会更新其内容。

我想这是一个很好的方法,因为您创建了一个自定义界面 (OnCoordinateUpdate),它只对您的自定义视图有意义。

【讨论】:

  • 嘿W0rmH0le!伟大的。我花了一些时间将代码从 Java 改编为 Kotlin,但它确实有效。谢谢哥们!
  • 但是,如果我能够在屏幕上显示点坐标,数据仍然不在 ViewModel 中,所以如果我切换模式,数据就会消失。如何在 ViewModel 中实现 onUpdate 并在 MainActivity 中调用它?
  • @jmamath 分享你的 ViewModel
【解决方案2】:

最后它以以下方式工作。 我从上一篇文章中获得灵感,只是使用绑定的视图模型调用一个函数,然后获取数据。

这里是 MainActivity 代码:

class MainActivity : AppCompatActivity () {

    private lateinit var binding: ActivityMainBinding
    private lateinit var viewModel: PaintViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        viewModel = ViewModelProviders.of(this).get(PaintViewModel::class.java)

        binding.viewmodel = viewModel
        binding.paintView.setCoordinatesListener(object : 
            PaintView.OnCoordinateUpdate {
            override fun onUpdate(x: Float, y: Float) {
                binding.textView.text = "X:  $x \nY:  $y"
                binding.viewmodel?.onUpdateCoordinate(x,y)
            }
        })
        binding.clearButton.setOnClickListener { binding.paintView.clearPath() }
    }
}

这里是 ViewModel 代码,挑战是在 ViewModel 中调用 onUpdate 函数。

class PaintViewModel : ViewModel() {
    private val _pointX = MutableLiveData<Float>()
    private val _pointY = MutableLiveData<Float>()

    val pointX : LiveData<Float> = _pointX
    val pointY : LiveData<Float> = _pointY

    init {
        _pointX.value = 0f
        _pointY.value = 0f
    }

    fun onUpdateCoordinate(x: Float, y: Float) {
            _pointX.value = x
            _pointY.value = y
        }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-21
    • 2021-01-08
    • 1970-01-01
    • 2023-03-27
    • 2017-05-12
    • 2013-04-12
    • 2015-04-11
    相关资源
    最近更新 更多