簡體   English   中英

onClick 未觸發關聯的 function - kotlin

[英]onClick not triggering associated function - kotlin

編輯 - 我試圖在 XML 中將 android:focusable 和 android:clickable 屬性設置為 true,但它沒有改變任何東西。 還在尋找!

我不明白為什么我的 onClick 處理程序不能處理這種特殊情況。

我想使用數據綁定使 CardView 可點擊。 我已經看過很多 onClickListener 的代碼,但我決定使用這種模式,如 Android 文檔中所述。

我有一個名為 Recipe() 的 class,它包含 3 個元素:一個 ID、一個標題和一個 URL。 此單擊處理程序的最終目標是導航到新片段,將 ID 作為參數傳遞以顯示新元素。 稍后我將使用觀察者在 Fragment 中獲取 ID。

在這個例子中,我已經使用了 XML(recipe.image 和 recipe.title)中的 ViewModel 提供的數據,它工作得很好:數據被正確綁定和顯示。 但是,單擊 CardView 不會產生任何結果:由於未顯示日志,我想單擊不會觸發 onClick 事件。

您將在下面的 ViewModel 和 XML 中找到元素。 提前致謝!

class DefaultRecipeListViewModel : ViewModel() {

    private val _recipeList = MutableLiveData<List<Recipe>>()

    val recipeList: LiveData<List<Recipe>>
    get() = _recipeList

    //Defining coroutine
    private var viewModelJob = Job()
    private val coroutineScope = CoroutineScope(viewModelJob + Dispatchers.Main )

    //Livedata observed in the Fragment
    private var _navigateToRecipe = MutableLiveData<Int>()
    val navigateToRecipe: LiveData<Int>
        get() = _navigateToRecipe

    private var _showSnackbarEvent = MutableLiveData<Boolean>()
    val showSnackBarEvent: LiveData<Boolean>
        get() = _showSnackbarEvent

    init {
        getRecipesForNewbie()
    }

  fun getRecipesForNewbie() {
        coroutineScope.launch {
            var getRecipes = service.getRecipe().await()
            try {
                _recipeList.value = getRecipes.results
            } catch (e: Exception) {
                Log.i("ViewModel","Error: $e")
            }
        }
    }

    fun onRecipeClicked(id: Int) {
        _showSnackbarEvent.value = true
        _navigateToRecipe.value = id
        Log.i("ViewModel", "Item clicked, id: $id")
    }

    fun doneNavigating(){
        Log.i("ViewModel", "done navigating, navigateToRecipe set to -1")
        _navigateToRecipe.value = -1
    }

    fun doneShowingSnackbar() {
        _showSnackbarEvent.value = false
    }

    override fun onCleared() {
        super.onCleared()
        viewModelJob.cancel()
    }
}

這是 XML

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="recipe"
            type="com.example.recipesfornewbies.recipes.Recipe" />
        <variable
            name="viewModel"
            type="com.example.recipesfornewbies.defaultrecipelist.DefaultRecipeListViewModel" />
    </data>

    <LinearLayout
        android:layout_height="wrap_content"
        android:layout_width="match_parent">

        <androidx.cardview.widget.CardView
            android:id="@+id/card_view"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_marginBottom="6dp"
            android:layout_marginTop="6dp"
            app:cardCornerRadius="10dp"
            app:cardElevation="6dp"
            android:onClick="@{()-> viewModel.onRecipeClicked(recipe.id)}">
            <androidx.constraintlayout.widget.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent">

                <ImageView
                    android:id="@+id/recipe_image"
                    android:layout_width="match_parent"
                    android:layout_height="100dp"
                    android:contentDescription="@{recipe.title}"
                    app:imageFromUrl="@{recipe.image}"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    tools:layout_editor_absoluteX="0dp" />

                <TextView
                    android:id="@+id/recipe_name"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:paddingStart="16dp"
                    android:paddingEnd="16dp"
                    android:text="@{recipe.title}"
                    android:textSize="24sp"
                    app:layout_constraintTop_toBottomOf="@id/recipe_image"/>
            </androidx.constraintlayout.widget.ConstraintLayout>
        </androidx.cardview.widget.CardView>
    </LinearLayout>
</layout>

片段代碼:

class DefaultRecipeListFragment: Fragment(){

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {

    val binding = FragmentDefaultRecipeListBinding.inflate(inflater)

    val viewModel: DefaultRecipeListViewModel by lazy {
        ViewModelProviders.of(this).get(DefaultRecipeListViewModel::class.java)
    }
    binding.viewModel = viewModel

    // Allows Data Binding to Observe LiveData with the lifecycle of this Fragment
    binding.setLifecycleOwner(this)

    //Creating the RecyclerView
    val manager = LinearLayoutManager(activity)
    binding.recyclerRecipeList.layoutManager = manager

    binding.recyclerRecipeList.adapter = RecipeListAdapter()

    viewModel.navigateToRecipe.observe(this, Observer{id ->

        if (id != -1){
            Log.i("Fragment","Navigate to ${id}")
        }
        viewModel.doneNavigating()
    })

    viewModel.showSnackBarEvent.observe(this, Observer {
        if (it == true) {
            Snackbar.make(
                activity!!.findViewById(android.R.id.content),
                "Clicked!",
                Snackbar.LENGTH_SHORT
            ).show()
            viewModel.doneShowingSnackbar()
        }
    })

   return binding.root
}

}

ViewHolder class,用於RecyclerView Adapter

class RecipeViewHolder(private var binding: RecipeViewBinding):
    RecyclerView.ViewHolder(binding.root) {
    fun bind(Recipe: Recipe) {
        val imageURI = "https://spoonacular.com/recipeImages/"
        Recipe.image = imageURI + Recipe.image
        binding.recipe = Recipe
        // Forces the data binding to execute immediately,to correctly size RecyclerVieW
        binding.executePendingBindings()

    }

我最終決定在我的代碼上使用這個解決方案,效果很好。

我不再嘗試直接從 XML 訪問我的 ViewModel 中的 function:我實際上在片段上監聽事件,即使我發現解決方案不如我想要的那個漂亮。

在片段中,這是我處理點擊的方式: binding.recyclerRecipeList.addOnItemTouchListener(RecyclerItemClickListener(this.context,., binding:recyclerRecipeList. object : RecyclerItemClickListener.OnItemClickListener {

        override fun onItemClick(view: View, position: Int) {
            viewModel.recipeList.value?.let {
            val ident = it[position].id
            findNavController().navigate(
                DefaultRecipeListFragmentDirections.actionDefaultRecipeListFragmentToDetailedRecipeFragment(ident))
                Log.i("Fragment", "id: $ident")
            }
        }
        override fun onItemLongClick(view: View?, position: Int) {
            TODO("do nothing")
        }
    }))

仍然不明白為什么我的第一個解決方案不起作用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM