在项目中根据原型图实现代码
思路:最外层是一个ScrollView 然后下面的细节是RecyclerView的二级嵌套
布局文件
最外层
<Scrollview android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/rl_title" android:layout_marginBottom="52dp" android:layout_marginTop="5dp" android:scrollbars="none" android:fillViewport="true"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginTop="10dp" android:text="面料选择" android:textColor="#000000" android:textSize="12sp" /> <LinearLayout android:id="@+id/ll_mianliao" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="10dp" android:background="@drawable/squre_hui" android:orientation="vertical" android:padding="5dp"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <ImageView android:id="@+id/iv_mianliao" android:layout_width="150dp" android:layout_height="60dp" /> <LinearLayout android:id="@+id/ll_detail" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_weight="1" android:gravity="center_vertical" android:orientation="vertical"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginTop="5dp" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="编号: " android:textSize="10sp" /> <TextView android:id="@+id/tv_identifier" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="10sp" /> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginTop="5dp" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="颜色: " android:textSize="10sp" /> <TextView android:id="@+id/tv_color" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="10sp" /> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginTop="5dp" android:orientation="horizontal"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="成分: " android:textSize="10sp" /> <TextView android:id="@+id/tv_component" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="10sp" /> </LinearLayout> </LinearLayout> <TextView android:id="@+id/tv_null" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:layout_marginLeft="10dp" android:text="没有默认面料,请选择" android:textSize="12sp" android:visibility="gone" /> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:padding="10dp" android:src="@drawable/ic_more" /> </LinearLayout> </LinearLayout> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="#ededed" /> <android.support.v7.widget.RecyclerView android:id="@+id/rv_style" android:layout_width="match_parent" android:layout_height="match_parent"> </android.support.v7.widget.RecyclerView> </LinearLayout> </Scrollview>
大RecyclerView的item布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#ffffff" android:orientation="vertical"> <TextView android:id="@+id/tv_style_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginTop="5dp" android:textColor="#000000" android:textSize="12sp"/> <android.support.v7.widget.RecyclerView android:id="@+id/rv_style_item" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="5dp"> </android.support.v7.widget.RecyclerView> </LinearLayout>
小recyclerview item的布局
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" android:gravity="center" android:orientation="vertical"> <LinearLayout android:id="@+id/ll_bg" android:layout_width="70dp" android:layout_height="70dp" android:padding="2dp" android:descendantFocusability="blocksDescendants" android:orientation="horizontal"> <ImageView android:id="@+id/iv_style" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout> <TextView android:id="@+id/tv_name" android:layout_width="70dp" android:layout_height="wrap_content" android:layout_gravity="center" android:gravity="center" android:paddingBottom="10dp" android:singleLine="true" android:textSize="10sp" /> </LinearLayout>
最初的时候,发现外层RecyclerView显示不全,后面百度,大家说需要重新计算item的高度,试了好几种方法,还是不行,后面翻看一篇国外大神的文章发现了不通,结果也算顺利解决
下面给出代码:MyLinearLayoutManager
public class MyLinearLayoutManager extends LinearLayoutManager { private static boolean canMakeInsetsDirty = true; private static Field insetsDirtyField = null; private static final int CHILD_WIDTH = 0; private static final int CHILD_HEIGHT = 1; private static final int DEFAULT_CHILD_SIZE = 100; private final int[] childDimensions = new int[2]; private final RecyclerView view; private int childSize = DEFAULT_CHILD_SIZE; private boolean hasChildSize; private int overScrollMode = ViewCompat.OVER_SCROLL_ALWAYS; private final Rect tmpRect = new Rect(); public MyLinearLayoutManager(Context context) { super(context); this.view = null; } public MyLinearLayoutManager(Context context, int orientation, boolean reverseLayout) { super(context, orientation, reverseLayout); this.view = null; } public MyLinearLayoutManager(RecyclerView view) { super(view.getContext()); this.view = view; this.overScrollMode = ViewCompat.getOverScrollMode(view); } public MyLinearLayoutManager(RecyclerView view, int orientation, boolean reverseLayout) { super(view.getContext(), orientation, reverseLayout); this.view = view; this.overScrollMode = ViewCompat.getOverScrollMode(view); } public void setOverScrollMode(int overScrollMode) { if (overScrollMode < ViewCompat.OVER_SCROLL_ALWAYS || overScrollMode > ViewCompat.OVER_SCROLL_NEVER) throw new IllegalArgumentException("Unknown overscroll mode: " + overScrollMode); if (this.view == null) throw new IllegalStateException("view == null"); this.overScrollMode = overScrollMode; ViewCompat.setOverScrollMode(view, overScrollMode); } public static int makeUnspecifiedSpec() { return View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); } @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); final boolean hasWidthSize = widthMode != View.MeasureSpec.UNSPECIFIED; final boolean hasHeightSize = heightMode != View.MeasureSpec.UNSPECIFIED; final boolean exactWidth = widthMode == View.MeasureSpec.EXACTLY; final boolean exactHeight = heightMode == View.MeasureSpec.EXACTLY; final int unspecified = makeUnspecifiedSpec(); if (exactWidth && exactHeight) { // in case of exact calculations for both dimensions let's use default "onMeasure" implementation super.onMeasure(recycler, state, widthSpec, heightSpec); return; } final boolean vertical = getOrientation() == VERTICAL; initChildDimensions(widthSize, heightSize, vertical); int width = 0; int height = 0; // it's possible to get scrap views in recycler which are bound to old (invalid) adapter entities. This // happens because their invalidation happens after "onMeasure" method. As a workaround let's clear the // recycler now (it should not cause any performance issues while scrolling as "onMeasure" is never // called whiles scrolling) recycler.clear(); final int stateItemCount = state.getItemCount(); final int adapterItemCount = getItemCount(); // adapter always contains actual data while state might contain old data (f.e. data before the animation is // done). As we want to measure the view with actual data we must use data from the adapter and not from the // state for (int i = 0; i < adapterItemCount; i++) { if (vertical) { if (!hasChildSize) { if (i < stateItemCount) { // we should not exceed state count, otherwise we'll get IndexOutOfBoundsException. For such items // we will use previously calculated dimensions measureChild(recycler, i, widthSize, unspecified, childDimensions); } } height += childDimensions[CHILD_HEIGHT]; if (i == 0) { width = childDimensions[CHILD_WIDTH]; } if (hasHeightSize && height >= heightSize) { break; } } else { if (!hasChildSize) { if (i < stateItemCount) { // we should not exceed state count, otherwise we'll get IndexOutOfBoundsException. For such items // we will use previously calculated dimensions measureChild(recycler, i, unspecified, heightSize, childDimensions); } } width += childDimensions[CHILD_WIDTH]; if (i == 0) { height = childDimensions[CHILD_HEIGHT]; } if (hasWidthSize && width >= widthSize) { break; } } } if (exactWidth) { width = widthSize; } else { width += getPaddingLeft() + getPaddingRight(); if (hasWidthSize) { width = Math.min(width, widthSize); } } if (exactHeight) { height = heightSize; } else { height += getPaddingTop() + getPaddingBottom(); if (hasHeightSize) { height = Math.min(height, heightSize); } } setMeasuredDimension(width, height); if (view != null && overScrollMode == ViewCompat.OVER_SCROLL_IF_CONTENT_SCROLLS) { final boolean fit = (vertical && (!hasHeightSize || height < heightSize)) || (!vertical && (!hasWidthSize || width < widthSize)); ViewCompat.setOverScrollMode(view, fit ? ViewCompat.OVER_SCROLL_NEVER : ViewCompat.OVER_SCROLL_ALWAYS); } } @Override public void setOrientation(int orientation) { // might be called before the constructor of this class is called //noinspection ConstantConditions if (childDimensions != null) { if (getOrientation() != orientation) { childDimensions[CHILD_WIDTH] = 0; childDimensions[CHILD_HEIGHT] = 0; } } super.setOrientation(orientation); } private void initChildDimensions(int width, int height, boolean vertical) { if (childDimensions[CHILD_WIDTH] != 0 || childDimensions[CHILD_HEIGHT] != 0) { // already initialized, skipping return; } if (vertical) { childDimensions[CHILD_WIDTH] = width; childDimensions[CHILD_HEIGHT] = childSize; } else { childDimensions[CHILD_WIDTH] = childSize; childDimensions[CHILD_HEIGHT] = height; } } public void clearChildSize() { hasChildSize = false; setChildSize(DEFAULT_CHILD_SIZE); } public void setChildSize(int childSize) { hasChildSize = true; if (this.childSize != childSize) { this.childSize = childSize; requestLayout(); } } private void measureChild(RecyclerView.Recycler recycler, int position, int widthSize, int heightSize, int[] dimensions) { final View child; try { child = recycler.getViewForPosition(position); } catch (IndexOutOfBoundsException e) { return; } final RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) child.getLayoutParams(); final int hPadding = getPaddingLeft() + getPaddingRight(); final int vPadding = getPaddingTop() + getPaddingBottom(); final int hMargin = p.leftMargin + p.rightMargin; final int vMargin = p.topMargin + p.bottomMargin; // we must make insets dirty in order calculateItemDecorationsForChild to work makeInsetsDirty(p); // this method should be called before any getXxxDecorationXxx() methods calculateItemDecorationsForChild(child, tmpRect); final int hDecoration = getRightDecorationWidth(child) + getLeftDecorationWidth(child); final int vDecoration = getTopDecorationHeight(child) + getBottomDecorationHeight(child); final int childWidthSpec = getChildMeasureSpec(widthSize, hPadding + hMargin + hDecoration, p.width, canScrollHorizontally()); final int childHeightSpec = getChildMeasureSpec(heightSize, vPadding + vMargin + vDecoration, p.height, canScrollVertically()); child.measure(childWidthSpec, childHeightSpec); dimensions[CHILD_WIDTH] = getDecoratedMeasuredWidth(child) + p.leftMargin + p.rightMargin; dimensions[CHILD_HEIGHT] = getDecoratedMeasuredHeight(child) + p.bottomMargin + p.topMargin; // as view is recycled let's not keep old measured values makeInsetsDirty(p); recycler.recycleView(child); } private static void makeInsetsDirty(RecyclerView.LayoutParams p) { if (!canMakeInsetsDirty) { return; } try { if (insetsDirtyField == null) { insetsDirtyField = RecyclerView.LayoutParams.class.getDeclaredField("mInsetsDirty"); insetsDirtyField.setAccessible(true); } insetsDirtyField.set(p, true); } catch (NoSuchFieldException e) { onMakeInsertDirtyFailed(); } catch (IllegalAccessException e) { onMakeInsertDirtyFailed(); } } private static void onMakeInsertDirtyFailed() { canMakeInsetsDirty = false; } }
Activity 中代码就跟是常规使用recyclerview的方法
下面贴出第一个adapter中的代码 StyleAdapte
这里在onBindView中绑定数据,并设置第二个recyclerview的adapter
注意f粉色部分 后面出现了小recyclerview也显示不全 明明设置好了layoutManager还是显示不全,试了好几种都不行,后面将其改成红色部分就好了
原因我还不是太清楚 我想应该是数据源的地址相同引起的数据错乱 。
放在外面 即使在下方clear了 但是数据地址还是一样,所以引起了数据错乱
放在下面的话,就相当于 每一次绑定数据都是一个 新的数据
public class StyleAdapter extends RecyclerView.Adapter<StyleAdapter.MyViewHolder> { private List<AttributeClass> mAttributeClassDatas;
//List<Attribute> mAttributeDatas = new ArrayList<Attribute>();private LayoutInflater mInflater; private DetailTaoxiActivity mContext; public StyleAdapter(DetailTaoxiActivity context, List<AttributeClass> datas) { mInflater = LayoutInflater.from(context); mAttributeClassDatas = datas; mContext = context; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { MyViewHolder holder = new MyViewHolder(mInflater.inflate(R.layout.item_style, parent, false)); return holder; } @Override public void onBindViewHolder(MyViewHolder holder, int position) { holder.tv_style_name.setText(mAttributeClassDatas.get(position).name); JSONArray attributeList = mAttributeClassDatas.get(position).attributeList;
// mAttributeDatas.clear();
List<Attribute> mAttributeDatas = new ArrayList<Attribute>(); for (int i = 0; i < attributeList.length(); i++) { Attribute attribute = Attribute.createFromJson(attributeList.optJSONObject(i)); mAttributeDatas.add(attribute); } if (mAttributeDatas != null && mAttributeDatas.size() > 0) { ImageAdapter imageAdapter = new ImageAdapter(mContext, mAttributeDatas); FullyGridLayoutManager gm = new FullyGridLayoutManager(mContext, 4, FullyGridLayoutManager.VERTICAL, false); holder.rv_style_item.setLayoutManager(gm); holder.rv_style_item.setAdapter(imageAdapter); holder.rv_style_item.setVisibility(View.VISIBLE); } else { holder.rv_style_item.setVisibility(View.GONE); } } @Override public int getItemCount() { return mAttributeClassDatas.size(); } class MyViewHolder extends ViewHolder { TextView tv_style_name; RecyclerView rv_style_item; public MyViewHolder(View view) { super(view); tv_style_name = (TextView) view.findViewById(R.id.tv_style_name); rv_style_item = (RecyclerView) view.findViewById(R.id.rv_style_item); } }}
小Adapter也是很简单的 就跟平常用的recyclerview的adapter一样
public class ImageAdapter extends RecyclerView.Adapter<ImageAdapter.MyViewHolder>{ private List<Attribute> mDatas; private LayoutInflater mInflater; private DetailTaoxiActivity mContext; private ImageLoader imageLoader; private int layoutPosition; private List<String> idList=new ArrayList<String>(); public ImageAdapter(DetailTaoxiActivity context, List<Attribute> datas) { mInflater = LayoutInflater.from(context); mDatas = datas; mContext=context; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = mInflater.inflate(R.layout.item_style_item, parent, false); return new MyViewHolder(view); } @Override public void onBindViewHolder(final MyViewHolder holder, final int position) { holder.tv_name.setText(mDatas.get(position).name); imageLoader = new ImageLoader(mContext); imageLoader.DisplayImage(URL_P.ImageBasePath +mDatas.get(position).pic, holder.iv_style); mContext.setBackground(holder.ll_bg,position); holder.ll_bg.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) {
/*
实现item的单选
*/
//上一个选中的位置 int selPos=mContext.getmSelectedPos(); String oldId=mDatas.get(selPos).attributeValueId; //获取当前点击的位置 layoutPosition = holder.getLayoutPosition(); notifyDataSetChanged(); String newId=mDatas.get(layoutPosition).attributeValueId; mContext.updataBackground(oldId,newId); } }); //更改状态 if(position == layoutPosition){ holder.ll_bg.setBackgroundResource(R.drawable.squre_gray_black); }else{ holder.ll_bg.setBackgroundResource(R.drawable.squre_hui); } } @Override public int getItemCount() { return mDatas.size(); } class MyViewHolder extends RecyclerView.ViewHolder { LinearLayout ll_bg; TextView tv_name; ImageView iv_style; public MyViewHolder(View view) { super(view); ll_bg= (LinearLayout) view.findViewById(R.id.ll_bg); tv_name= (TextView) view.findViewById(R.id.tv_name); iv_style = (ImageView) view.findViewById(R.id.iv_style); } } }
将更改状态写到点击事件外面 因为里面执行了notify,执行完点击事件还会出来执行外面的代码
List<Attribute> mAttributeDatas = new ArrayList<Attribute>();