从 Kotlin RecyclerView(cardview) onclick 加载详细信息视图

Load Details view from Kotlin RecyclerView(cardview) onclick

我有一个 RecyclerView 的片段,其中的项目在 CardViews 中。我有一个适配器,它将使用来自 newsapi.org 的数据填充 RecyclerView。我需要实现的是当我单击一个项目 (CardView) 以加载带有图像、标题和描述的 activity 时。我对 kotlin 很陌生,发现我被困在这里,需要帮助才能跟进。真的很有帮助。我将附上我的适配器和片段(它有 RecyclerView)。

我的问题是我应该在 onBindViewHolder -> ....cardView.setOnClickListener 中启动 activity 还是其他?令人困惑的部分是将图像(来自 url)设置为将值传递给详细信息视图。

适配器Class

class ArticleAdapter(
private var articleList: ArrayList<Article>
) : RecyclerView.Adapter<ArticleViewHolder>() {

private val placeHolderImage = "https://picsum.photos/200/200/?blur"
private lateinit var viewGroupContext: Context

override fun onCreateViewHolder(viewGroup: ViewGroup, p1: Int): ArticleViewHolder {
    viewGroupContext = viewGroup.context
    val itemView: View =
        LayoutInflater.from(viewGroup.context).inflate(R.layout.article_item, viewGroup, false)
    return ArticleViewHolder(itemView)
}

override fun getItemCount(): Int {
    return articleList.size
}

override fun onBindViewHolder(articleViewHolder: ArticleViewHolder, itemIndex: Int) {
    val article: Article = articleList.get(itemIndex)
    setPropertiesForArticleViewHolder(articleViewHolder, article)
    articleViewHolder.cardView.setOnClickListener {
        //do something
    }
}

private fun setPropertiesForArticleViewHolder(
    articleViewHolder: ArticleViewHolder,
    article: Article
) {
    checkForUrlToImage(article, articleViewHolder)
    articleViewHolder.title.text = article?.title
    articleViewHolder.description.text = article?.description
    articleViewHolder.url.text = article?.url
}

private fun checkForUrlToImage(article: Article, articleViewHolder: ArticleViewHolder) {
    if (article.urlToImage == null || article.urlToImage.isEmpty()) {
        Picasso.get()
            .load(placeHolderImage)
            .centerCrop()
            .fit()
            .into(articleViewHolder.urlToImage)
    } else {
        Picasso.get()
            .load(article.urlToImage)
            .centerCrop()
            .fit()
            .into(articleViewHolder.urlToImage)
    }
}

fun setArticles(articles: ArrayList<Article>) {
    articleList = articles
    notifyDataSetChanged()
}
}

//interface ItemClickListener{
//    fun onItemClick(articleList: Article, position:Int)
//}

片段

class HomeFragment : Fragment(), SwipeRefreshLayout.OnRefreshListener {

//    private lateinit var homeViewModel: HomeViewModel
private val ENDPOINT_URL by lazy { "https://newsapi.org/v2/" }
private lateinit var topHeadlinesEndpoint: TopHeadlinesEndpoint
private lateinit var newsApiConfig: String
private lateinit var articleAdapter: ArticleAdapter
private lateinit var articleList: ArrayList<Article>
private lateinit var userKeyWordInput: String
// RxJava related fields
private lateinit var topHeadlinesObservable: Observable<TopHeadlines>
private lateinit var compositeDisposable: CompositeDisposable

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

    return inflater.inflate(R.layout.fragment_home, container, false)
}

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

    swipe_refresh.setOnRefreshListener {
        queryTopHeadlines()
 //            refreshAction()  //refresh the list
        swipe_refresh.isRefreshing = false
    }

    //Network request
    val retrofit: Retrofit = generateRetrofitBuilder()
    topHeadlinesEndpoint = retrofit.create(TopHeadlinesEndpoint::class.java)
    newsApiConfig = resources.getString(R.string.api_key)
    swipe_refresh.setOnRefreshListener(this)
    swipe_refresh.setColorSchemeResources(R.color.colorAccent)
    articleList = ArrayList()
    articleAdapter = ArticleAdapter(articleList)

 //        userKeyWordInput = ""

    compositeDisposable = CompositeDisposable()
    recycler_viewHome.setHasFixedSize(true)
    recycler_viewHome.layoutManager = LinearLayoutManager(context)
    recycler_viewHome.itemAnimator = DefaultItemAnimator()
    recycler_viewHome.adapter = articleAdapter

}
override fun onStart() {
    super.onStart()
    queryTopHeadlines()
}
override fun onDestroy() {
    super.onDestroy()
    compositeDisposable.clear()
}
override fun onRefresh() {
    queryTopHeadlines()
}

private fun queryTopHeadlines() {
    swipe_refresh.isRefreshing = true
    topHeadlinesObservable = topHeadlinesEndpoint.getTopHeadlines("us", newsApiConfig)
    subscribeObservableOfArticle()
}

private fun subscribeObservableOfArticle() {
    articleList.clear()
    compositeDisposable.add(
        topHeadlinesObservable.subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .flatMap {
                Observable.fromIterable(it.articles)
            }
            .subscribeWith(createArticleObserver())
    )
}

private fun createArticleObserver(): DisposableObserver<Article> {
    return object : DisposableObserver<Article>() {
        override fun onNext(article: Article) {
            if (!articleList.contains(article)) {
                articleList.add(article)
            }
        }

        override fun onComplete() {
            showArticlesOnRecyclerView()
        }

        override fun onError(e: Throwable) {
            Log.e("createArticleObserver", "Article error: ${e.message}")
        }
    }
}

private fun showArticlesOnRecyclerView() {
    if (articleList.size > 0) {
        empty_text.visibility = View.GONE
        retry_fetch_button.visibility = View.GONE
        recycler_viewHome.visibility = View.VISIBLE
        articleAdapter.setArticles(articleList)
    } else {
        recycler_viewHome.visibility = View.GONE
        empty_text.visibility = View.VISIBLE
        retry_fetch_button.visibility = View.VISIBLE
 //            retry_fetch_button.setOnClickListener { checkUserKeywordInput()    }
    }
    swipe_refresh.isRefreshing = false
}

private fun generateRetrofitBuilder(): Retrofit {

    return Retrofit.Builder()
        .baseUrl(ENDPOINT_URL)
        .addConverterFactory(GsonConverterFactory.create())
        //Add RxJava2CallAdapterFactory as a Call adapter when building     your Retrofit instance
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .build()
}
}

初始化适配器时传递片段上下文 class

val adapter = ArticleAdapter(listItems, context);

里面 onClickListener

articleViewHolder.cardView.setOnClickListener {
    context.startActivity(context, TargetActivity);
}

首先您需要从您的 cardView 的 onclick 传递数据,然后开始 activity,最后在您想要的项目详细信息中处理这些数据 activity... 启动 activity 时需要 context/AppCompatActivity,因此您可以修改适配器的构造函数以接收 Context:

class ArticleAdapter(
   private val context: Context,
    private var articleList: ArrayList<Article>
) : RecyclerView.Adapter<ArticleViewHolder>()

在从您的 fragment:

初始化它时使用此构造函数
articleAdapter = ArticleAdapter(activity, articleList) // activity => getActivity()

在您的项目点击侦听器中:

 override fun onBindViewHolder(articleViewHolder: ArticleViewHolder, itemIndex: Int) {
    val article: Article = articleList?.get(itemIndex)
    setPropertiesForArticleViewHolder(articleViewHolder, article)
    articleViewHolder.cardView.setOnClickListener {

        val titleString = article.title
        val descString = article.description
        val urlString = article.url

        val toPass = Bundle()
        toPass.putString("url", urlString)
        toPass.putString("title", titleString)
        toPass.putString("desc", descString)

        val intent =
            Intent(context, YourActivity::class.java) //context we got from constructor
        intent.putExtras(toPass)
        context.startActivity(intent) // or we can use ContextCompat
    }
}

现在处理此数据并相应地设置视图:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val bundle = intent.extras
    val url = bundle?.get("url")
    val title = bundle?.get("title")
    val desc = bundle?.get("desc")

    // now handle those...

    titleTextView.text = title!!
//            ...

}

更新:我看到有人已经给出了类似的答案。但是,我仍然保留它,因为我在该答案中看到了一些问题。您不能使用 startActivity 从适配器启动 activity,它必须是 activity.startActivity

我帮你把东西弄碎

首先,您需要将列表和context/activity传递给适配器。您可以通过适配器的构造函数传递它。

class ArticleAdapter(
    val activity: AppCompatActivity
    val itemList: MutableList<String>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
}

因此,从片段中,您需要像这样发送 context/activity:

recyclerView.adapter = ArticleAdapter(activity!!, articleList)

现在,在您的适配器中,在 onBindViewHolder 方法中,您需要监听点击。

articleViewHolder.itemView.setOnClickListener {
    val intent = Intent(activity, YourDesiredActivity::class.java)
    activity.startActivity(intent)
}

如果 itemView 中有错误,请检查 ArticleViewHolder class 并从其构造函数中重命名视图。如果您遇到任何问题,请告诉我。