RecyclerView 显示不正确?
RecycleView not displaying properly?
我正在关注 Big Nerd Ranch Guide
(2015 年版)。我们从片段开始。本章介绍了RecycleView
。
目标是使用 RecycleView
显示 100 Crime
秒,如下所示:
作者使用 Crime
作为数据 object(字段:id、title、resolved、Date)。
我们有一个名为 SingleFragmentActivity
的超类 Activity
:
public abstract class SingleFragmentActivity extends FragmentActivity {
protected abstract Fragment createFragment();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment); //container for different fragments...
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.fragment_container);
if (fragment == null) {
fragment = createFragment();
fm.beginTransaction()
.add(R.id.fragment_container, fragment)
.commit();
}
}
}
伴随布局(如您在 SingleFragmentActivity 中所见)为 fragment_container.xml
:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
然后我们有一个子类,叫做CrimeListActivity
:
public class CrimeListActivity extends SingleFragmentActivity {
@Override
protected Fragment createFragment() {
return new CrimeListFragment();
}
}
CrimeListFragment
是,如您所想,ViewHolder
的内部 类 的 Fragment,RecycleView
需要 Adapter
来创建必要的 Views
并回收它们。
public class CrimeListFragment extends Fragment {
private RecyclerView mCrimeRecyclerView;
private CrimeAdapter mAdapter;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_crime_list, container, false);
mCrimeRecyclerView = (RecyclerView) view.findViewById(R.id.crime_recycler_view);
mCrimeRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
updateUI();
return view;
}
private void updateUI() {
CrimeLab crimeLab = CrimeLab.get(getActivity());
List<Crime> crimes = crimeLab.getCrimes();
mAdapter = new CrimeAdapter(crimes);
mCrimeRecyclerView.setAdapter(mAdapter);
}
private class CrimeHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
private Crime mCrime;
private TextView mTitleTextView;
private TextView mDateTextView;
private CheckBox mSolvedCheckBox;
public CrimeHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
mTitleTextView = (TextView)
itemView.findViewById(R.id.list_item_crime_title_text_view);
mDateTextView = (TextView)
itemView.findViewById(R.id.list_item_crime_date_text_view);
mSolvedCheckBox = (CheckBox)
itemView.findViewById(R.id.list_item_crime_solved_check_box);
}
public void bindCrime(Crime crime) {
mCrime = crime;
mTitleTextView.setText(mCrime.getTitle());
mDateTextView.setText(mCrime.getDate().toString());
mSolvedCheckBox.setChecked(mCrime.isSolved());
}
@Override
public void onClick(View v) {
Toast.makeText(getActivity(),mCrime.getTitle() + " clicked!", Toast.LENGTH_SHORT)
.show();
}
}
private class CrimeAdapter extends RecyclerView.Adapter<CrimeHolder> {
private List<Crime> mCrimes;
public CrimeAdapter(List<Crime> crimes) {
mCrimes = crimes;
}
@Override
public CrimeHolder onCreateViewHolder(ViewGroup parent, int viewType) {
/*onCreateViewHolder is called by the RecyclerView when it needs a new View to display an item. In
this method, you create the View and wrap it in a ViewHolder. The RecyclerView does not expect that
you will hook it up to any data yet.
For the View, you inflate a layout from the Android standard library called simple_list_item_1. This
layout contains a single TextView, styled to look nice in a list. Later in the chapter, you will make a
more advanced View for the list items*/
LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
View view = layoutInflater.inflate(R.layout.list_item_crime, parent, false);
return new CrimeHolder(view);
}
@Override
public void onBindViewHolder(CrimeHolder holder, int position) {
/*onBindViewHolder: This method will bind a ViewHolder’s View to your model object. It receives
the ViewHolder and a position in your data set. To bind your View, you use that position to find the
right model data. Then you update the View to reflect that model data.
In your implementation, that position is the index of the Crime in your array. Once you pull it out, you
bind that Crime to your View by sending its title to your ViewHolder’s TextView.*/
Crime crime = mCrimes.get(position);
holder.bindCrime(crime);
}
@Override
public int getItemCount() {
return mCrimes.size();
}
}
}
此片段的伴随布局自然是 RecycleView
xml 格式,命名为 fragment_crime_list.xml
:
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/crime_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
最后 Adapter
将通过其绑定数据的实际 ViewItem
以两个 TextViews
的形式给出(一个用于 Crime
的日期,一个用于 Crime
) 的标题,一个 CheckBox
用于标记犯罪已解决。
它被命名为 list_item_crime.xml
,看起来像这样:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<CheckBox
android:id="@+id/list_item_crime_solved_check_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:padding="4dp"/>
<TextView
android:id="@+id/list_item_crime_title_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/list_item_crime_solved_check_box"
android:textStyle="bold"
android:padding="4dp"
tools:text="Crime Title"/>
<TextView
android:id="@+id/list_item_crime_date_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/list_item_crime_solved_check_box"
android:layout_below="@id/list_item_crime_title_text_view"
android:padding="4dp"
tools:text="Crime Date"/>
</RelativeLayout>
现在,这是书中的内容,我仔细检查了所有内容,希望我没有遗漏任何内容。我的 Crime
项目只出现在屏幕顶部,我需要向下滚动到屏幕底部,只有第二个犯罪项目出现。像这样:
有人知道我在这里错过了什么吗?过去三天我一直在寻找修复这个问题的方法。其实在这里问是我最后的希望:)
没有足够的时间阅读所有这些,但我认为将 recyclerview list_item_crime.xml
的查看器的父布局高度设置为 wrap_content
也就是像这样
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox
android:id="@+id/list_ite.....
这个问题很难解决。仔细查看您的 list_item_crime.xml
文件。特别是在这一行:
android:layout_height="match_parent"
您正在将单个项目的高度设置为整个可用高度。如果您尝试滚动,您应该会看到下面的其他项目占据相同的高度。简单修复,更改为:
android:layout_height="wrap_content"
当我刚开始使用 Android 时,我讨厌 RecyclerView
,因为它会导致很多问题。这在我身上发生过不止一次:-)
我正在关注 Big Nerd Ranch Guide
(2015 年版)。我们从片段开始。本章介绍了RecycleView
。
目标是使用 RecycleView
显示 100 Crime
秒,如下所示:
作者使用 Crime
作为数据 object(字段:id、title、resolved、Date)。
我们有一个名为 SingleFragmentActivity
的超类 Activity
:
public abstract class SingleFragmentActivity extends FragmentActivity {
protected abstract Fragment createFragment();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment); //container for different fragments...
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.fragment_container);
if (fragment == null) {
fragment = createFragment();
fm.beginTransaction()
.add(R.id.fragment_container, fragment)
.commit();
}
}
}
伴随布局(如您在 SingleFragmentActivity 中所见)为 fragment_container.xml
:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
然后我们有一个子类,叫做CrimeListActivity
:
public class CrimeListActivity extends SingleFragmentActivity {
@Override
protected Fragment createFragment() {
return new CrimeListFragment();
}
}
CrimeListFragment
是,如您所想,ViewHolder
的内部 类 的 Fragment,RecycleView
需要 Adapter
来创建必要的 Views
并回收它们。
public class CrimeListFragment extends Fragment {
private RecyclerView mCrimeRecyclerView;
private CrimeAdapter mAdapter;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_crime_list, container, false);
mCrimeRecyclerView = (RecyclerView) view.findViewById(R.id.crime_recycler_view);
mCrimeRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
updateUI();
return view;
}
private void updateUI() {
CrimeLab crimeLab = CrimeLab.get(getActivity());
List<Crime> crimes = crimeLab.getCrimes();
mAdapter = new CrimeAdapter(crimes);
mCrimeRecyclerView.setAdapter(mAdapter);
}
private class CrimeHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
private Crime mCrime;
private TextView mTitleTextView;
private TextView mDateTextView;
private CheckBox mSolvedCheckBox;
public CrimeHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
mTitleTextView = (TextView)
itemView.findViewById(R.id.list_item_crime_title_text_view);
mDateTextView = (TextView)
itemView.findViewById(R.id.list_item_crime_date_text_view);
mSolvedCheckBox = (CheckBox)
itemView.findViewById(R.id.list_item_crime_solved_check_box);
}
public void bindCrime(Crime crime) {
mCrime = crime;
mTitleTextView.setText(mCrime.getTitle());
mDateTextView.setText(mCrime.getDate().toString());
mSolvedCheckBox.setChecked(mCrime.isSolved());
}
@Override
public void onClick(View v) {
Toast.makeText(getActivity(),mCrime.getTitle() + " clicked!", Toast.LENGTH_SHORT)
.show();
}
}
private class CrimeAdapter extends RecyclerView.Adapter<CrimeHolder> {
private List<Crime> mCrimes;
public CrimeAdapter(List<Crime> crimes) {
mCrimes = crimes;
}
@Override
public CrimeHolder onCreateViewHolder(ViewGroup parent, int viewType) {
/*onCreateViewHolder is called by the RecyclerView when it needs a new View to display an item. In
this method, you create the View and wrap it in a ViewHolder. The RecyclerView does not expect that
you will hook it up to any data yet.
For the View, you inflate a layout from the Android standard library called simple_list_item_1. This
layout contains a single TextView, styled to look nice in a list. Later in the chapter, you will make a
more advanced View for the list items*/
LayoutInflater layoutInflater = LayoutInflater.from(getActivity());
View view = layoutInflater.inflate(R.layout.list_item_crime, parent, false);
return new CrimeHolder(view);
}
@Override
public void onBindViewHolder(CrimeHolder holder, int position) {
/*onBindViewHolder: This method will bind a ViewHolder’s View to your model object. It receives
the ViewHolder and a position in your data set. To bind your View, you use that position to find the
right model data. Then you update the View to reflect that model data.
In your implementation, that position is the index of the Crime in your array. Once you pull it out, you
bind that Crime to your View by sending its title to your ViewHolder’s TextView.*/
Crime crime = mCrimes.get(position);
holder.bindCrime(crime);
}
@Override
public int getItemCount() {
return mCrimes.size();
}
}
}
此片段的伴随布局自然是 RecycleView
xml 格式,命名为 fragment_crime_list.xml
:
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/crime_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
最后 Adapter
将通过其绑定数据的实际 ViewItem
以两个 TextViews
的形式给出(一个用于 Crime
的日期,一个用于 Crime
) 的标题,一个 CheckBox
用于标记犯罪已解决。
它被命名为 list_item_crime.xml
,看起来像这样:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<CheckBox
android:id="@+id/list_item_crime_solved_check_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:padding="4dp"/>
<TextView
android:id="@+id/list_item_crime_title_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/list_item_crime_solved_check_box"
android:textStyle="bold"
android:padding="4dp"
tools:text="Crime Title"/>
<TextView
android:id="@+id/list_item_crime_date_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/list_item_crime_solved_check_box"
android:layout_below="@id/list_item_crime_title_text_view"
android:padding="4dp"
tools:text="Crime Date"/>
</RelativeLayout>
现在,这是书中的内容,我仔细检查了所有内容,希望我没有遗漏任何内容。我的 Crime
项目只出现在屏幕顶部,我需要向下滚动到屏幕底部,只有第二个犯罪项目出现。像这样:
有人知道我在这里错过了什么吗?过去三天我一直在寻找修复这个问题的方法。其实在这里问是我最后的希望:)
没有足够的时间阅读所有这些,但我认为将 recyclerview list_item_crime.xml
的查看器的父布局高度设置为 wrap_content
也就是像这样
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox
android:id="@+id/list_ite.....
这个问题很难解决。仔细查看您的 list_item_crime.xml
文件。特别是在这一行:
android:layout_height="match_parent"
您正在将单个项目的高度设置为整个可用高度。如果您尝试滚动,您应该会看到下面的其他项目占据相同的高度。简单修复,更改为:
android:layout_height="wrap_content"
当我刚开始使用 Android 时,我讨厌 RecyclerView
,因为它会导致很多问题。这在我身上发生过不止一次:-)