从 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 并从其构造函数中重命名视图。如果您遇到任何问题,请告诉我。
我有一个 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 并从其构造函数中重命名视图。如果您遇到任何问题,请告诉我。