java Android RecyclerView First and Last Item click在双击首次加载后生效
我有一个新的视角。它在onCreateViewHolder
方法中有一个项目点击事件,在onBindViewHolder
方法中有一个imageview点击事件。令人惊讶的是,当recyclerview第一次加载first and last
项单击在第二次单击后生效,如果没有滚动,则在每次单击后生效。同样,当我滚动recyclerview时,第一个和最后一个项目也会发生同样的情况,比如first load。我想不出是什么问题
下面是我的recyclerview布局@+id/recyclerViewForFilteredCourses
是recyclerview
<安卓x.coordinatorlayout.widget.CoordinatorLayout xmlns:安卓="http://schemas.安卓.com/apk/res/安卓"
xmlns:app="http://schemas.安卓.com/apk/res-auto"
xmlns:tools="http://schemas.安卓.com/tools"
安卓:layout_width="match_parent"
安卓:layout_height="match_parent"
tools:context=".Activities.CoursesActivity">
<RelativeLayout
安卓:layout_width="match_parent"
安卓:layout_height="match_parent">
<include layout="@layout/toolbar_with_search"
安卓:id="@+id/toolbar" />
<com.github.ybq.安卓.spinkit.SpinKitView
xmlns:app="http://schemas.安卓.com/apk/res-auto"
安卓:id="@+id/progressBar"
安卓:layout_width="wrap_content"
安卓:layout_height="wrap_content"
安卓:layout_centerVertical="true"
安卓:layout_centerHorizontal="true"
app:SpinKit_Color="@color/textColorGrey"
安卓:visibility="gone"
安卓:elevation="200dp"
style="@style/SpinKitView.Circle"/>
<!--This textview and the recycler view is responsible for filtered course section-->
<TextView
安卓:id="@+id/filterResultTitle"
安卓:layout_width="wrap_content"
安卓:layout_height="wrap_content"
安卓:text="Showing X Courses"
安卓:layout_below="@+id/toolbar"
style="@style/headerTitleLabel"/>
<安卓x.recyclerview.widget.RecyclerView
安卓:id="@+id/recyclerViewForFilteredCourses"
安卓:layout_width="wrap_content"
安卓:layout_height="wrap_content"
安卓:layout_below="@+id/filterResultTitle"
安卓:layout_above="@+id/bottomNavigationView"
安卓:paddingHorizontal="14dp"
安卓:clipToPadding="false"
安卓:layout_marginTop="10dp"
安卓:overScrollMode="never"/>
<!--This is the floating filter button-->
<com.google.安卓.material.floatingactionbutton.FloatingActionButton
安卓:id="@+id/floatingFilterButton"
安卓:layout_width="wrap_content"
安卓:layout_height="wrap_content"
安卓:clickable="true"
安卓:layout_alignParentRight="true"
安卓:layout_marginRight="25dp"
安卓:layout_marginBottom="25dp"
安卓:layout_alignParentBottom="true"
安卓:backgroundTint="#273647"
安卓:elevation="6dp"
app:fabSize="normal"
app:borderWidth="0dp"
安卓:src="@drawable/filter"
安卓:onClick="handleFilterButton" />
</RelativeLayout>
<安卓x.core.widget.NestedScrollView
安卓:id="@+id/bottomSheet"
安卓:layout_width="match_parent"
安卓:layout_height="match_parent"
安卓:background="#FEFFFF"
app:layout_behavior="com.google.安卓.material.bottomsheet.BottomSheetBehavior"
app:behavior_hideable="true"
app:behavior_peekHeight = "0dp">
<include layout="@layout/course_filter_page" />
</安卓x.core.widget.NestedScrollView>
</安卓x.coordinatorlayout.widget.CoordinatorLayout>
下面是我的onCreateVieHolder项目点击
public CoursesAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.course_cell2, parent, false);
final ViewHolder holder = new ViewHolder(view);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
final Course currentCourse = mCourses.get(holder.getAdapterPosition());
switchToCourseDetailsActivity(currentCourse);
}
});
return holder;
}
private void switchToCourseDetailsActivity(Course currentCourse) {
Intent intent = new Intent(mContext, CourseDetailsActivity .class);
intent.putExtra("Course", currentCourse);
mContext.startActivity(intent);
}
下面是我完整的onBindViewHolder
public class CoursesAdapter extends RecyclerView.Adapter<CoursesAdapter.ViewHolder> {
private static final String TAG = "Courses List Adapter";
private static final String TAG2 = "Checker";
//vars
private Context mContext;
private ArrayList<Course> mCourses = new ArrayList<>();
Matcher matcher;
public CoursesAdapter(Context context, ArrayList<Course> courses) {
mCourses = courses;
mContext = context;
}
@NonNull
@Override
public CoursesAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.course_cell2, parent, false);
final ViewHolder holder = new ViewHolder(view);
return holder;
}
private void switchToCourseDetailsActivity(Course currentCourse) {
Intent intent = new Intent(mContext, CourseDetailsActivity .class);
intent.putExtra("Course", currentCourse);
mContext.startActivity(intent);
}
@Override
public void onBindViewHolder(@NonNull final CoursesAdapter.ViewHolder holder, final int position) {
final Course currentCourse = mCourses.get(position);
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
switchToCourseDetailsActivity(currentCourse);
}
});
holder.name.setText(currentCourse.getTitle());
// holder.coursePrice.setText(currentCourse.getPrice());
holder.totalNumberOfRating.setText("( "+currentCourse.getTotalNumberRating()+" )");
//holder.instructorName.setText("by "+currentCourse.getInstructor()+" "+currentCourse.getBiography());
holder.starRating.setRating(currentCourse.getRating());
holder.rating.setText((" "+currentCourse.getRating()+" "));
if(currentCourse.getIs_bestseller().equals("yes")){
holder.tvBestseller.setVisibility(View.VISIBLE);
}else{
holder.tvBestseller.setVisibility(View.GONE);
}
if(currentCourse.getCourseOverviewUrl()!=null && currentCourse.getCourseOverviewProvider()!=null && currentCourse.getCourseOverviewProvider().equals("youtube")){
//Extract video id from url
String pattern = "(?<=watch\\?v=|/videos/|embed\\/|youtu.be\\/|\\/v\\/|\\/e\\/|watch\\?v%3D|watch\\?feature=player_embedded&v=|%2Fvideos%2F|embed%\u200C\u200B2F|youtu.be%2F|%2Fv%2F)[^#\\&\\?\\n]*";
Pattern compiledPattern = Pattern.compile(pattern);
matcher = compiledPattern.matcher(currentCourse.getCourseOverviewUrl()); //url is youtube url for which you want to extract the id.
if (matcher.find()) {
holder.play_video.setVisibility(View.VISIBLE);
holder.play_video1.setVisibility(View.VISIBLE);
} else{
holder.play_video.setVisibility(View.GONE);
holder.play_video1.setVisibility(View.GONE);
}
} else{
holder.play_video.setVisibility(View.GONE);
holder.play_video1.setVisibility(View.GONE);
}
holder.play_video.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
final BottomSheetDialog dialog3 = new BottomSheetDialog(mContext);
dialog3.setContentView(R.layout.bottom_videoplay);
if(!dialog3.isShowing()) {
dialog3.show();
}
dialog3.setCancelable(true);
final WebView web_view = (WebView) dialog3.findViewById(R.id.youtube_web_view);
final ProgressBar progressBar2 = (ProgressBar) dialog3.findViewById(R.id.progressBar2);
final TextView tvTitle2 = (TextView) dialog3.findViewById(R.id.tvTitle2);
final TextView tvEnroll = (TextView) dialog3.findViewById(R.id.tvEnroll);
tvTitle2.setText(currentCourse.getTitle());
tvEnroll.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
switchToCourseDetailsActivity(currentCourse);
}
});
//String myVideoYoutubeId = "Wwy9aibAd54";
String myVideoYoutubeId;
WebSettings webSettings = web_view.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setLoadWithOverviewMode(true);
webSettings.setUseWideViewPort(true);
myVideoYoutubeId=matcher.group();
web_view.loadUrl("https://www.youtube.com/embed/" + myVideoYoutubeId);
web_view.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false;
}
});
web_view.setWebViewClient(new WebViewClient() {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
progressBar2.setVisibility(View.VISIBLE);
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
progressBar2.setVisibility(View.GONE);
//to enable autoplay ref:https://stackoverflow.com/questions/28039209/安卓-webview-youtube-embed-video-autoplay-not-working/45655979#45655979
long delta = 100;
long downTime = SystemClock.uptimeMillis();
float x = view.getLeft() + (view.getWidth()/2);
float y = view.getTop() + (view.getHeight()/2);
MotionEvent tapDownEvent = MotionEvent.obtain(downTime, downTime + delta, MotionEvent.ACTION_DOWN, x, y, 0);
tapDownEvent.setSource(InputDevice.SOURCE_CLASS_POINTER);
MotionEvent tapUpEvent = MotionEvent.obtain(downTime, downTime + delta + 2, MotionEvent.ACTION_UP, x, y, 0);
tapUpEvent.setSource(InputDevice.SOURCE_CLASS_POINTER);
view.dispatchTouchEvent(tapDownEvent);
view.dispatchTouchEvent(tapUpEvent);
}
});
}
});
holder.play_video1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
holder.play_video.performClick();
}
});
if(currentCourse.getIs_mentor()!=null && currentCourse.getIs_mentor().equals("1")){
holder.instructorName.setVisibility(View.VISIBLE);
holder.tvMentor.setVisibility(View.GONE);
if(currentCourse.getBiography()!=null) {
holder.instructorName.setText("by " + currentCourse.getInstructor() + " " + currentCourse.getBiography());
}else{
holder.instructorName.setText("by " + currentCourse.getInstructor());
}
} else{
//holder.tvMentor.setVisibility(View.GONE);
holder.instructorName.setVisibility(View.GONE);
holder.tvMentor.setVisibility(View.VISIBLE);
if(currentCourse.getBiography()!=null) {
holder.tvMentor.setText("by " + currentCourse.getInstructor() + " " + currentCourse.getBiography());
} else{
holder.tvMentor.setText("by " + currentCourse.getInstructor());
}
}
if(currentCourse.getMain_price()!=null && !currentCourse.getPrice().equals("Free")){
String c_price = currentCourse.getPrice().substring(0, currentCourse.getPrice().length() - 1);
Double main_price=Double.parseDouble(currentCourse.getMain_price());
Double current_price=Double.parseDouble(c_price);
if(current_price<main_price){
holder.tvcompare.setVisibility(View.VISIBLE);
holder.tvDiscountprice.setVisibility(View.VISIBLE);
holder.tvDiscountprice.setText(Double.toString(main_price)+"Tk");
Double diff=main_price-current_price;
Double percent=diff*100/main_price;
holder.tvcompare.setText(percent+"% OFF");
}else{
holder.tvDiscountprice.setVisibility(View.GONE);
holder.tvcompare.setVisibility(View.GONE);
}
} else{
holder.tvcompare.setVisibility(View.GONE);
holder.tvDiscountprice.setVisibility(View.GONE);
}
if(!currentCourse.getPrice().equals("Free")) {
String c_price = currentCourse.getPrice().substring(0, currentCourse.getPrice().length() - 1);
holder.coursePrice.setText(c_price + "Tk");
} else{
holder.coursePrice.setText(currentCourse.getPrice());
}
if(currentCourse.getCourse_type()!=null){
if(currentCourse.getCourse_type().equals("Course")){
holder.tvCategory.setText("Lifetime Access");
holder.image.setVisibility(View.VISIBLE);
holder.play_video.setVisibility(View.VISIBLE);
holder.monthly_couching.setVisibility(View.GONE);
Glide.with(mContext)
.asBitmap()
.load(currentCourse.getThumbnail())
.into(holder.image);
}
if (currentCourse.getCourse_type().equals("MonthlyCouching")){
holder.tvCategory.setText("Monthly Couching");
holder.coursePrice.setText(holder.coursePrice.getText()+"/month");
holder.image.setVisibility(View.GONE);
holder.play_video.setVisibility(View.GONE);
holder.monthly_couching.setVisibility(View.VISIBLE);
Picasso.get().load(currentCourse.getThumbnail()).into(holder.image);
Picasso.get().load(currentCourse.getThumbnail()).into(holder.image1);
if(currentCourse.getOnline_classschedule()!=null){
holder.layout_classschedule.setVisibility(View.VISIBLE);
holder.tvClass_schedule.setText(currentCourse.getOnline_classschedule());
} else{
holder.layout_classschedule.setVisibility(View.GONE);
}
}
if(currentCourse.getCourse_type().equals("FixedTermCouching")){
holder.image.setVisibility(View.GONE);
holder.play_video.setVisibility(View.GONE);
holder.monthly_couching.setVisibility(View.VISIBLE);
if(currentCourse.getDuration()!=null && currentCourse.getStart_date()!=null){
long l = Long.parseLong(currentCourse.getStart_date());
Date date = new Date(l);
holder.tvCategory.setText(currentCourse.getDuration()+" Couching starting on "+date);
}
if(currentCourse.getOnline_classschedule()!=null){
holder.layout_classschedule.setVisibility(View.VISIBLE);
holder.tvClass_schedule.setText(currentCourse.getOnline_classschedule());
} else{
holder.layout_classschedule.setVisibility(View.GONE);
}
}
if(currentCourse.getCourse_type().equals("Workshop")){
holder.image.setVisibility(View.VISIBLE);
holder.play_video.setVisibility(View.VISIBLE);
holder.monthly_couching.setVisibility(View.GONE);
if(currentCourse.getDuration()!=null && currentCourse.getStart_date()!=null){
long l = Long.parseLong(currentCourse.getStart_date());
Date date = new Date(l);
holder.tvCategory.setText(currentCourse.getDuration()+" workshop starting on "+date);
}
}
}
if(currentCourse.getWeekly_class()!=null && currentCourse.getWeekly_class().equals("1")){
holder.tvweekly_class.setVisibility(View.VISIBLE);
if(currentCourse.getWeeklyonline_class()!=null && Integer.parseInt(currentCourse.getWeeklyonline_class())>0){
holder.tvweekly_class.setText(holder.tvweekly_class.getText()+" "+currentCourse.getWeeklyonline_class());
}
} else{holder.tvweekly_class.setVisibility(View.GONE);}
if(currentCourse.getWeekly_exam()!=null && currentCourse.getWeekly_exam().equals("1")){
holder.tvweekly_exam.setVisibility(View.VISIBLE);
if(currentCourse.getWeeklyonline_test()!=null && Integer.parseInt(currentCourse.getWeeklyonline_test())>0){
holder.tvweekly_exam.setText(holder.tvweekly_exam.getText()+" "+currentCourse.getWeeklyonline_test());
}
} else{holder.tvweekly_exam.setVisibility(View.GONE);}
if(currentCourse.getReview_class()!=null && currentCourse.getReview_class().equals("1")){
holder.tvreview_class.setVisibility(View.VISIBLE);
} else{holder.tvreview_class.setVisibility(View.GONE);}
if(currentCourse.getCourse_upload()!=null && currentCourse.getCourse_upload().equals("1")){
holder.tvcourse_upload.setVisibility(View.VISIBLE);
} else{holder.tvcourse_upload.setVisibility(View.GONE);}
if(currentCourse.getRecord_upload()!=null && currentCourse.getRecord_upload().equals("1")){
holder.tvrecord_upload.setVisibility(View.VISIBLE);
} else{holder.tvrecord_upload.setVisibility(View.GONE);}
if(currentCourse.getCourse_type()!=null && currentCourse.getCourse_type().equals("FixedTermCouching") && currentCourse.getLifetime_access()!=null && currentCourse.getLifetime_access().equals("1")){
holder.tvlifetime_access.setVisibility(View.VISIBLE);
} else{holder.tvlifetime_access.setVisibility(View.GONE);}
}
@Override
public int getItemCount() {
return mCourses.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
ImageView image,image1,play_video,play_video1;
TextView name;
TextView coursePrice;
TextView instructorName;
TextView rating;
TextView totalNumberOfRating;
RatingBar starRating;
TextView tvweekly_class,tvweekly_exam,tvreview_class,tvcourse_upload,tvrecord_upload,tvlifetime_access,tvCategory,tvDiscountprice,tvMentor,tvcompare,tvBestseller,tvClass_schedule;
RelativeLayout monthly_couching;
LinearLayout layout_classschedule;
public ViewHolder(View itemView) {
super(itemView);
image = itemView.findViewById(R.id.courseThumbnail);
image1 = itemView.findViewById(R.id.courseThumbnail1);
name = itemView.findViewById(R.id.courseTitle);
coursePrice = itemView.findViewById(R.id.tvcoursePrice);
instructorName = itemView.findViewById(R.id.instructorName);
rating = itemView.findViewById(R.id.numericRating);
totalNumberOfRating = itemView.findViewById(R.id.totalNumberOfRatingByUsers);
starRating = itemView.findViewById(R.id.starRating);
tvweekly_class=itemView.findViewById(R.id.tvweekly_class);
tvweekly_exam=itemView.findViewById(R.id.tvweekly_exam);
tvreview_class=itemView.findViewById(R.id.tvreview_class);
tvcourse_upload=itemView.findViewById(R.id.tvcourse_upload);
tvrecord_upload=itemView.findViewById(R.id.tvrecord_upload);
tvlifetime_access=itemView.findViewById(R.id.tvlifetime_access);
tvCategory=itemView.findViewById(R.id.tvCategory);
tvDiscountprice=itemView.findViewById(R.id.tvDiscountprice);
tvMentor=itemView.findViewById(R.id.tvMentor);
play_video=itemView.findViewById(R.id.play_video);
play_video1=itemView.findViewById(R.id.play_video1);
tvcompare=itemView.findViewById(R.id.tvcompare);
tvBestseller=itemView.findViewById(R.id.tvBestseller);
monthly_couching=itemView.findViewById(R.id.monthly_couching);
tvClass_schedule=itemView.findViewById(R.id.tvClass_schedule);
layout_classschedule=itemView.findViewById(R.id.layout_classschedule);
}
}
}
# 1 楼答案
RecyclerView
重用视图持有者以提高性能。你也可以说它回收视图持有者——这就是它的名字来源RecyclerView
适配器将不会创建超过其要求的视图持有者。视图持有者的数量大致可以等于:因此,它将生成填充屏幕的视图持有者数量+1个屏幕外的项目(例如,在回收器视图的底部),以平滑滚动动画并消除任何故障
接下来:将任何数据绑定到视图持有者
onCreateViewHolder
仅用于创建视图持有者! 永远不要从^{如果适配器中有100个要显示的项目,但设备的屏幕只能显示10个,那么在滚动列表时,将有11个视图保持架可重复使用
每次显示项目时都会调用
onBindViewHolder
——这是将数据附加到视图持有者的地方