简体   繁体   English

将事件信息从“自定义视图”传递到ViewModel

[英]Passing Event Information from Custom View to ViewModel

Basically I am implementing a paint app, so I made a custom View to handle event and draw on canvas. 基本上,我正在实现绘画应用程序,因此我制作了一个自定义视图来处理事件并在画布上绘制。 Now I would like to display the coordinate of the points being drawn on a TextView in real time. 现在,我想实时显示在TextView上绘制的点的坐标。 So I am trying to use a ViewModel with LiveData to do the updating. 因此,我尝试将ViewModel与LiveData一起使用来进行更新。 But I can't figure out a way to give the information from my custom View to the ViewModel. 但是我想不出一种方法,可以将自定义View中的信息提供给ViewModel。 How would you do that ? 你会怎么做? I also tried to use BindingAdapter but I can't find a way to do that. 我也尝试使用BindingAdapter,但是我找不到方法。

Here the code for my custom View: 这是我的自定义视图的代码:

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)
    }
}

Here is a binding adapter that I found following this post: Android data binding view.onTouchListener . 这是我在本文后找到的绑定适配器: Android数据绑定view.onTouchListener I can Log the points coordinate, but I cant't send them to my ViewModel, so it is quite empty right now. 我可以记录点的坐标,但是无法将其发送到我的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
            }
        })
}

Sorry for sharing this in JAVA... But I guess you can capture the ideia. 很抱歉在JAVA中分享此内容...但是我想您可以抓住这个想法。

On CustomView, create a custom interface: 在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);
    }
}

Then, on your activity: 然后,关于您的活动:

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

This way, your PaintView can invoke the onUpdate whenever you want. 这样,您的PaintView可以随时调用onUpdate Then, in your activity, everytime the onUpdate is called, the TextView will have its content updated. 然后,在您的活动中,每次调用onUpdate ,TextView的内容都会更新。

I guess this is a good a approach because you create a custom interface ( OnCoordinateUpdate ) and it only makes sense to your custom view only. 我猜这是一个好方法,因为您创建了一个自定义界面( OnCoordinateUpdate ),它仅对您的自定义视图有意义。

Finally it worked the following way. 最终,它按照以下方式工作。 I took inspiration from the previous post and just used the binded viewmodel to call a function and then get the data. 我从前一篇文章中汲取了灵感,只是使用绑定的viewmodel调用一个函数然后获取数据。

here is the MainActivity code: 这是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() }
    }
}

Here is the ViewModel code, the challenge is to call the onUpdate function right in the ViewModel. 这是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
        }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM