美文网首页Android基础知识AndroidAndroid开发感悟
羊皮书APP(Android版)开发系列(二十一)双联动分组Li

羊皮书APP(Android版)开发系列(二十一)双联动分组Li

作者: JeenWang | 来源:发表于2016-04-15 09:16 被阅读3250次

    双联动ListView在很多APP中都有应用,美团外卖、糯米外卖、京东分类等都有使用。

    效果图如下:

    pic1.jpeg pic2.jpeg

    双ListView分为左侧ListView和右侧ListView,通过左侧ListView的点击来定位右侧ListView的位置,通过右侧ListView的滑动来定位左侧ListView的选中位置。左侧ListView我们直接使用原生ListView即可,右侧ListView由于需要头部标题和滑动监听,我们自己定义一个ListView,来设置下滑动事件的监听和头部标题。

    实现双ListView联动最关键的一点就是这个自定义ListView,代码如下:

    package cn.studyou.doublelistviewlinkage.View;
    
    import android.content.Context;
    import android.graphics.Canvas;
    import android.util.AttributeSet;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.AbsListView;
    import android.widget.AbsListView.OnScrollListener;
    import android.widget.AdapterView;
    import android.widget.HeaderViewListAdapter;
    import android.widget.ListAdapter;
    import android.widget.ListView;
    
    import cn.studyou.doublelistviewlinkage.Adapter.SectionedBaseAdapter;
    
    public class PinnedHeaderListView extends ListView implements OnScrollListener {
    
        private OnScrollListener mOnScrollListener;
    
        public static interface PinnedSectionedHeaderAdapter {
            public boolean isSectionHeader(int position);
    
            public int getSectionForPosition(int position);
    
            public View getSectionHeaderView(int section, View convertView, ViewGroup parent);
    
            public int getSectionHeaderViewType(int section);
    
            public int getCount();
    
        }
    
        private PinnedSectionedHeaderAdapter mAdapter;
        private View mCurrentHeader;
        private int mCurrentHeaderViewType = 0;
        private float mHeaderOffset;
        private boolean mShouldPin = true;
        private int mCurrentSection = 0;
        private int mWidthMode;
        private int mHeightMode;
    
        public PinnedHeaderListView(Context context) {
            super(context);
            super.setOnScrollListener(this);
        }
    
        public PinnedHeaderListView(Context context, AttributeSet attrs) {
            super(context, attrs);
            super.setOnScrollListener(this);
        }
    
        public PinnedHeaderListView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            super.setOnScrollListener(this);
        }
    
        public void setPinHeaders(boolean shouldPin) {
            mShouldPin = shouldPin;
        }
    
        @Override
        public void setAdapter(ListAdapter adapter) {
            mCurrentHeader = null;
            mAdapter = (PinnedSectionedHeaderAdapter) adapter;
            super.setAdapter(adapter);
        }
    
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            if (mOnScrollListener != null) {
                mOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
            }
    
            if (mAdapter == null || mAdapter.getCount() == 0 || !mShouldPin || (firstVisibleItem < getHeaderViewsCount())) {
                mCurrentHeader = null;
                mHeaderOffset = 0.0f;
                for (int i = firstVisibleItem; i < firstVisibleItem + visibleItemCount; i++) {
                    View header = getChildAt(i);
                    if (header != null) {
                        header.setVisibility(VISIBLE);
                    }
                }
                return;
            }
    
            firstVisibleItem -= getHeaderViewsCount();
    
            int section = mAdapter.getSectionForPosition(firstVisibleItem);
            int viewType = mAdapter.getSectionHeaderViewType(section);
            mCurrentHeader = getSectionHeaderView(section, mCurrentHeaderViewType != viewType ? null : mCurrentHeader);
            ensurePinnedHeaderLayout(mCurrentHeader);
            mCurrentHeaderViewType = viewType;
    
            mHeaderOffset = 0.0f;
    
            for (int i = firstVisibleItem; i < firstVisibleItem + visibleItemCount; i++) {
                if (mAdapter.isSectionHeader(i)) {
                    View header = getChildAt(i - firstVisibleItem);
                    float headerTop = header.getTop();
                    float pinnedHeaderHeight = mCurrentHeader.getMeasuredHeight();
                    header.setVisibility(VISIBLE);
                    if (pinnedHeaderHeight >= headerTop && headerTop > 0) {
                        mHeaderOffset = headerTop - header.getHeight();
                    } else if (headerTop <= 0) {
                        header.setVisibility(INVISIBLE);
                    }
                }
            }
    
            invalidate();
        }
    
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            if (mOnScrollListener != null) {
                mOnScrollListener.onScrollStateChanged(view, scrollState);
            }
        }
    
        private View getSectionHeaderView(int section, View oldView) {
            boolean shouldLayout = section != mCurrentSection || oldView == null;
    
            View view = mAdapter.getSectionHeaderView(section, oldView, this);
            if (shouldLayout) {
                // a new section, thus a new header. We should lay it out again
                ensurePinnedHeaderLayout(view);
                mCurrentSection = section;
            }
            return view;
        }
    
        private void ensurePinnedHeaderLayout(View header) {
            if (header.isLayoutRequested()) {
                int widthSpec = MeasureSpec.makeMeasureSpec(getMeasuredWidth(), mWidthMode);
    
                int heightSpec;
                ViewGroup.LayoutParams layoutParams = header.getLayoutParams();
                if (layoutParams != null && layoutParams.height > 0) {
                    heightSpec = MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY);
                } else {
                    heightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
                }
                header.measure(widthSpec, heightSpec);
                header.layout(0, 0, header.getMeasuredWidth(), header.getMeasuredHeight());
            }
        }
    
        @Override
        protected void dispatchDraw(Canvas canvas) {
            super.dispatchDraw(canvas);
            if (mAdapter == null || !mShouldPin || mCurrentHeader == null)
                return;
            int saveCount = canvas.save();
            canvas.translate(0, mHeaderOffset);
            canvas.clipRect(0, 0, getWidth(), mCurrentHeader.getMeasuredHeight()); // needed
            mCurrentHeader.draw(canvas);
            canvas.restoreToCount(saveCount);
        }
    
        @Override
        public void setOnScrollListener(OnScrollListener l) {
            mOnScrollListener = l;
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    
            mWidthMode = MeasureSpec.getMode(widthMeasureSpec);
            mHeightMode = MeasureSpec.getMode(heightMeasureSpec);
        }
    
        public void setOnItemClickListener(OnItemClickListener listener) {
            super.setOnItemClickListener(listener);
        }
    
        public static abstract class OnItemClickListener implements AdapterView.OnItemClickListener {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int rawPosition, long id) {
                SectionedBaseAdapter adapter;
                if (adapterView.getAdapter().getClass().equals(HeaderViewListAdapter.class)) {
                    HeaderViewListAdapter wrapperAdapter = (HeaderViewListAdapter) adapterView.getAdapter();
                    adapter = (SectionedBaseAdapter) wrapperAdapter.getWrappedAdapter();
                } else {
                    adapter = (SectionedBaseAdapter) adapterView.getAdapter();
                }
                int section = adapter.getSectionForPosition(rawPosition);
                int position = adapter.getPositionInSectionForPosition(rawPosition);
    
                if (position == -1) {
                    onSectionClick(adapterView, view, section, id);
                } else {
                    onItemClick(adapterView, view, section, position, id);
                }
            }
    
            public abstract void onItemClick(AdapterView<?> adapterView, View view, int section, int position, long id);
    
            public abstract void onSectionClick(AdapterView<?> adapterView, View view, int section, long id);
    
        }
    }
    
    

    然后为PinnedHeaderListView定义Adapter,代码如下:

    package cn.studyou.doublelistviewlinkage.Adapter;
    
    import android.util.SparseArray;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    
    import cn.studyou.doublelistviewlinkage.View.PinnedHeaderListView;
    
    public abstract class SectionedBaseAdapter extends BaseAdapter implements PinnedHeaderListView.PinnedSectionedHeaderAdapter {
    
        private static int HEADER_VIEW_TYPE = 0;
        private static int ITEM_VIEW_TYPE = 0;
        private SparseArray<Integer> mSectionPositionCache;
        private SparseArray<Integer> mSectionCache;
        private SparseArray<Integer> mSectionCountCache;
        private int mCount;
        private int mSectionCount;
        public SectionedBaseAdapter() {
            super();
            mSectionCache = new SparseArray<Integer>();
            mSectionPositionCache = new SparseArray<Integer>();
            mSectionCountCache = new SparseArray<Integer>();
            mCount = -1;
            mSectionCount = -1;
        }
    
        @Override
        public void notifyDataSetChanged() {
            mSectionCache.clear();
            mSectionPositionCache.clear();
            mSectionCountCache.clear();
            mCount = -1;
            mSectionCount = -1;
            super.notifyDataSetChanged();
        }
    
        @Override
        public void notifyDataSetInvalidated() {
            mSectionCache.clear();
            mSectionPositionCache.clear();
            mSectionCountCache.clear();
            mCount = -1;
            mSectionCount = -1;
            super.notifyDataSetInvalidated();
        }
    
        @Override
        public final int getCount() {
            if (mCount >= 0) {
                return mCount;
            }
            int count = 0;
            for (int i = 0; i < internalGetSectionCount(); i++) {
                count += internalGetCountForSection(i);
                count++; // for the header view
            }
            mCount = count;
            return count;
        }
    
        @Override
        public final Object getItem(int position) {
            return getItem(getSectionForPosition(position), getPositionInSectionForPosition(position));
        }
    
        @Override
        public final long getItemId(int position) {
            return getItemId(getSectionForPosition(position), getPositionInSectionForPosition(position));
        }
    
        @Override
        public final View getView(int position, View convertView, ViewGroup parent) {
            if (isSectionHeader(position)) {
                return getSectionHeaderView(getSectionForPosition(position), convertView, parent);
            }
            return getItemView(getSectionForPosition(position), getPositionInSectionForPosition(position), convertView, parent);
        }
    
        @Override
        public final int getItemViewType(int position) {
            if (isSectionHeader(position)) {
                return getItemViewTypeCount() + getSectionHeaderViewType(getSectionForPosition(position));
            }
            return getItemViewType(getSectionForPosition(position), getPositionInSectionForPosition(position));
        }
    
        @Override
        public final int getViewTypeCount() {
            return getItemViewTypeCount() + getSectionHeaderViewTypeCount();
        }
    
        public final int getSectionForPosition(int position) {
            // first try to retrieve values from cache
            Integer cachedSection = mSectionCache.get(position);
            if (cachedSection != null) {
                return cachedSection;
            }
            int sectionStart = 0;
            for (int i = 0; i < internalGetSectionCount(); i++) {
                int sectionCount = internalGetCountForSection(i);
                int sectionEnd = sectionStart + sectionCount + 1;
                if (position >= sectionStart && position < sectionEnd) {
                    mSectionCache.put(position, i);
                    return i;
                }
                sectionStart = sectionEnd;
            }
            return 0;
        }
    
        public int getPositionInSectionForPosition(int position) {
            // first try to retrieve values from cache
            Integer cachedPosition = mSectionPositionCache.get(position);
            if (cachedPosition != null) {
                return cachedPosition;
            }
            int sectionStart = 0;
            for (int i = 0; i < internalGetSectionCount(); i++) {
                int sectionCount = internalGetCountForSection(i);
                int sectionEnd = sectionStart + sectionCount + 1;
                if (position >= sectionStart && position < sectionEnd) {
                    int positionInSection = position - sectionStart - 1;
                    mSectionPositionCache.put(position, positionInSection);
                    return positionInSection;
                }
                sectionStart = sectionEnd;
            }
            return 0;
        }
    
        public final boolean isSectionHeader(int position) {
            int sectionStart = 0;
            for (int i = 0; i < internalGetSectionCount(); i++) {
                if (position == sectionStart) {
                    return true;
                } else if (position < sectionStart) {
                    return false;
                }
                sectionStart += internalGetCountForSection(i) + 1;
            }
            return false;
        }
    
        public int getItemViewType(int section, int position) {
            return ITEM_VIEW_TYPE;
        }
    
        public int getItemViewTypeCount() {
            return 1;
        }
    
        public int getSectionHeaderViewType(int section) {
            return HEADER_VIEW_TYPE;
        }
    
        public int getSectionHeaderViewTypeCount() {
            return 1;
        }
    
        public abstract Object getItem(int section, int position);
    
        public abstract long getItemId(int section, int position);
    
        public abstract int getSectionCount();
    
        public abstract int getCountForSection(int section);
    
        public abstract View getItemView(int section, int position, View convertView, ViewGroup parent);
    
        public abstract View getSectionHeaderView(int section, View convertView, ViewGroup parent);
    
        private int internalGetCountForSection(int section) {
            Integer cachedSectionCount = mSectionCountCache.get(section);
            if (cachedSectionCount != null) {
                return cachedSectionCount;
            }
            int sectionCount = getCountForSection(section);
            mSectionCountCache.put(section, sectionCount);
            return sectionCount;
        }
    
        private int internalGetSectionCount() {
            if (mSectionCount >= 0) {
                return mSectionCount;
            }
            mSectionCount = getSectionCount();
            return mSectionCount;
        }
    
    }
    
    

    这样我们就可以使用PinnedHeaderListView了,新建MainActivity,在布局文件中创建两个ListView。

    package cn.studyou.doublelistviewlinkage.Activity;
    
    import android.os.Bundle;
    import android.support.v7.app.AppCompatActivity;
    import android.view.View;
    import android.widget.AbsListView;
    import android.widget.AdapterView;
    import android.widget.ListView;
    
    import butterknife.Bind;
    import butterknife.ButterKnife;
    import cn.studyou.doublelistviewlinkage.Adapter.LeftListAdapter;
    import cn.studyou.doublelistviewlinkage.Adapter.MainSectionedAdapter;
    import cn.studyou.doublelistviewlinkage.R;
    import cn.studyou.doublelistviewlinkage.View.PinnedHeaderListView;
    
    public class MainActivity extends AppCompatActivity {
    
        @Bind(R.id.left_listview)
        ListView leftListview;
        @Bind(R.id.pinnedListView)
        PinnedHeaderListView pinnedListView;
        private boolean isScroll = true;
        private LeftListAdapter adapter;
    
        private String[] leftStr = new String[]{"面食类", "盖饭", "寿司", "烧烤", "酒水", "凉菜", "小吃", "粥", "休闲"};
        private boolean[] flagArray = {true, false, false, false, false, false, false, false, false};
        private String[][] rightStr = new String[][]{{"热干面", "臊子面", "烩面"},
                {"番茄鸡蛋", "红烧排骨", "农家小炒肉"},
                {"芝士", "丑小丫", "金枪鱼"}, {"羊肉串", "烤鸡翅", "烤羊排"}, {"长城干红", "燕京鲜啤", "青岛鲜啤"},
                {"拌粉丝", "大拌菜", "菠菜花生"}, {"小食组", "紫薯"},
                {"小米粥", "大米粥", "南瓜粥", "玉米粥", "紫米粥"}, {"儿童小汽车", "悠悠球", "熊大", " 熊二", "光头强"}
        };
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            ButterKnife.bind(this);
            pinnedListView = (PinnedHeaderListView) findViewById(R.id.pinnedListView);
            final MainSectionedAdapter sectionedAdapter = new MainSectionedAdapter(this, leftStr, rightStr);
            pinnedListView.setAdapter(sectionedAdapter);
            adapter = new LeftListAdapter(this, leftStr, flagArray);
            leftListview.setAdapter(adapter);
            leftListview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    
                @Override
                public void onItemClick(AdapterView<?> arg0, View view, int position, long arg3) {
                    isScroll = false;
    
                    for (int i = 0; i < leftStr.length; i++) {
                        if (i == position) {
                            flagArray[i] = true;
                        } else {
                            flagArray[i] = false;
                        }
                    }
                    adapter.notifyDataSetChanged();
                    int rightSection = 0;
                    for (int i = 0; i < position; i++) {
                        rightSection += sectionedAdapter.getCountForSection(i) + 1;
                    }
                    pinnedListView.setSelection(rightSection);
    
                }
    
            });
    
            pinnedListView.setOnScrollListener(new AbsListView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(AbsListView arg0, int scrollState) {
                    switch (scrollState) {
                        // 当不滚动时
                        case AbsListView.OnScrollListener.SCROLL_STATE_IDLE:
                            // 判断滚动到底部
                            if (pinnedListView.getLastVisiblePosition() == (pinnedListView.getCount() - 1)) {
                                leftListview.setSelection(ListView.FOCUS_DOWN);
                            }
    
                            // 判断滚动到顶部
                            if (pinnedListView.getFirstVisiblePosition() == 0) {
                                leftListview.setSelection(0);
                            }
    
                            break;
                    }
                }
    
                int y = 0;
                int x = 0;
                int z = 0;
    
                @Override
                public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                    if (isScroll) {
                        for (int i = 0; i < rightStr.length; i++) {
                            if (i == sectionedAdapter.getSectionForPosition(pinnedListView.getFirstVisiblePosition())) {
                                flagArray[i] = true;
                                x = i;
                            } else {
                                flagArray[i] = false;
                            }
                        }
                        if (x != y) {
                            adapter.notifyDataSetChanged();
                            y = x;
                            //左侧ListView滚动到最后位置
                            if (y == leftListview.getLastVisiblePosition()) {
                                leftListview.setSelection(z);
                            }
                            //左侧ListView滚动到第一个位置
                            if (x == leftListview.getFirstVisiblePosition()) {
                                leftListview.setSelection(z);
                            }
                            if (firstVisibleItem + visibleItemCount == totalItemCount - 1) {
                                leftListview.setSelection(ListView.FOCUS_DOWN);
                            }
                        }
                    } else {
                        isScroll = true;
                    }
                }
            });
    
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            ButterKnife.unbind(this);
        }
    }
    
    

    MainActivity的布局文件如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/white"
        android:orientation="horizontal">
    
        <ListView
            android:id="@+id/left_listview"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="2"
            android:scrollbars="none"
            android:divider="@null"></ListView>
    
        <cn.studyou.doublelistviewlinkage.View.PinnedHeaderListView
            android:id="@+id/pinnedListView"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_marginLeft="@dimen/dp10"
            android:layout_weight="5"
            android:background="@android:color/white"></cn.studyou.doublelistviewlinkage.View.PinnedHeaderListView>
    
    </LinearLayout>
    
    

    分别为左侧ListView和右侧ListView创建Adapter。

    package cn.studyou.doublelistviewlinkage.Adapter;
    
    import android.content.Context;
    import android.graphics.Color;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import android.widget.TextView;
    
    import cn.studyou.doublelistviewlinkage.R;
    
    /**
    * 基本功能:左侧Adapter
    * 创建:王杰
    * 创建时间:16/4/14
    * 邮箱:w489657152@gmail.com
    */
    public class LeftListAdapter extends BaseAdapter {
       private String[] leftStr;
       boolean[] flagArray;
       private Context context;
    
       public LeftListAdapter(Context context, String[] leftStr, boolean[] flagArray) {
           this.leftStr = leftStr;
           this.context = context;
           this.flagArray = flagArray;
       }
    
       @Override
       public int getCount() {
           return leftStr.length;
       }
    
       @Override
       public Object getItem(int arg0) {
           return leftStr[arg0];
       }
    
       @Override
       public long getItemId(int arg0) {
           return arg0;
       }
    
       @Override
       public View getView(int arg0, View arg1, ViewGroup arg2) {
           Holder holder = null;
           if (arg1 == null) {
               holder = new Holder();
               arg1 = LayoutInflater.from(context).inflate(R.layout.left_list_item, null);
               holder.left_list_item = (TextView) arg1.findViewById(R.id.left_list_item);
               arg1.setTag(holder);
           } else {
               holder = (Holder) arg1.getTag();
           }
           holder.updataView(arg0);
           return arg1;
       }
    
       private class Holder {
           private TextView left_list_item;
    
           public void updataView(final int position) {
               left_list_item.setText(leftStr[position]);
               if (flagArray[position]) {
                   left_list_item.setBackgroundColor(Color.rgb(255, 255, 255));
               } else {
                   left_list_item.setBackgroundColor(Color.TRANSPARENT);
               }
           }
    
       }
    }
    
    
    package cn.studyou.doublelistviewlinkage.Adapter;
    
    import android.content.Context;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.view.ViewGroup;
    import android.widget.LinearLayout;
    import android.widget.RelativeLayout;
    import android.widget.TextView;
    import android.widget.Toast;
    
    import cn.studyou.doublelistviewlinkage.R;
    /**
    * 基本功能:右侧Adapter
    * 创建:王杰
    * 创建时间:16/4/14
    * 邮箱:w489657152@gmail.com
    */
    public class MainSectionedAdapter extends SectionedBaseAdapter {
    
       private Context mContext;
       private String[] leftStr;
       private String[][] rightStr;
    
       public MainSectionedAdapter(Context context, String[] leftStr, String[][] rightStr) {
           this.mContext = context;
           this.leftStr = leftStr;
           this.rightStr = rightStr;
       }
    
       @Override
       public Object getItem(int section, int position) {
           return rightStr[section][position];
       }
    
       @Override
       public long getItemId(int section, int position) {
           return position;
       }
    
       @Override
       public int getSectionCount() {
           return leftStr.length;
       }
    
       @Override
       public int getCountForSection(int section) {
           return rightStr[section].length;
       }
    
       @Override
       public View getItemView(final int section, final int position, View convertView, ViewGroup parent) {
           RelativeLayout layout = null;
           if (convertView == null) {
               LayoutInflater inflator = (LayoutInflater) parent.getContext()
                       .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
               layout = (RelativeLayout) inflator.inflate(R.layout.right_list_item, null);
           } else {
               layout = (RelativeLayout) convertView;
           }
           ((TextView) layout.findViewById(R.id.textItem)).setText(rightStr[section][position]);
           layout.setOnClickListener(new OnClickListener() {
               @Override
               public void onClick(View arg0) {
                   Toast.makeText(mContext, rightStr[section][position], Toast.LENGTH_SHORT).show();
               }
           });
           return layout;
       }
    
       @Override
       public View getSectionHeaderView(int section, View convertView, ViewGroup parent) {
           LinearLayout layout = null;
           if (convertView == null) {
               LayoutInflater inflator = (LayoutInflater) parent.getContext()
                       .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
               layout = (LinearLayout) inflator.inflate(R.layout.header_item, null);
           } else {
               layout = (LinearLayout) convertView;
           }
           layout.setClickable(false);
           ((TextView) layout.findViewById(R.id.textItem)).setText(leftStr[section]);
           return layout;
       }
    
    }
    
    

    三个ListView用到的Item。

    header_item.xml

    <?xml version="1.0" encoding="utf-8"?>
    
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@color/gray_light"
        android:orientation="horizontal">
    
        <TextView
            android:id="@+id/textItem"
            android:layout_marginLeft="@dimen/dp10"
            android:layout_width="wrap_content"
            android:layout_height="@dimen/dp30"
            android:layout_gravity="center_vertical"
            android:gravity="center_vertical"
            android:paddingLeft="@dimen/dp6"
            android:textColor="@color/black" />
    </LinearLayout>
    

    left_list_item.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
     android:background="@color/gray_light"
        android:orientation="vertical" >
        
     <TextView 
         android:id="@+id/left_list_item"
         android:layout_width="match_parent"
         android:layout_height="@dimen/dp60"
         android:padding="@dimen/dp12"
      android:gravity="center_vertical"
      android:textColor="@color/black"/>
        
    </LinearLayout>
    
    

    right_list_item.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/white"
        android:padding="@dimen/dp6">
    
        <ImageView
            android:id="@+id/imageItem"
            android:layout_width="@dimen/dp50"
            android:layout_height="@dimen/dp50"
            android:scaleType="fitXY"
            android:src="@drawable/pic"/>
    
        <TextView
            android:id="@+id/textItem"
            android:layout_width="wrap_content"
            android:layout_height="@dimen/dp50"
            android:gravity="center_vertical"
            android:paddingLeft="@dimen/dp6"
            android:layout_toRightOf="@+id/imageItem"
            android:textColor="@color/black" />
    </RelativeLayout>
    

    ok,到这里就完成了双ListView联动的实现,可以到这里下载运行体验https://github.com/wjie2014/DoubleListViewLinkage

    相关文章

      网友评论

      • 飞的鱼33:你好,当左边的数量大于10个的时候,右边的列表滑动到左边的第10个外的时候,左边的列表不会跟着滑动哦,可以处理下嘛
        JeenWang:@飞的鱼33 这种方式觉得技术有点low,你看看这个http://www.jianshu.com/p/5864db231ed5, RecyclerView 的。
        飞的鱼33:是右边的数据从上往下滑的时候,如果超出了目前可见的区域,左边的菜单不会滑动,当从下往上的时候又是可以的哦~~~
      • 向日葵lll:有bug 滑动到休闲那里 左边不切换。而且右边滑不到顶部
        JeenWang:@琳琳不开心 看下 RecyclerView 的吧,http://www.jianshu.com/p/5864db231ed5
        JeenWang:@微微心凉L 是的,list view处理的问题。你看下这篇文章,现在新的项目基本上都采用RecyclerView,http://www.jianshu.com/p/5864db231ed5
        微微心凉L:你说到休闲 左边不变换是因为 右边数据少了- - , 多一些就没问题了- -, 右边并没有发现什么滑不到顶部
      • aaa5c0cc24e8:问下以上那些类都是自己在包里新建的.java文件吗?
        JeenWang: @一个想要搬砖的妹纸 在github 上,你下载看一下😀
      • Zack_zhou:支持!!!我也去撸一个出来

      本文标题:羊皮书APP(Android版)开发系列(二十一)双联动分组Li

      本文链接:https://www.haomeiwen.com/subject/dkcnlttx.html