Загрузить представление сведений из Kotlin RecyclerView (cardview) onclick - PullRequest
2 голосов
/ 26 февраля 2020

У меня есть фрагмент, который имеет 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 голосов
/ 26 февраля 2020

Сначала вам нужно передать данные из onclick вашего cardView, а затем начать действие, и, наконец, обработать эти данные в желаемой операции с деталями элемента ... При запуске действия вам понадобится 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!!
//            ...

}
0 голосов
/ 26 февраля 2020

Обновление: я вижу, кто-то уже дал аналогичный ответ. Однако, я все еще держу это, поскольку я вижу некоторые проблемы в этом ответе. Вы не можете начать действие с Адаптера с 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 и переименуйте представление из его конструктора. Дайте мне знать, если у вас возникнут какие-либо проблемы.

0 голосов
/ 26 февраля 2020

Передать контекст фрагмента при инициализации класса адаптера

val adapter = ArticleAdapter(listItems, context);

Внутри onClickListener

articleViewHolder.cardView.setOnClickListener {
    context.startActivity(context, TargetActivity);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...