动态设置交错网格视图的固定高度

我正在尝试使用带有StaggeredGridLayoutRecyclerView ,并通过测量视图并动态设置高度使其成为固定高度。 我正在覆盖onMeasure() ,但它似乎并不总是正确测量。 我说它大约50%的时间都有效。 其他50%的时间用于衡量它。 我认为这与文本包装在view_tile_small.xml ,但我不确定。

分段

 public class AtTheMuseumFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener{ //Odds n Ends Variables private MapFragment mapFragment; private FragmentTransaction fragmentTransaction; private User user = new User(); private MuseumCollection museumCollection; private Context context; //Story Grid Adapter Variables private AtTheMuseumAdapter nearMeAdapter; private TileFactory tileFactory; //Interfaces private OnFragmentChangeListener changeListener; @Bind(R.id.stories_list_view) RecyclerView storiesListView; @Bind(R.id.swipe_container) SwipeRefreshLayout swipeRefreshLayout; public static AtTheMuseumFragment newInstance(MuseumCollection museumCollection) { AtTheMuseumFragment fragment = new AtTheMuseumFragment(); Bundle args = new Bundle(); fragment.setArguments(args); return fragment; } public AtTheMuseumFragment() { // Required empty public constructor } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); museumCollection = ((MainActivity) getActivity()).getMuseumCollection(); context = getActivity().getApplicationContext(); tileFactory = new TileFactory(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_museum, container, false); ButterKnife.bind(this, view); //Sets up the layoutManager to the Mason View storiesListView.setLayoutManager(new MeasuredStaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)); //Sets up The map try{ fragmentTransaction = getChildFragmentManager().beginTransaction(); mapFragment = MapFragment.newInstance(MapFragment.MUSEUM); fragmentTransaction.add(R.id.museum_map, mapFragment).commit(); }catch (Exception e){ Log.d("Map - Initial Inflate:", e.getMessage()); } //Sets up the swipe to refresh jawn swipeRefreshLayout.setOnRefreshListener(this); setNearMeAdapter(); return view; } @Override public void onResume(){ super.onResume(); } @Override public void onAttach(Activity activity) { super.onAttach(activity); try { changeListener = (OnFragmentChangeListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnFragmentInteractionListener"); } } @Override public void onDetach() { super.onDetach(); changeListener = null; } /** * Loads the adapter once the data is ready * */ public void setNearMeAdapter(){ List newList = museumCollection.getObjectsNearUser(User.position, 4); List tiles = tileFactory.createAtMuseumFeed(newList, true); nearMeAdapter = new AtTheMuseumAdapter(context, tiles, getActivity()); storiesListView.setAdapter(nearMeAdapter); } /** * Refreshes Adapter with new data * */ public void refreshNearMeAdapter(){ //TODO CHANGE THIS TO LOCATION BASED WHEN TIME IS RIGHT - Peter //nearMeAdapter.setNewData(MuseumCollection.getObjectsNearUser(User.position, 4)); List newList = museumCollection.getRandomOrder(); nearMeAdapter.setNewData(tileFactory.createAtMuseumFeed(newList,false)); } /** * Adds past data to the Adapter * */ public void loadPastObjects(){ //TODO MAKE THIS NOT ONLY LOAD RANDOM DATA - Peter List newList = museumCollection.getRandomOrder(); nearMeAdapter.addNewData(tileFactory.createAtMuseumFeed(newList, false)); nearMeAdapter.notifyDataSetChanged(); } @Override public void onRefresh() { user.updateUserLocation(); refreshNearMeAdapter(); mapFragment.refreshMap(museumCollection.getObjectFeed()); swipeRefreshLayout.setRefreshing(false); } public interface OnFragmentChangeListener { void onFragmentChange(String fragment); } @OnClick(R.id.explore_map) public void exploreMap(){ changeListener.onFragmentChange("map"); } @OnClick(R.id.load_more) public void loadMore(){ loadPastObjects(); } } 

MeasuredStaggeredGridLayoutManager

 public class MeasuredStaggeredGridLayoutManager extends StaggeredGridLayoutManager { public MeasuredStaggeredGridLayoutManager(int spanCount, int orientation) { super(spanCount, orientation); } private int[] mMeasuredDimension = new int[2]; @Override public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) { final int widthMode = View.MeasureSpec.getMode(widthSpec); final int heightMode = View.MeasureSpec.getMode(heightSpec); final int widthSize = View.MeasureSpec.getSize(widthSpec); final int heightSize = View.MeasureSpec.getSize(heightSpec); int width = 0; int height = 0; int heightR = 0; int heightL = 0; for (int i = 0; i  heightR) ? heightL : heightR; } //TODO come up with a better way to fix the slightly wrong height // must be not accounting for padding or margin or something - Peter height += (20 * (getItemCount() / 2)) + 5; setMeasuredDimension(width, height); } private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec, int heightSpec, int[] measuredDimension) { View view = recycler.getViewForPosition(position); if (view != null) { RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams(); int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, getPaddingLeft() + getPaddingRight(), p.width); int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, getPaddingTop() + getPaddingBottom(), p.height); view.measure(childWidthSpec, childHeightSpec); measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin; measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin; recycler.recycleView(view); } } } 

AtTheMuseumAdapter

 public class AtTheMuseumAdapter extends RecyclerView.Adapter { private List tiles; private LayoutInflater inflater; private AdapterCallback mListener; private Context context; public AtTheMuseumAdapter(Context context, List tiles, Activity activity) { this.tiles = tiles; this.context = context; inflater = LayoutInflater.from(this.context); //Sets up interface between Stock Adapter and Fragment try { this.mListener = ((AdapterCallback) activity); } catch (ClassCastException e) { throw new ClassCastException("Fragment must implement AdapterCallback."); } } @Override public MuseumStoriesViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { View view = inflater.inflate(R.layout.view_tile_small, viewGroup, false); MuseumStoriesViewHolder holder = new MuseumStoriesViewHolder(view); return holder; } @Override public void onBindViewHolder(MuseumStoriesViewHolder holder, int position) { Tile currentTile = tiles.get(position); holder.title.setText(currentTile.getTitle()); holder.desc.setText(currentTile.getDescription()); holder.type.setText(currentTile.getObjectTypeName()); //Using Picasso since it handles caching and all that jazz Picasso.with(context) .load(currentTile.getImg()) .into(holder.img); } @Override public int getItemCount() { return tiles.size(); } public void setNewData(List newItems){ tiles = newItems; notifyDataSetChanged(); } public void addNewData(final List newItems){ tiles.addAll(newItems); notifyDataSetChanged(); } class MuseumStoriesViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { public TextView type,title,desc; public ImageView img; public MuseumStoriesViewHolder(View itemView) { super(itemView); //Tried Butterknife, but it doesn't seem like it was working in the view holder. - Peter type = (TextView) itemView.findViewById(R.id.small_box_type); title = (TextView) itemView.findViewById(R.id.small_box_title); desc = (TextView) itemView.findViewById(R.id.small_box_desc); img = (ImageView) itemView.findViewById(R.id.small_box_image); itemView.setOnClickListener(this); } @Override public void onClick(View view) { Tile t = tiles.get(getPosition()); switch (t.getObjectTypeName()){ case Tile.OBJECT_NAME: mListener.onObjectClick(t.getObjectID()); break; case Tile.TOUR_NAME: mListener.onTourCLick(t.getTourID()); break; case Tile.STORY_NAME: mListener.onStoryClick(t.getObjectID(), t.getStoryID()); break; } } } public interface AdapterCallback { public void onObjectClick(String objectID); public void onStoryClick(String objectID, String storyID); public void onTourCLick(String tourID); } } 

view_tile_small.xml

            

fragment_museum

          

ViewTreeObserver代码我现在正在玩。 它在片段中。

  mTopStoriesListView.setLayoutManager(new NewMeasuredStaggeredLayoutManager(2, StaggeredGridLayoutManager.VERTICAL, mTopStoriesListView)); mTopStoriesListView.setNestedScrollingEnabled(false); //Testing Issue 54 final ViewTreeObserver viewTreeObserver = mTopStoriesListView.getViewTreeObserver(); if (viewTreeObserver.isAlive()) { viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { mTopStoriesListView.getViewTreeObserver().removeOnGlobalLayoutListener(this); int l = 0,r = 0; for(int i = 0 ; i  r) ? l : r; mTopStoriesListView.getLayoutParams().height = viewHeight; Log.d("TAG", String.valueOf(viewHeight)); } }); } //END TEST 

你看过ViewTreeObserver吗?

我在传递的项目上遇到了类似的问题,我发现它比onMesure更可靠,可以动态获取布局属性

你可以从这里查看: http : //developer.android.com/reference/android/view/ViewTreeObserver.html