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

时间:2020-02-26 06:04:07

标签: android kotlin android-recyclerview onclicklistener cardview

我有一个片段,其中有一个RecyclerView,项目在CardViews中。我有一个适配器,该适配器将用RecyclerView中的数据填充newsapi.org。我需要实现的是单击一个项目(CardView)以加载带有图像,标题和描述的活动。我对Kotlin还是很陌生,发现我被困在这里,需要帮助来跟进。真的很有帮助。我将附加我的适配器和片段(具有RecyclerView)。

我应该遇到什么问题,我应该在onBindViewHolder-> .... cardView.setOnClickListener中启动活动吗?而令人困惑的部分是将图像(来自url)设置为将值传递给详细信息视图。

适配器类

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

3 个答案:

答案 0 :(得分:0)

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

val adapter = ArticleAdapter(listItems, context);

onClickListener

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

答案 1 :(得分:0)

首先,您需要传递cardView的onclick数据,然后开始活动,最后在所需的项目明细活动中处理这些数据... 开始活动时,您将需要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!!
//            ...

}

答案 2 :(得分:0)

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

我会帮你解决这个问题。

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

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

因此,从片段中,您需要像这样发送上下文/活动:

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

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

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

如果itemView中存在错误,请检查ArticleViewHolder类并从其构造函数重命名视图。让我知道您是否遇到任何问题。

相关问题