Android之两级联动点餐列表

android中实现双列表联动功能 实现的思路,就是左右一个列表,右边的列表里面嵌套一个列表,一共三个列表。就是一个数据展示的功能,左边是目录、右边是详情列表。第八步,在主Activity里面写具体的联动方法。第六步,写右边列表里面嵌套的详情列表适配器。第一步:先写一个主页面布局文件。第三步,写左边列表的布局文件。第五步:写右边列表的布局文件。第七步,写详情列表的布局文件。第二步:写一个左边适配器。第四步,写右边列表适配器。另外两个ben类代码如下。 阅读详情


前言

此功能为两个listview相互联动,左边listview点击右边联动,右边listview滑动联动左侧listview,仿饿了吗点餐列表


提示:以下是本篇文章正文内容,下面案例可供参考

一、效果图

在这里插入图片描述

二、实现步骤

1.相关layout

1:主界面layout,两个listview,右侧listview自定义的:

   <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/rela_button"
        android:layout_below="@+id/linear_top"
        android:layout_marginTop="10dp"
        android:layout_marginBottom="2dp"
        android:orientation="horizontal">

        <ListView
            android:id="@+id/left_listview"
            android:layout_width="84dp"
            android:layout_height="match_parent"
            android:background="#ffffff"
            android:divider="@null"
            android:scrollbars="none" />

        <com.example.mobilecashier.view.PinnedHeaderListView
            android:id="@+id/pinnedListView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginLeft="10dp"
            android:background="#ffffff"></com.example.mobilecashier.view.PinnedHeaderListView>
    </LinearLayout>

2.左侧listview的item布局

<?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="#EBEDF0"
    android:orientation="vertical" >
    
	<TextView 
	    android:id="@+id/left_list_item"
	    android:layout_width="match_parent"
	    android:layout_height="60dp"
	    android:padding="12dp"
		android:gravity="center_vertical"
		android:textColor="#444444"/>
    
</LinearLayout>

2.右侧侧listview的item布局

<?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="#ffffff"
    android:padding="6dp">

    <ImageView
        android:id="@+id/imageItem"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:scaleType="fitXY"
        android:src="@drawable/pic"/>

    <TextView
        android:id="@+id/textItem"
        android:layout_width="wrap_content"
        android:layout_height="50dp"
        android:gravity="center_vertical"
        android:paddingLeft="6dp"
        android:layout_toRightOf="@+id/imageItem"
        android:textColor="#444444" />
</RelativeLayout>

2.相关adapter

1:左侧adapter

package com.example.mobilecashier.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 com.example.mobilecashier.R;


/**
 * 左侧Adapter
 */
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);
            }
        }

    }
}

2:右侧adapter

package com.example.mobilecashier.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 com.example.mobilecashier.R;

/**
 * 基本功能:右侧Adapter
 */
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;
    }

}

3:继承adapter

package com.example.mobilecashier.adapter;


import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

import com.example.mobilecashier.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;

    /**
     * Holds the calculated values of @{link getPositionInSectionForPosition}
     */
    private SparseArray<Integer> mSectionPositionCache;
    /**
     * Holds the calculated values of @{link getSectionForPosition}
     */
    private SparseArray<Integer> mSectionCache;
    /**
     * Holds the calculated values of @{link getCountForSection}
     */
    private SparseArray<Integer> mSectionCountCache;

    /**
     * Caches the item count
     */
    private int mCount;
    /**
     * Caches the section count
     */
    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;
    }

}

3.自定义view

package com.example.mobilecashier.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 com.example.mobilecashier.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
        // for
        // <
        // HONEYCOMB
        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);

    }
}

4.activity实现

//全局变量
  private boolean isScroll = true;
    ListView left_listview;//左侧列表
    PinnedHeaderListView pinnedListView;//右侧列表
    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[][]{{"热干面", "臊子面", "烩面"},
            {"番茄鸡蛋", "红烧排骨", "农家小炒肉"},
            {"芝士", "丑小丫", "金枪鱼"}, {"羊肉串", "烤鸡翅", "烤羊排"}, {"长城干红", "燕京鲜啤", "青岛鲜啤"},
            {"拌粉丝", "大拌菜", "菠菜花生"}, {"小食组", "紫薯"},
            {"小米粥", "大米粥", "南瓜粥", "玉米粥", "紫米粥"}, {"儿童小汽车", "悠悠球", "熊大", " 熊二", "光头强"}
    };

  /**
     * 实例化
     */
    private void instantiation() {
        left_listview = findViewById(R.id.left_listview);
        pinnedListView = findViewById(R.id.pinnedListView);
        final MainSectionedAdapter sectionedAdapter = new MainSectionedAdapter(this, leftStr, rightStr);
        pinnedListView.setAdapter(sectionedAdapter);
        adapter = new LeftListAdapter(this, leftStr, flagArray);
        left_listview.setAdapter(adapter);
        left_listview.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)) {
                            left_listview.setSelection(ListView.FOCUS_DOWN);
                        }

                        // 判断滚动到顶部
                        if (pinnedListView.getFirstVisiblePosition() == 0) {
                            left_listview.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;
                        if (y == left_listview.getLastVisiblePosition()) {
//                            z = z + 3;
                            left_listview.setSelection(z);
                        }
                        if (x == left_listview.getFirstVisiblePosition()) {
//                            z = z - 1;
                            left_listview.setSelection(z);
                        }
                        if (firstVisibleItem + visibleItemCount == totalItemCount - 1) {
                            left_listview.setSelection(ListView.FOCUS_DOWN);
                        }
                    }
                } else {
                    isScroll = true;
                }
            }
        });
    }

补贴一个header_item的布局

<?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="#EBEDF0"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/textItem"
        android:layout_width="wrap_content"
        android:layout_height="30dp"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="10dp"
        android:gravity="center_vertical"
        android:paddingLeft="6dp"
        android:textColor="#444444" />
</LinearLayout>

总结

以上就是listview两级联动全部代码,如有指教私信我。

Android PopupWindow+RecyclerView 实现二级联动筛选 在popupWindow 布局里自定义了 MyScrollView,重写 onMeasure() 方法可以实现自定义测量规则。其中,使用 getMeasuredHeight() 方法和 getMeasuredWidth() 方法可以获取 ScrollView 的测量高度和测量宽度。通过 setMaxHeight 来设置 ScrollView 的最大高度@Override主要是读取本地数据添加到数组,以及popupWindow 的创建 跟点击交互。 阅读详情

相关推荐

使用 RecyclerView 做点餐列表联动页面

使用 RecyclerView 做点餐列表联动页面 版权声明:本文为博主原创文章,未经博主允许不得转载。 最近刚换了工作,来到一家做了11年餐饮软件管理的公司,开发平板端点餐安卓端原生app。因为之前一直没做过类似的软件,对于我来说是一个全新的开始,所以打算写博客记录下来我从头开发的整个过程。平板设置横屏属性就可以横屏在平板上显示,不用担心切换横竖屏会导致activity的生命周期改变。代码如下

假装成熟的冯先生的博客 4759

【Android】二级分类双列表联动Demo

二级分类双列表联动Demo

butterfly_new的博客 2542

仿饿了么美团点餐界面,listView的二级联动

项目需求,需要在项目里加入点餐的功能,自己简单写了一个, 先看图,界面丑勿喷: 只是做了简单的效果,实现点击左边右边改变,滑动右边左边改变,代码量很少,可以参考下 这是项目目录: 布局文件 左边listView 适配器 public class LeftAdapter extends BaseAdapter{ private List data

夏蝉冬雪 7111

qtabwidget怎么隐藏tab页_3分钟,写出“即刻App”最复杂的双列表页

码个蛋(codeegg)第 703 次推文作者:walkeer原文: https://juejin.im/post/5d4262ee6fb9a06afc2520a61. SlideLayout 双列表页面实现即刻 5.3 版本的时候,随着圈子详情页的内容越来越丰富,之前的页面结构已经不能满足我们的需求,需要一个新的布局方案承载各种圈子元素并满足我们的自定义交互。改版前改版前的结构比较简单,头部显示...

weixin_39669982的博客 416

Android-RecycleView的双向列表左右联动效果

开篇 有一个需求,需要做一个左右双向联动的列表。类似于饿了么点餐页面,但是远没有那么复杂,只是用于展示的一个页面。只用了两个RecycleView加适配器,没有调用Fragment。 MainActivity public class MainActivity extends Activity { private RecyclerView mR...

maopihu2308的博客 3158

Android实现类似股票列表联动

1.最近项目在做学校成绩分析这一块,当我看到效果图的时候直接蒙蔽,以为实现起来很难,不过经过研究并不难 首先看下效果图 2.代码的实现 (1)首先上下移动通过scrollview实现左右侧同时滑动,右侧listview通过重写HorizontalScrollView实现右侧上下部分能够同时联动 package com.example.leftrightdemo; import

BriskLyer的博客 4075

android 二级联动列表,仿eleme点餐页面

写在前面最近手感不错,老想写点轮子。正好周末外卖点得多,就仿一仿“饿了么”好了。先上图吧,这样的订单页面是不是很眼熟:右边的listview分好组以后,在左边的Tab页建立索引。可以直接导航,是不是很方便。关键在于右边滑动,左边也会跟着滑;而点击左边呢,也能定位右边的项。它们存在这样一种特殊的交互。像这种联动的效果,还有些常见的例子呢,比如知乎采用了常见的toolbar+viewPager的联动,只

fashare 的博客 1万+

安卓ListView高亮选中与两级联动带图标的实现

ListView的实现需要以下几个主要步骤:布局文件中定义ListView:首先,在布局文件中添加ListView元素,这样用户界面才能显示列表。xml<ListView创建适配器:适配器是连接数据和ListView的桥梁。需要创建一个适配器的实例来为ListView提供数据,并定义如何在列表项中显示数据。java填充数据:数据通常来自一个数组或ArrayList。适配器将这些数据项转换为列表项,并显示在ListView中。java。

weixin_31641077的博客 1091

android 高仿点餐,仿饿了吗点餐界面ListView联动的实现

主要实现了2个ListView怎样实现互相关联,正好上篇博客review了ListView控件常规使用,因此本篇博客主要对大神的那篇博客的实现进行代码层的剖析。一方面,方便自己,在以后的代码实现上加以参考。另一方面,供刚入门的Android菜鸟们共同学习。二、最终的效果图如上图效果图为仿饿了么点餐界面的ListView级联三、实现ListView级联的困难点为了好做区分,在本文中左侧的ListVi...

weixin_36214833的博客 1275

Android仿eleme点餐页面二级联动列表

本周末外卖点得多,就仿一仿“饿了么”好了。先上图吧,这样的订单页面是不是很眼熟: 右边的listview分好组以后,在左边的Tab页建立索引。可以直接导航,是不是很方便。关键在于右边滑动,左边也会跟着滑;而点击左边呢,也能定位右边的项。它们存在这样一种特殊的交互。像这种联动的效果,还有些常见的例子呢,比如知乎采用了常见的toolbar+viewPager的联动,只不过是上下布局: 再看看点评,它的城市选择页面也有这种联动的影子,只是稍微弱一点。侧边栏可以对listview进行索引,这最早是在微信好友列表里出现的把: 趁着周末,我也撸一个。就拓展性而言,应该可以适配以上所有情况吧。我称其为

SAP PS项目结算实操:从CJ20N到CJ88,手把手搞定项目成本结转与凭证生成

本文详细解析SAP PS项目结算全流程,从CJ20N到CJ88的操作要点,涵盖成本归集、结算规则配置、结果分析及凭证生成等关键环节。特别针对FICO模块中的项目凭证流转问题提供实战解决方案,帮助财务人员规避常见配置错误,提升项目结算效率与准确性。

weixin_26833503的博客 815

双RecyclerView联动,仿饿了么选餐列表;

点击左边的列表,右边的定位到指定条目; 滑动右边的列表,左边的选中指定条目; 现在的饿了么或美团的点餐界面类似这样的; 下面来看代码咯,注释还是比较详细的; public class MainActivity extends AppCompatActivity { private LinkBean linkBean; private LAdapter lAdapte...

Choi晨的博客 2262

Kolla 容器化 高可用OpenStack 部署与 Ceph 集群集成

本文介绍了 Kolla 项目在容器化 OpenStack 部署和管理方面的应用,以及与 Ceph 集群的集成。Kolla 项目通过容器技术提供了一种简化和自动化的 OpenStack 部署方法,同时实现了易于升级和回滚的特点。本文还探讨了 Kolla 在实现零宕机升级方面的进展,并分析了其对 OpenStack 用户和社区的重要意义。

we22635的博客 2702

Android双向列表左右联动效果

转载请作明出处: 开篇 前一段时间有一个需求,需要做一个左右双向联动的列表。类似于饿了么点餐页面,但是远没有那么复杂,只是用于展示的一个页面。不是很复杂,做完已经很久了,目前为止没有出现什么问题,所以在此将它分享给大家。 番外 此功能依赖于BaseRecyclerViewAdapterHelper的adapter框架编写,如果各位看官没有接触过这个库,请先点击链接,大致了解过后再回来看此文...

一种简单粗暴的Android屏幕适配方案 3121

DCDC--控制方式(Control Mode)

DCDC反馈控制方式

网始如芯个人博客 1万+

达梦数据库(DM)的备份与恢复功能

本文系统介绍了达梦数据库(DM)的备份与恢复功能,主要包括作业系统和物理/逻辑备份还原两大模块。作业系统部分详细说明了通过代理环境创建定时备份和删除备份作业的步骤;物理备份还原部分阐述了联机和脱机备份方式,包括数据库、表空间、表和归档的备份还原操作;逻辑备份还原部分介绍了dexp/dimp工具的使用方法及四种级别的导入导出功能。文章还介绍了图形化管理工具进行备份还原的操作流程,全面覆盖了达梦数据库的数据保护方案,为数据库管理员提供了详细的技术指导。

weixin_48812832的博客 1211

android商城左右侧列表关联,Android-RecycleView的双向列表左右联动效果

效果图.png开篇有一个需求,需要做一个左右双向联动的列表。类似于饿了么点餐页面,但是远没有那么复杂,只是用于展示的一个页面。只用了两个RecycleView加适配器,没有调用Fragment。MainActivitypublic class MainActivity extends Activity {private RecyclerView mRvClass;private RecyclerV...

weixin_34530164的博客 679

信息流广告ROI线性预测看板&投放分析监控看板展示&数据处理入库全流程

此看板数据量太大,在tableau public部署运行速度极慢,因此用图片作展示 数据清洗

Larry_Westside的博客 2316

Android开发丶二级列表的联动功能实现

通常我们在外卖或者商城app会看到竖排二级列表的界面,点击左边列表的分类菜单,右边列表则会显示对应分类下的列表内容,这篇博文将对该功能的实现归纳和整理。 首先看下效果图: 在第一个页面选择最多三个标签,将书局塞到数组里返回上一个页面,然后就可以按照需求完成一系列操作。 下面说下实现步骤: 1.首先分析界面,是两个等比宽的列表,推荐使用recyclerview,右上角用来记录选择的标签个...

u014078990的博客 9599

人工智能训练师认证教程(5)使用MONAI进行医学影像分析的完整指南

本文介绍了使用MONAI框架进行医学影像分析的全流程。首先详细说明了环境搭建步骤,包括PyTorch和MONAI的安装配置。然后以肺部CT 3D分割为例,分步骤讲解了数据准备与预处理、3D UNet模型构建、训练配置(DiceLoss损失函数、Adam优化器等)以及训练验证循环的实现。文章还包含推理可视化方法和模型导出为ONNX格式的部署方案,并强调了医学影像分析中的数据格式适配、强度归一化、显存优化等关键注意事项。最后指出MONAI的医学专用组件可大幅简化开发流程,建议后续可探索SwinUNETR等进阶方

华为开发者布道师,天府英才计划,致力于大数据+AI 的应用创新,助力企业与个人AI创新赋能。 1208

【Unity3D框架】GameFramework框架完全教程《全网最全》-专栏文章目录

最近准备学习框架,了解到GameFramework框架是国产Unity3D框架,准备学习一下,但是奈何全网关于这个框架的教程实在太少。为了让自己学习方便一些,也为了让后来者乘凉。将框架以自己的理解整理目录,并且补全教程。觉得教程有帮助别忘了一键三连哦。

优快云博客专家,Unity3D高级软件工程师,《Unity 3D从入门到实战》作者。 2万+

RecyclerView选中后保持高亮状态,且两级联动示例

RecyclerView选中后保持高亮状态,且两级联动示例 提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录RecyclerView选中后保持高亮状态,且两级联动示例前言一、pandas是什么?二、使用步骤1.引入库2.读入数据总结 前言 相信不少刚刚步入Android开发的“程序猿”在遇到公司类似美团、饿了么的点餐列表,都会比较迷茫怎么写,之前我写过使用ListView实现的功能,也可以参考看下。现在使用RecyclerView重新实现这个功能,代码更加简洁明了的实现了列表的

吾少的博客 1479

MSBlock赋能C2f模块,让目标检测在轻量化与精度间双向突破

在文件夹下新建,将上述MSBlock和C2f_MS类的代码写入其中。这一步是为了让YOLOv8的代码架构能识别我们的自定义模块。

LXY_LOVE36的博客 143

仿饿了点餐界面2个ListView联动

如图是效果图 是仿饿了的点餐界面 1.点击左侧的ListView,通过在在适配器中设置Item来改变颜色,再通过notifyDataSetInvalidated来刷新并用lv_home.setSelection(showTitle.get(arg2));来关联右侧的 2.右侧的主要是重写下onScroll的方法;来改变左侧ListView的颜色及背景 不过程序中还有个问题,望大神...

alf13610的博客 156

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

上一篇: Android之收银机称重和打印及抹零
下一篇: Android之USB打印
叶已初秋
博客等级 码龄11年 2684粉丝 82原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叶已初秋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值