简体   繁体   English

如何在RecyclerView顶部插入图片

[英]How to insert picture on top of RecyclerView

I currently have a page on an app I'm working for a client. 我目前正在为客户使用的应用程序上有一个页面。 The page in question has an image on top of it, a banner i've been using. 有问题的页面上面有一个图像,这是我一直在使用的横幅。 Below that is a recycler view with cards that hold news information which are constantly changing everyday. 在此下方是一个回收站视图,其中包含用于存储新闻信息的卡,这些信息每天都在不断变化。 I did this before on the iOS version of this app where I put the image banner into the recyclerview(on iOS its called a collection) on the very top and then when you'd scroll through the recyclerview the image would move up and down with the scroll. 我之前在此应用的iOS版本上执行过此操作,在该版本中,我将图片横幅放在最顶部的recyclerview(在iOS上称为集合)中,然后当您滚动浏览recyclerview时,图片会随着上下移动滚动。 Is there any way where I can set the image banner into the recyclerview at the very top so it scrolls up and down with the cards in the recyclerview, as opposed to being outside the recyclerview. 有什么办法可以将图像横幅设置到最顶部的recyclerview中,以便它与卡一起在cyclerview中上下滚动,而不是在recyclerview之外。

The image banner takes up a lot of space which is why i want to insert it into the recyclerview so it frees up space on the screen when scrolling to view more cards at the same time. 图像横幅占据了大量空间,这就是为什么我想将其插入recyclerview的原因,以便在滚动滚动以同时查看更多卡片时可以释放屏幕上的空间。 See images below 看下面的图片

How the recyclerview looks without scrolling How the recyclerview looks after scrolling 无需滚动 ,recyclerview的外观滚动后,recyclerview的外观

public class News extends Fragment {

private static final String url = "somenewsurl";    //news url
private LinearLayoutManager linearLayoutManager;
private List<NewsItem> news;
private RecyclerView rv;
private RecyclerView.Adapter adapter;

public News() {
    // Required empty public constructor
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    return inflater.inflate(R.layout.fragment_news, container, false);
}

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {

    //initialize variables
    news = new ArrayList<>();
    adapter = new NewsRvAdapter(news, getActivity().getApplicationContext());

    //set up linear layout manager
    linearLayoutManager = new LinearLayoutManager(getActivity());
    linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);

    //set up recycler view
    rv = getView().findViewById(R.id.news_rv);
    rv.setHasFixedSize(true);
    rv.setLayoutManager(linearLayoutManager);
    rv.setAdapter(adapter);

    newsData();     //parse json data
}

Here is the other file used for this page with the image and recylerview 这是用于此页面的其他文件,其中包含图片和recylerview

public class NewsRvAdapter extends          RecyclerView.Adapter<NewsRvAdapter.MyViewHolder> {
private Context context;
private List<NewsItem> newsList;

//default constructor
public NewsRvAdapter(){}

public NewsRvAdapter(List<NewsItem> newsList, Context context){
    this.newsList = newsList;
    this.context = context;
}
@NonNull
@Override
public NewsRvAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
    View view;
    LayoutInflater layoutInflater = LayoutInflater.from(context);
    view = layoutInflater.inflate(R.layout.news_card, viewGroup, false);
    final MyViewHolder viewHolder = new MyViewHolder(view);
    return viewHolder;
}

@Override
public void onBindViewHolder(@NonNull final NewsRvAdapter.MyViewHolder myViewHolder, int i) {
    myViewHolder.title.setText(newsList.get(i).getTitle());
    myViewHolder.description.setText(newsList.get(i).getDescription());

    //Load image URL using Picasso
    Picasso.get()
            .load(newsList.get(i).getImageUrl())
            .centerCrop()
            .fit()
            .into(myViewHolder.photoUrl);

    //on click listener that opens url in webview
    myViewHolder.photoUrl.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View view) {
            String link = newsList.get(myViewHolder.getAdapterPosition()).getLink();
            Intent intent = new Intent();
            intent.setAction(Intent.ACTION_VIEW);
            intent.addCategory(Intent.CATEGORY_BROWSABLE);
            intent.setData(Uri.parse(link));
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(intent);
        }
    });

    //onclick that opens new activity
    myViewHolder.description.setOnClickListener(new View.OnClickListener(){
        @Override
        public void onClick(View view) {
            Intent i = new Intent(context, SingleNews.class);
            i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            i.putExtra("title", newsList.get(myViewHolder.getAdapterPosition()).getTitle());
            i.putExtra("urlToImage", newsList.get(myViewHolder.getAdapterPosition()).getImageUrl());
            i.putExtra("publishedAt", newsList.get(myViewHolder.getAdapterPosition()).getDate());
            i.putExtra("content", newsList.get(myViewHolder.getAdapterPosition()).getContent());
            context.startActivity(i);
        }
    });
}

@Override
public int getItemCount() {
    return newsList.size();
}

public static class MyViewHolder extends RecyclerView.ViewHolder{
    TextView title, description;
    ImageView photoUrl;
    LinearLayout viewContainer;
    public MyViewHolder(@NonNull View itemView) {
        super(itemView);
        title = itemView.findViewById(R.id.news_title);
        description = itemView.findViewById(R.id.news_description);
        photoUrl = itemView.findViewById(R.id.news_photo);
        viewContainer = itemView.findViewById(R.id.newsView_container);
    }
}

} }

Here is the xml file 这是xml文件

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout    xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/gradient"
tools:context=".News">

<ImageView
    android:id="@+id/img"
    android:layout_width="match_parent"
    android:layout_height="100dp"
    android:scaleType="centerCrop"
    app:srcCompat="@drawable/news" />

<android.support.v7.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_below="@+id/img"
    android:id="@+id/news_rv">
</android.support.v7.widget.RecyclerView>

Heres the error: 2019-08-19 11:36:13.788 14829-14829/com.example.gabe.politicianspulse E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.gabe.politicianspulse, PID: 14829 android.view.InflateException: Binary XML file line #10 in com.example.gabe.politicianspulse:layout/fragment_news: Binary XML file line #10 in com.example.gabe.politicianspulse:layout/fragment_news: Error inflating class androidx.core.widget.NestedScrollView Caused by: android.view.InflateException: Binary XML file line #10 in com.example.gabe.politicianspulse:layout/fragment_news: Error inflating class androidx.core.widget.NestedScrollView Caused by: java.lang.ClassNotFoundException: androidx.core.widget.NestedScrollView at java.lang.Class.classForName(Native Method) 继承人错误:2019-08-19 11:36:13.788 14829-14829 / com.example.gabe.politicianspulse E / AndroidRuntime:致命例外:主要过程:com.example.gabe.politicianspulse,PID:14829 android.view。 InflateException:com.example.gabe.politicianspulse:layout / fragment_news中的二进制XML文件第10行:com.example.gabe.politicianspulse:layout / fragment_news中的二进制XML文件第10行:膨胀类androidx.core.widget.NestedScrollView时出错原因:android.view.InflateException:com.example.gabe.politicianspulse:layout / fragment_news中的二进制XML文件第10行:膨胀类androidx.core.widget.NestedScrollView的原因:java.lang.ClassNotFoundException:androidx.core java.lang.Class.classForName上的.widget.NestedScrollView(本机方法)

You can wrap your layout with NestedScrollView 您可以使用NestedScrollView包装布局

It will be like this 就像这样

 <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/gradient"
    tools:context=".News">

    <android.support.v4.widget.NestedScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <ImageView
                android:id="@+id/img"
                android:layout_width="match_parent"
                android:layout_height="100dp"
                android:scaleType="centerCrop"
                app:srcCompat="@drawable/news" />

            <android.support.v7.widget.RecyclerView
                android:id="@+id/news_rv"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_below="@+id/img" />
        </LinearLayout>
      </android.support.v4.widget.NestedScrollView>


</RelativeLayout>

And don't forget to disable nested scroll on your recyclerview by calling setNestedScrollingEnabled(false); 并且不要忘了通过调用setNestedScrollingEnabled(false);来禁用recyclerview上的嵌套滚动setNestedScrollingEnabled(false); with your recyclerView reference object. 与您的recyclerView参考对象。

You can achieve a similar solution to your iOS solution by creating an adapter that uses different item view types alongside a list that contains your banner image + many "post" items. 通过创建一个使用不同项目视图类型的适配器以及一个包含横幅图像+许多“发布”项目的列表,可以实现与iOS解决方案类似的解决方案。

It's very verbose, but we can do a quick summary here: 这非常冗长,但是我们可以在此处进行快速总结:

First, create a class to represent the banner image. 首先,创建一个类来表示横幅图像。 Maybe a BannerItem class that has an imageId field or similar. 可能是具有imageId字段或类似内容的BannerItem类。

Second, in your adapter, change your list from List<NewsItem> to List<Object> (gross, I know). 其次,在您的适配器中,将列表从List<NewsItem>更改为List<Object> (很严重,我知道)。 Create this list by first adding one BannerItem and then adding your NewsItem s. 首先添加一个BannerItem ,然后添加NewsItem创建此列表。

Override getItemViewType() in your adapter to indicate which items are banner images and which are news cards: 覆盖适配器中的getItemViewType() ,以指示哪些项目是横幅图像,哪些是新闻卡:

@Override
public int getItemViewType(int position) {
    Object item = list.get(position);

    if (item instanceof BannerItem) {
        return 0;
    } else if (item instanceof NewsItem) {
        return 1;
    } else {
        throw new AssertionError("item can only be a banner image or news post");
    }
}

Then, in your onCreateViewHolder() and onBindViewHolder() methods, you can create/populate a different kind of ViewHolder based on the item view type. 然后,在onCreateViewHolder()onBindViewHolder()方法中,您可以根据项目视图类型创建/填充另一种ViewHolder

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    if (viewType == 0) {
        // is a banner image - return a BannerViewHolder
    } else if (viewType == 1) {
        // is a news post - return a NewsViewHolder
    } else {
        throw new AssertionError();
    }
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
    if (holder.getItemViewType() == 0) {
        // is a banner image - cast holder to BannerViewHolder
    } else if (holder.getItemViewType() == 1) {
        // is a news post - cast holder to NewsViewHolder
    } else {
        throw new AssertionError();
    }
}

A web search for recyclerview getitemviewtype should provide you with plenty of tutorials. 在网上搜索recyclerview getitemviewtype应该可以为您提供大量的教程。 At a quick glance, this one seems reasonable: https://guides.codepath.com/android/Heterogenous-Layouts-inside-RecyclerView 乍一看,这似乎是合理的: https : //guides.codepath.com/android/Heterogenous-Layouts-inside-RecyclerView

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM