这就是我要的:
如上图所示,我想绘制一条中心线RecycleView
,然后在滚动时(以及向左或向右移动)获取中心项目.
这是我尝试绘制水平线RecycleView
:
HorizontalAdapter adapter = new HorizontalAdapter(data); LinearLayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false); recycleView.setLayoutManager(layoutManager); recycleView.setAdapter(adapter);
有没有办法知道哪个项目被移动到中心RecycleView
?如何RecycleView
向左或向右滚动一个位置?
更新:我试图使用滚动侦听器来获得中间位置,但它不能作为方面.
@Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); int firstPos = layoutManager.findFirstVisibleItemPosition(); int lastPos = layoutManager.findLastVisibleItemPosition(); int middle = Math.abs(lastPos - firstPos) / 2 + firstPos; int selectedPos = -1; for (int i = 0; i < adapter.getItemCount(); i++) { if (i == middle) { adapter.getItem(i).setSelected(true); selectedPos = i; } else { adapter.getItem(i).setSelected(false); } } adapter.notifyDataSetChanged(); }
得到结果:
我只想在蓝色时更改选择项目(使文本变为白色) Rect
我做了这样的事.我可以完全按照你的需要做.首先,这就是我的算法是如何运作的
这是我的recyclerView适配器
public class DateAdapter extends RecyclerView.Adapter{ private ArrayList dateDataList; private static final int VIEW_TYPE_PADDING = 1; private static final int VIEW_TYPE_ITEM = 2; private int paddingWidthDate = 0; private int selectedItem = -1; public DateAdapter(ArrayList dateData, int paddingWidthDate) { this.dateDataList = dateData; this.paddingWidthDate = paddingWidthDate; } @Override public DateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == VIEW_TYPE_ITEM) { final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_date, parent, false); return new DateViewHolder(view); } else { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_padding, parent, false); RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams(); layoutParams.width = paddingWidthDate; view.setLayoutParams(layoutParams); return new DateViewHolder(view); } } @Override public void onBindViewHolder(DateViewHolder holder, int position) { LabelerDate labelerDate = dateDataList.get(position); if (getItemViewType(position) == VIEW_TYPE_ITEM) { if(labelerDate.dateType.equals(BirthDayActivity.DateType.C31)) holder.tvDate.setText(String.valueOf(labelerDate.valueDate)); holder.tvDate.setVisibility(View.VISIBLE); holder.imgSmall.setVisibility(View.VISIBLE); if (position == selectedItem) { holder.tvDate.setTextColor(Color.parseColor("#094673")); holder.tvDate.setTextSize(35); holder.imgSmall.setBackgroundResource(R.color.textviewbold); } else { holder.tvDate.setTextColor(Color.GRAY); holder.tvDate.setTextSize(35); holder.imgSmall.setBackgroundResource(R.color.gray); } } } public void setSelecteditem(int selecteditem) { this.selectedItem = selecteditem; notifyDataSetChanged(); } @Override public int getItemCount() { return dateDataList.size(); } @Override public int getItemViewType(int position) { LabelerDate labelerDate = dateDataList.get(position); if (labelerDate.dateType.equals(BirthDayActivity.DateType.NONE)) { return VIEW_TYPE_PADDING; } return VIEW_TYPE_ITEM; } public class DateViewHolder extends RecyclerView.ViewHolder { public TextView tvDate; public ImageView imgSmall; public DateViewHolder(View itemView) { super(itemView); tvDate = (TextView) itemView.findViewById(R.id.tvNumberDate); imgSmall = (ImageView) itemView.findViewById(R.id.small_marked_dob); } }}
这是最重要的算法:
public void getRecyclerviewDate() { recyclerViewDate = (RecyclerView) findViewById(R.id.recyclerViewDay); ViewTreeObserver vtoDate = recyclerViewDate.getViewTreeObserver(); vtoDate.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { recyclerViewDate.getViewTreeObserver().removeOnPreDrawListener(this); finalWidthDate = recyclerViewDate.getMeasuredWidth(); itemWidthDate = getResources().getDimension(R.dimen.item_dob_width); paddingDate = (finalWidthDate - itemWidthDate) / 2; firstItemWidthDate = paddingDate ; allPixelsDate = 0; final LinearLayoutManager dateLayoutManager = new LinearLayoutManager(getApplicationContext()); dateLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); recyclerViewDate.setLayoutManager(dateLayoutManager); recyclerViewDate.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); synchronized (this) { if(newState == RecyclerView.SCROLL_STATE_IDLE){ calculatePositionAndScrollDate(recyclerView); } } } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); allPixelsDate += dx; } }); if (labelerDates == null) labelerDates = new ArrayList<>(); labelerDates.addAll(genLabelerDate(currentMonth, currentYear)); dateAdapter = new DateAdapter(labelerDates, (int) firstItemWidthDate); recyclerViewDate.setAdapter(dateAdapter); return true; } }); } /* this if most important, if expectedPositionDate < 0 recyclerView will return to nearest item*/ private void calculatePositionAndScrollDate(RecyclerView recyclerView) { int expectedPositionDate = Math.round((allPixelsDate + paddingDate - firstItemWidthDate) / itemWidthDate); if (expectedPositionDate == -1) { expectedPositionDate = 0; } else if (expectedPositionDate >= recyclerView.getAdapter().getItemCount() - 2) { expectedPositionDate--; } scrollListToPositionDate(recyclerView, expectedPositionDate); } /* this if most important, if expectedPositionDate < 0 recyclerView will return to nearest item*/ private void scrollListToPositionDate(RecyclerView recyclerView, int expectedPositionDate) { float targetScrollPosDate = expectedPositionDate * itemWidthDate + firstItemWidthDate - paddingDate; float missingPxDate = targetScrollPosDate - allPixelsDate; if (missingPxDate != 0) { recyclerView.smoothScrollBy((int) missingPxDate, 0); } } private void setDateValue() { int expectedPositionDateColor = Math.round((allPixelsDate + paddingDate - firstItemWidthDate) / itemWidthDate); setColorDate = expectedPositionDateColor + 1; //set color here dateAdapter.setSelecteditem(setColorDate); } @Override protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); allPixelsDate = savedInstanceState.getFloat(BUNDLE_LIST_PIXELS_DATE); allPixelsDateChanged = savedInstanceState.getFloat(BUNDLE_LIST_PIXELS_DATE_CHANGED); } @Override protected void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); outState.putFloat(BUNDLE_LIST_PIXELS_DATE, allPixelsDate); outState.putFloat(BUNDLE_LIST_PIXELS_DATE_CHANGED, allPixelsDateChanged); }
这是我的结果:
看看这个视频链接,这是我的应用程序演示
有时需要将整个示例代码块放在一起,因为我们可能会错过一些东西.这就是我所拥有的,随意纠正任何事情,因为我可能在某处犯了一些小错误.是的,这个答案是@tranhieu答案的延伸.谢谢@tranhieu.
MainActivity.java
package com.test; import android.app.Activity; import android.graphics.Color; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.ViewTreeObserver; import android.widget.TextView; import java.util.ArrayList; public class MainActivity extends Activity { private static final String TAG = MainActivity.class.getSimpleName(); public float firstItemWidthDate; public float paddingDate; public float itemWidthDate; public int allPixelsDate; public int finalWidthDate; private DateAdapter dateAdapter; private ArrayListlabelerDates = new ArrayList<>(); @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); getRecyclerviewDate(); } public void getRecyclerviewDate() { final RecyclerView recyclerViewDate = (RecyclerView) findViewById(R.id.rv_tasks_date); if (recyclerViewDate != null) { recyclerViewDate.postDelayed(new Runnable() { @Override public void run() { setDateValue(); } }, 300); recyclerViewDate.postDelayed(new Runnable() { @Override public void run() { recyclerViewDate.smoothScrollToPosition(dateAdapter.getItemCount()-1); setDateValue(); } }, 5000); } ViewTreeObserver vtoDate = recyclerViewDate.getViewTreeObserver(); vtoDate.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { recyclerViewDate.getViewTreeObserver().removeOnPreDrawListener(this); finalWidthDate = recyclerViewDate.getMeasuredWidth(); itemWidthDate = getResources().getDimension(R.dimen.item_dob_width); paddingDate = (finalWidthDate - itemWidthDate) / 2; firstItemWidthDate = paddingDate; allPixelsDate = 0; final LinearLayoutManager dateLayoutManager = new LinearLayoutManager(getApplicationContext()); dateLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); recyclerViewDate.setLayoutManager(dateLayoutManager); recyclerViewDate.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); synchronized (this) { if (newState == RecyclerView.SCROLL_STATE_IDLE) { calculatePositionAndScrollDate(recyclerView); } } } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); allPixelsDate += dx; } }); if (labelerDates == null) { labelerDates = new ArrayList<>(); } genLabelerDate(); dateAdapter = new DateAdapter(labelerDates, (int) firstItemWidthDate); recyclerViewDate.setAdapter(dateAdapter); dateAdapter.setSelecteditem(dateAdapter.getItemCount() - 1); return true; } }); } private void genLabelerDate() { for (int i = 0; i < 32; i++) { LabelerDate labelerDate = new LabelerDate(); labelerDate.setNumber(Integer.toString(i)); labelerDates.add(labelerDate); if (i == 0 || i == 31) { labelerDate.setType(DateAdapter.VIEW_TYPE_PADDING); } else { labelerDate.setType(DateAdapter.VIEW_TYPE_ITEM); } } } /* this if most important, if expectedPositionDate < 0 recyclerView will return to nearest item*/ private void calculatePositionAndScrollDate(RecyclerView recyclerView) { int expectedPositionDate = Math.round((allPixelsDate + paddingDate - firstItemWidthDate) / itemWidthDate); if (expectedPositionDate == -1) { expectedPositionDate = 0; } else if (expectedPositionDate >= recyclerView.getAdapter().getItemCount() - 2) { expectedPositionDate--; } scrollListToPositionDate(recyclerView, expectedPositionDate); } /* this if most important, if expectedPositionDate < 0 recyclerView will return to nearest item*/ private void scrollListToPositionDate(RecyclerView recyclerView, int expectedPositionDate) { float targetScrollPosDate = expectedPositionDate * itemWidthDate + firstItemWidthDate - paddingDate; float missingPxDate = targetScrollPosDate - allPixelsDate; if (missingPxDate != 0) { recyclerView.smoothScrollBy((int) missingPxDate, 0); } setDateValue(); } // private void setDateValue() { int expectedPositionDateColor = Math.round((allPixelsDate + paddingDate - firstItemWidthDate) / itemWidthDate); int setColorDate = expectedPositionDateColor + 1; // set color here dateAdapter.setSelecteditem(setColorDate); } public class DateAdapter extends RecyclerView.Adapter { private ArrayList dateDataList; private static final int VIEW_TYPE_PADDING = 1; private static final int VIEW_TYPE_ITEM = 2; private int paddingWidthDate = 0; private int selectedItem = -1; public DateAdapter(ArrayList dateData, int paddingWidthDate) { this.dateDataList = dateData; this.paddingWidthDate = paddingWidthDate; } @Override public DateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { if (viewType == VIEW_TYPE_ITEM) { final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false); return new DateViewHolder(view); } else { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false); RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams(); layoutParams.width = paddingWidthDate; view.setLayoutParams(layoutParams); return new DateViewHolder(view); } } @Override public void onBindViewHolder(DateViewHolder holder, int position) { LabelerDate labelerDate = dateDataList.get(position); if (getItemViewType(position) == VIEW_TYPE_ITEM) { holder.tvDate.setText(labelerDate.getNumber()); holder.tvDate.setVisibility(View.VISIBLE); Log.d(TAG, "default " + position + ", selected " + selectedItem); if (position == selectedItem) { Log.d(TAG, "center" + position); holder.tvDate.setTextColor(Color.parseColor("#76FF03")); holder.tvDate.setTextSize(35); } else { holder.tvDate.setTextColor(Color.WHITE); holder.tvDate.setTextSize(18); } } else { holder.tvDate.setVisibility(View.INVISIBLE); } } public void setSelecteditem(int selecteditem) { this.selectedItem = selecteditem; notifyDataSetChanged(); } @Override public int getItemCount() { return dateDataList.size(); } @Override public int getItemViewType(int position) { LabelerDate labelerDate = dateDataList.get(position); if (labelerDate.getType() == VIEW_TYPE_PADDING) { return VIEW_TYPE_PADDING; } else { return VIEW_TYPE_ITEM; } } public class DateViewHolder extends RecyclerView.ViewHolder { public TextView tvDate; public DateViewHolder(View itemView) { super(itemView); tvDate = (TextView) itemView.findViewById(R.id.txt_date); } } } private class LabelerDate { private int type; private String number; public String getNumber() { return number; } public void setNumber(String number) { this.number = number; } public int getType() { return type; } public void setType(int type) { this.type = type; } } }
activity_main.xml中
item.xml
dimens.xml
100dp
我在这里使用了SnapHelper:
// init snaphelper SnapHelper snapHelper = new LinearSnapHelper(); snapHelper.attachToRecyclerView(recyclerView) // init layout manager LinearLayoutManager layoutManager = new LinearLayoutManager(mainActivity); layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); recyclerView.setLayoutManager(layoutManager); // init adapter adatper.setSnapHelper(snapHelper); adatper.setLayoutManager(layoutManager); adatper.initAdapter(new Float((DisplayHelper.getDisplayWidth(mainActivity) / 2) - (fooViewWidth / 2)).intValue()); recyclerView.setAdapter(adatper);
正如TranHieu所说,插入2项用于填充(在开始和结束位置)的解决方案是好的.
我不喜欢使用ViewTreeObserver,因为代码的可读性差.使用此技术,您还必须管理重新绘制项目的重新绘制.
如果您使用的是customview类,则可以将其宽度直接设置为这些类.
例如,这是我的填充类
/** * Created by firegloves on 25/09/15. */ @EViewGroup(R.layout.view_padding) public class PaddingView extends FooView { Context mCtx; public PaddingView(Context context) { super(context); mCtx = context; } public void setWidth(int width) { setLayoutParams(new LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT)); } }
在我的适配器中,我存储了所需的填充项目宽度,等于(displayWidth/2) - (realItemWidth/2)
这是我的适配器,不要看不匹配RecyclerView.Adapter的方法,注意initAdapter方法和onCreateItemView方法
@EBean public class FooAdapterRecycler extends RecyclerViewAdapterBase{ private final int TYPE_PADDING_VIEW = 0; private final int TYPE_REAL_VIEW = 1; @RootContext Context ctx; @Bean(Finder.class) IFinder finder; SnapHelper snapHelper; RecyclerView.LayoutManager layoutManager; private int paddingWidth = 0; /** * preleva i dati dal finder */ public void initAdapter(int paddingWidth) { /******************************* * THIS CODE IS THE IMPORTANT ONE ******************************/ this.paddingWidth = paddingWidth; // add 1 item for initial space mItems = new ArrayList<>(); Foo foo = new Foo(); mItems.add(foo); // get real items from finder mItems.addAll(finder.findAll()); // add 1 item for final space mItems = new ArrayList<>(); Foo foo2 = new Foo(); mItems.add(foo2); } @Override public int getItemViewType(int position) { if (position == 0 || position == getItemCount()-1) { return TYPE_PADDING_VIEW; } else { return TYPE_REAL_VIEW; } } @Override protected FooView onCreateItemView(ViewGroup parent, int viewType) { /******************************* * THIS CODE IS THE IMPORTANT ONE ******************************/ if (viewType == TYPE_PADDING_VIEW) { PaddingView view = PaddingView_.build(ctx); view.setWidth(paddingWidth); return view; } else { return FooView_.build(ctx); } } public void setSnapHelper(SnapHelper snapHelper) { this.snapHelper = snapHelper; } public void setLayoutManager(RecyclerView.LayoutManager layoutManager) { this.layoutManager = layoutManager; } }
我正在使用AndroidAnnotations库,但这不是必需的
希望有所帮助