2019-09-10 09:53:32 weixin_37228152 阅读数 66
公司的项目中用到了百度地图定位,但是在测试机上无法实现自动定位,但诡异的是日志中并没有关于定位的报错,经过断点调试后发现是registerLocationListener没有回调。
然鹅隔壁的小伙伴的测试机能够自动定位,我的手机却不能,由此可以判断并不是项目代码本身的问题。
所以打算将锅甩给手机,看看是否手机的定位功能出现问题。然鹅通过测试机上的饿了么和美团等程序的成功定位也可以判断出不是手机的问题。
在一一排除之后开始把目光放在百度地图上,在对比了不同机型的差别之后,发现唯一一台能成功定位的手机是Android7.0系统,其余都是Android6.0,所以判断应该是安卓系统版本的问题。
最后发现在Android6.0版本下使用要静态注册service
解决:将service加到AndroidMainifest.xml文件中,如下:
<service
            android:name="com.baidu.location.f"
            android:enabled="true"
            android:process=":remote" />
2018-05-26 10:17:54 Silence_Sep 阅读数 396

Android常用组件整理:(大牛们写的组件)

1.城市选择、定位、搜索及右侧字母导航,类似美团 百度糯米 饿了么等APP选择城市功能

地址:https://github.com/zaaach/CityPicker



2.日历组件

地址:https://github.com/traex/CalendarListview


3.任意层级树

地址:https://www.cnblogs.com/bdsdkrb/p/5841468.html(没有完整源码)

源码:(自己整理的)https://download.csdn.net/download/silence_sep/10438894


4.可上拉刷新,下拉加载的RecyclerView

地址:https://github.com/limxing/LFRecyclerView-Android


2019-07-23 10:48:13 qq_35605213 阅读数 128

点击左边的列表,右边的定位到指定条目;

滑动右边的列表,左边的选中指定条目;

现在的饿了么或美团的点餐界面类似这样的;

下面来看代码咯,注释还是比较详细的;

public class MainActivity extends AppCompatActivity {

    private LinkBean linkBean;
    private LAdapter lAdapter;
    private RAdapter rAdapter;

    private void initData() {
        linkBean = new LinkBean();
        linkBean.itemLS = new ArrayList<>();
        linkBean.itemS = new ArrayList<>();
        for (int i = 0; i < 12; i++) {
            LinkBean.ItemL itemL = new LinkBean.ItemL();
            itemL.setTitle("分类"+i);
            linkBean.itemLS.add(itemL);

            for (int j = 0; j < 16; j++) {
                if (i % 2 == 0 && j % 2 == 0){
                }else {
                    LinkBean.Item item = new LinkBean.Item();
                    item.setTitle("分类"+i);
                    item.setName("名称"+j);
                    item.setPrice("¥:"+(2+i+j)*3);
                    linkBean.itemS.add(item);
                }
            }
        }
        Log.i("ccb", linkBean.itemS.size()+"initData: "+linkBean.itemLS.size());
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
        initView();
        initListener();
    }

    private RecyclerView rvL, rvR;
    private TextView tv_head;

    private void initView() {
        tv_head = findViewById(R.id.tv_header);
        tv_head.setText(linkBean.itemLS.get(0).getTitle());
        rvL = findViewById(R.id.rv1);
        rvR = findViewById(R.id.rv2);
        rvL.setLayoutManager(new LinearLayoutManager(this));
        rvR.setLayoutManager(new LinearLayoutManager(this));
        lAdapter = new LAdapter(this,R.layout.item,linkBean.itemLS);
        lAdapter.bindToRecyclerView(rvL);
        rvL.setAdapter(lAdapter);
        rAdapter = new RAdapter(this,R.layout.item_goods,linkBean.itemS);
        rvR.setAdapter(rAdapter);
    }

    private boolean moveToTop = false;
    private int index;
    private void initListener() {
        lAdapter.setOnItemClickListener(new BaseRecyclerViewAdater.OnItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                if (rvR.getScrollState() != RecyclerView.SCROLL_STATE_IDLE)return;
                lAdapter.fromClick = true;
                lAdapter.setChecked(position);
                String tag = lAdapter.getmData().get(position).getTitle();
                for (int i = 0; i < rAdapter.getmData().size(); i++) {
                    //根据左边选中的条目获取到右面此条目Title相同的位置索引;
                    if (TextUtils.equals(tag,rAdapter.getmData().get(i).getTitle())){
                        index = i;
                        moveToPosition_R(index);
                        return;
                    }
                }
            }
        });

        rvR.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                LinearLayoutManager layoutManager = (LinearLayoutManager) rvR.getLayoutManager();
                if (moveToTop){ //向下滑动时,只会把改条目显示出来;我们还需要让该条目滑动到顶部;
                    moveToTop = false;
                    int m = index - layoutManager.findFirstVisibleItemPosition();
                    if (m >= 0 && m <= layoutManager.getChildCount()){
                        int top = layoutManager.getChildAt(m).getTop();
                        rvR.smoothScrollBy(0,top);
                    }
                }else {
                    int index = layoutManager.findFirstVisibleItemPosition();
                    tv_head.setText(rAdapter.getmData().get(index).getTitle());
                    lAdapter.setToPosition(rAdapter.getmData().get(index).getTitle());
                }
            }
        });

        rvR.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                lAdapter.fromClick = false;
                return false;
            }
        });
    }


    private void moveToPosition_R(int index) {
        LinearLayoutManager layoutManager = (LinearLayoutManager) rvR.getLayoutManager();
        int f = layoutManager.findFirstVisibleItemPosition();
        int l = layoutManager.findLastVisibleItemPosition();
        if (index <= f){ //向上移动时
            layoutManager.scrollToPosition(index);
        }else if (index <= l){ //已经再屏幕上面显示时
            int m = index - f;
            if (0 <= m && m <= layoutManager.getChildCount()) {
                int top = layoutManager.getChildAt(m).getTop();
                rvR.smoothScrollBy(0, top);
            }
        }else { //向下移动时
            moveToTop = true;
            layoutManager.scrollToPosition(index);
        }
    }


    class LAdapter extends BaseRecyclerViewAdater<LinkBean.ItemL>{


        public LAdapter(Context context, int resLayout, List<LinkBean.ItemL> data) {
            super(context, resLayout, data);
        }

        @Override
        public void convert(BaseRecyclerHolder holder, final int position) {
            TextView tv = ((TextView)holder.getView(R.id.tv));
            tv.setText(getmData().get(position).getTitle());
            if (checked == position){
                tv.setTextColor(ContextCompat.getColor(context,R.color.colorPrimary));
                tv.setBackgroundResource(R.color.colorfff);
            }else {
                tv.setTextColor(ContextCompat.getColor(context,R.color.color666));
                tv.setBackgroundResource(R.color.color16333333);
            }

        }

        private int checked; //当前选中项
        public boolean fromClick; //是否是自己点击的

        public void setChecked(int checked) {
            this.checked = checked;
            notifyDataSetChanged();
        }

        //让左边的额条目选中
        public void setToPosition(String title){
            if (fromClick)return;
            if (TextUtils.equals(title,getmData().get(checked).getTitle()))return;
            if (TextUtils.isEmpty(title))return;
            for (int i = 0; i < getmData().size(); i++) {
                if (TextUtils.equals(getmData().get(i).getTitle(),title)){
                    setChecked(i);
                    moveToPosition(i);
                    return;
                }
            }

        }

        private void moveToPosition(int index){
            //如果选中的条目不在显示范围内,要滑动条目让该条目显示出来
            LinearLayoutManager linearLayoutManager = (LinearLayoutManager) getRecyclerView().getLayoutManager();
            int f = linearLayoutManager.findFirstVisibleItemPosition();
            int l = linearLayoutManager.findLastVisibleItemPosition();
            if (index<=f || index >= l){
                linearLayoutManager.scrollToPosition(index);
            }

        }

    }

    class RAdapter extends BaseRecyclerViewAdater<LinkBean.Item>{


        public RAdapter(Context context, int resLayout, List<LinkBean.Item> data) {
            super(context, resLayout, data);
        }

        @Override
        public void convert(BaseRecyclerHolder holder, final int position) {
            ((TextView)holder.getView(R.id.tvName)).setText(getmData().get(position).getTitle()+getmData().get(position).getName());
            ((TextView)holder.getView(R.id.tvPrice)).setText(getmData().get(position).getPrice());

            //悬停的标题头
            FrameLayout headLayout = holder.getView(R.id.stick_header);
            TextView tvHead = holder.getView(R.id.tv_header);
            if (position == 0){
               headLayout.setVisibility(View.VISIBLE);
               tvHead.setText(getmData().get(position).getTitle());
            }else {
                if (TextUtils.equals(getmData().get(position).getTitle(),getmData().get(position-1).getTitle())){
                    headLayout.setVisibility(View.GONE);
                }else {
                    headLayout.setVisibility(View.VISIBLE);
                    tvHead.setText(getmData().get(position).getTitle());
                }
            }

            holder.itemView.setOnClickListener(new View.OnClickListener() {
                 @Override
                 public void onClick(View view) {
                     Toast.makeText(MainActivity.this,getmData().get(position).getTitle()+getmData().get(position).getName(),Toast.LENGTH_SHORT).show();
                 }
             });
        }
    }

}

基础数据类:

public class LinkBean {
    public List<ItemL> itemLS;
    public List<Item> itemS;

    public static class ItemL{
        private String title;

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }
    }

    public static class Item{
        private String title;
        private String name;
        private String price;

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        private String content;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getPrice() {
            return price;
        }

        public void setPrice(String price) {
            this.price = price;
        }

        public String getContent() {
            return content;
        }

        public void setContent(String content) {
            this.content = content;
        }
    }


}

布局文件:

main_activity.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    tools:context=".MainActivity">
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rv1"
        android:layout_width="100dp"
        android:layout_height="match_parent"></androidx.recyclerview.widget.RecyclerView>

    <View
        android:layout_width="1dp"
        android:layout_height="match_parent"
        android:background="#ddd"
        />
    <FrameLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/rv2"
            android:layout_width="match_parent"
        android:layout_height="match_parent"></androidx.recyclerview.widget.RecyclerView>

        <include layout="@layout/view_stick_head"/>
    </FrameLayout>

</LinearLayout>

左边的recycler view:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/tv"
    android:textSize="14dp"
    android:text="你好啊"
    android:textColor="#333"
    android:background="#11fd5588"
    android:layout_marginBottom="1dp"
    android:padding="18dp"
    >

</TextView>

右边的recyclerview:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <include layout="@layout/view_stick_head" />

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="98dp"
        android:layout_margin="2dp"
        android:foreground="?android:attr/selectableItemBackground">

        <View
            android:layout_width="match_parent"
            android:layout_height="1px"
            android:layout_alignParentBottom="true"
            android:layout_marginLeft="8dp"
            android:background="#ededed" />

        <androidx.cardview.widget.CardView xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:tools="http://schemas.android.com/tools"
            android:id="@+id/iv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_marginLeft="8dp"
            app:cardCornerRadius="5dp"
            app:cardElevation="3dp">

            <androidx.appcompat.widget.AppCompatImageView
                android:layout_width="88dp"
                android:layout_height="88dp"
                android:scaleType="centerCrop"
                android:src="@mipmap/back_logo" />
        </androidx.cardview.widget.CardView>

        <TextView
            android:id="@+id/tvName"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="6dp"
            android:layout_marginTop="10dp"
            android:layout_toRightOf="@id/iv"
            android:textColor="#333"
            android:textSize="16dp"
            tools:text="我是名称" />

        <TextView
            android:id="@+id/tvContaent"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/tvName"
            android:layout_marginLeft="6dp"
            android:layout_marginTop="6dp"
            android:layout_toRightOf="@id/iv"
            android:text="这个真的巨TM好吃\n来吃来吃"
            android:textColor="#555"
            android:textSize="12dp" />

        <TextView
            android:id="@+id/tvPrice"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/tvContaent"
            android:layout_marginLeft="6dp"
            android:layout_marginTop="4dp"
            android:layout_toRightOf="@id/iv"
            android:text="¥:16"
            android:textColor="#fd3535"
            android:textSize="14dp" />
    </RelativeLayout>
</LinearLayout>


标题头布局:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/stick_header"
    android:layout_width="match_parent"
    android:layout_height="30dp"
    android:background="@color/colorfff"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_header"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:layout_marginLeft="16dp"/>

    <View
        android:layout_width="match_parent"
        android:layout_height="1px"
        android:layout_gravity="bottom"
        android:layout_marginLeft="16dp"
        android:background="@color/color16333333"/>
</FrameLayout>

代码已经传到Github:https://github.com/CuiChenbo/LinkageRecyclerView 喜欢就给个star

其中BaseRecyclerViewAdapter:https://blog.csdn.net/qq_35605213/article/details/80176558 ,https://github.com/CuiChenbo/BaseRecyclerAdapter

baseadapter中新增了这个方法:

private RecyclerView recyclerView;
public void bindToRecyclerView(RecyclerView recyclerView){
    this.recyclerView = recyclerView;
}

public RecyclerView getRecyclerView() {
    return recyclerView;
}

 

2016-10-19 00:24:52 a153614131 阅读数 11300

写在前面


最近手感不错,老想写点轮子。正好周末外卖点得多,就仿一仿“饿了么”好了。先上图吧,这样的订单页面是不是很眼熟:

这里写图片描述

右边的listview分好组以后,在左边的Tab页建立索引。可以直接导航,是不是很方便。关键在于右边滑动,左边也会跟着滑;而点击左边呢,也能定位右边的项。它们存在这样一种特殊的交互。像这种联动的效果,还有些常见的例子呢,比如知乎采用了常见的tabLayout+viewPager的联动,只不过是上下布局:

这里写图片描述

再看看点评,它的城市选择页面也有这种联动的影子,只是稍微弱一点。侧边栏可以对listview进行索引,这最早是在微信好友列表里出现的把:

这里写图片描述

趁着周末,我也撸一个。就拓展性而言,应该可以适配以上所有情况吧。我称其为LinkedLayout,看下效果图:

这里写图片描述

我把右边按5个一组,可以看到,左边的索引 = 右边/5

特点


  • 右边滑动,左边跟着动
  • 左边滑动到边界,右边跟着动
  • 点击左边tab项,右边滑动定位到相应的group

源码


github 传送门: https://github.com/fashare2015/LinkedScrollDemo

知识点


做之前先罗列一下知识点,或者说我们能从这个demo里收获到什么。

  • 面向抽象/接口编程
  • 自定义 view
  • 代理模式
  • UML类图
  • 复习 listview && recyclerview 的细节

感觉做完以后收获最大的还是第一点,面向接口编程。事实上,完成功能的时间只占了一半,后边的时间一直在抽象和重构;哎,一步到位太难了,还是老老实实写具体类,再抽取基类把。

构思


UI部分

LinkedLayout

要做的呢是两个相互关联的列表,在左边的作为tab页,右边的作为content页。先不考虑交互,我们来打个界面:搞一个叫做LinkedLayout的类,用来盛放tabcontent

这里写图片描述

public class LinkedLayout extends LinearLayout {
    private Context mContext;
    private BaseScrollableContainer mTabContainer;
    private BaseScrollableContainer mContentContainer;
    private SectionIndexer mSectionIndexer; // 代理
    ...
}

我们让它继承了LinearLayout,同时持有两个Container的东东,还有一个上帝对象mContext,以及一个分组用的SectionIndexer

BaseScrollableContainer

先别管这些,主要看两个Container,从名字上看一个是tab页,一个是content页,嘿嘿。因为它们都能scroll嘛,干脆搞一个BaseScrollableContainer把。取名为Container呢,当然是致敬Fragment啦。我们来定义一下这个类:
初步一想,无非有一个 mContext, 一个 viewGroup, 还有一些 Listener 嘛:

这里写图片描述

public abstract class BaseScrollableContainer<VG extends ViewGroup> {
    protected Context mContext;
    public VG mViewGroup;

    protected RealOnScrollListener mRealOnScrollListener;
    private EventDispatcher mEventDispatcher;
    ...
}

和我们预想的差不多嘛,mContext上下文,mViewGroup基本就是指代我们的两个listview了吧。当然,我之后可是要做tablayout+viewpager的,肯定得依赖抽象,不能直接写listview啦。余下两个是Listener,等我们界面搭好,写交互的时候在看把。
看来UML图还是有好处的,继承和依赖关系一目了然。

自定义View && 动态布局

好了到了自定义view地环节了。我们已经有了一个LinkedLayout,这是我们的activity_main.xml布局代码:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.fashare.linkedscrolldemo.ui.LinkedLayout
        android:id="@+id/linked_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"/>
</RelativeLayout>

擦,就没了嘛?剩下的得靠java代码来搞啦。回到LinkedLayout咱们来布局UI~:

public class LinkedLayout extends LinearLayout {
    ...
    private static final int MEASURE_BY_WEIGHT = 0;
    private static final float WEIGHT_TAB = 1;
    private static final float WEIGHT_CONTENT = 3;

    public void setContainers(BaseScrollableContainer tabContainer, BaseScrollableContainer contentContainer) {
        mTabContainer = tabContainer;
        mContentContainer = contentContainer;
        mTabContainer.setEventDispatcher(this);
        mContentContainer.setEventDispatcher(this);

        // 设置 LayoutParams
        mTabContainer.mViewGroup.setLayoutParams(new LinearLayout.LayoutParams(
                MEASURE_BY_WEIGHT,
                ViewGroup.LayoutParams.WRAP_CONTENT,
                WEIGHT_TAB
        ));

        mContentContainer.mViewGroup.setLayoutParams(new LinearLayout.LayoutParams(
                MEASURE_BY_WEIGHT,
                ViewGroup.LayoutParams.MATCH_PARENT,
                WEIGHT_CONTENT
        ));

        this.addView(mTabContainer.mViewGroup);
        this.addView(mContentContainer.mViewGroup);
        this.setOrientation(HORIZONTAL);
    }
}

搞了个setContainers用来注入我们的Container,里边有一些像layout_height,layout_width,layout_weight,orientation之类的,很眼熟吧,和xml没差。顺便一提的是,我们用了weight属性来控制这个比例1:3,一直感觉这个属性比较神奇。。。

注入ViewGroup, 使用自定义的LinkedLayout

到这里为止,LinkedLayout已经布局好了,我们分别注入ViewGroup就可以用了。我这里分别用listviewtab,recyclerviewcontent。想像力有限,用来用去好像也就这么几个控件。。。这部分代码很简单,在MainActivity里,就不贴了。

子类化 BaseScrollableContainer

按照常理,下边应该实现基类了吧。前面的MainActivity中,我们是这样实例化的:

mTabContainer = new ListViewTabContainer(this, mListView);
mContentContainer = new RecyclerViewContentContainer(this, mRecyclerView);

看名字一个是listview填充的tab,一个是recyclerview填充的content。就先实现这两个类吧,从图中可以看到,它们分别继承于BaseScrollableContainer,并被LinkedLayout所持有:
这里写图片描述

交互部分

与用户的交互:OnScrollListener 与 代理模式

终于到了交互部分,既然是滑动,那少不了定义监听器啦。然而,麻烦在于listviewrecyclerview各自的OnScrollListener还不一样,这个时候如果各自实现的话,既麻烦,又有冗余。像这样子:

// RecyclerView
public class RecyclerViewContentContainer extends BaseScrollableContainer<RecyclerView> {
    ...
    @Override
    protected void setOnScrollListener() {
        mViewGroup.addOnScrollListener(new ProxyOnScrollListener());
    }

    private class ProxyOnScrollListener extends RecyclerView.OnScrollListener {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            if(newState == RecyclerView.SCROLL_STATE_IDLE) {            // 停止滑动
                1.停止时的逻辑...
            }else if(newState == RecyclerView.SCROLL_STATE_DRAGGING){   // 按下拖动
                2.刚刚拖动时的逻辑...
            }
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) { // 滑动
            3.滑动时的逻辑...
        }
    }
}

// ListView
public class ListViewTabContainer extends BaseScrollableContainer<ListView> {
    ...
    @Override
    protected void setOnScrollListener() {
        mViewGroup.setOnScrollListener(new ProxyOnScrollListener());
        ...
    }

    public class ProxyOnScrollListener implements AbsListView.OnScrollListener{
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            if(scrollState == SCROLL_STATE_IDLE) {              // 停止滑动
                1.停止时的逻辑...
            }else if(scrollState == SCROLL_STATE_TOUCH_SCROLL)  // 按下拖动
                2.刚刚拖动时的逻辑...
        }

        @Override
        public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
            3.滑动时的逻辑...                // 滑动
        }
    }
}

那该怎么办呢,虽然各自的OnScrollListener差异挺大,但是仔细观察可以发现其实很多逻辑都是类似的,可以共用的。这时恰恰可以用代理模式来做重构。我抽取了1、2、3处的逻辑,由于在抽象意义上是一致的,可以整理成接口:

public interface OnScrollListener {
    // tab 点击事件
    void onClick(int position);

    // 1.滑动开始
    void onScrollStart();

    // 2.滑动结束
    void onScrollStop();

    // 3.触发 onScrolled()
    void onScrolled();

    // 用户手动滑, 触发的 onScrolled()
    void onScrolledByUser();

    // 程序调用 scrollTo(), 触发的 onScrolled()
    void onScrolledByInvoked();
}

与此同时,RecyclerViewListView各自的监听器便分别作为代理类,把1、2、3的逻辑都委托给某个接盘侠,不必自己去实现,倒也落的轻松自在。如图所示:这里写图片描述

然后,让我们来看看这个接盘侠:RealOnScrollListener。。。
不愧是一个老实类,它老实地接盘了OnScrollListener的所有接口,并被两个代理类Proxy…所持有(图中并未画出。。)。
具体实现就不贴了,大家可以下源码来看。这里大致分析一下,它有三个成员:

public class RealOnScrollListener implements OnScrollListener {
    public boolean isTouching = false;  // 处于触摸状态
    private int mCurPosition = 0;       // 当前选中项
    private BaseViewGroupUtil<VG> mViewUtil; // ViewGroup 工具类
    ...
}
  • isTouching:
    为啥要维护这个触摸状态呢?这是由于我们的效果是联动的。这就比较讨厌了,当onScrolled()被调用,我们分不清是用户的滑动,还是来自另一个列表滑动时的联动效果。那我们记录一下isTouching状态呢,就能区分开这两种情况了。
    更改isTouching的逻辑在onScrollStart()onScrollStop()里边。

  • mCurPosition
    这个很好解释,我们每次滑动需要记录当前位置,然后通知另一个列表进行联动。
    这段逻辑在onScrolled()里边。

  • mViewUtil
    一个工具库,用于简化逻辑。大概有scrollTo(),setViewSelected(),UpdatePosOnScrolled()等方法,如图:
    这里写图片描述

两个Container之间的交互

之前都是对用户的交互,终于到联动部分了。不急着实现,先回答我一个问题:假设我一个Activity里持有两个Fragment,问它们之间如何通信?

  • A同学大声道:用广播
  • B同学:EventBus !!!
  • C同学:看我 RxBus 。。。

别闹好吗。。。给我老老实实用Listener。显然,我们这里面临的是同样的场景。LinkedLayout=Activity,Container=Fragment
动手前先定义Listener吧,要取个中二点的名字:

/*
 * 事件分发者
 */
public interface EventDispatcher {
    /**
     * 分发事件: fromView 中的 pos 被选中
     * @param pos
     * @param fromView
     */
    void dispatchItemSelectedEvent(int pos, View fromView);
}

/*
 * 事件接受者
 */
public interface EventReceiver {
    /**
     * 收到事件: 立即选中 newPos
     * @param newPos
     */
    void selectItem(int newPos);
}

然后LinkedLayout作为父级元素,肯定是分发者的角色,应当实现EventDispatcher;而BaseScrollableContainer作为子元素,接受该事件,应当实现EventReceiver。看下类图:
这里写图片描述

看下相应的实现(EventReceiver):

public abstract class BaseScrollableContainer<VG extends ViewGroup>
        implements EventReceiver {
    protected RealOnScrollListener mRealOnScrollListener;
    private EventDispatcher mEventDispatcher; // 持有分发者
    ...
    public void setEventDispatcher(EventDispatcher eventDispatcher) {
        mEventDispatcher = eventDispatcher;
    }

    // 掉用 mEventDispatcher,也就是 LinkedLayout
    protected void dispatchItemSelectedEvent(int curPosition){
        if(mEventDispatcher != null)
            mEventDispatcher.dispatchItemSelectedEvent(curPosition, mViewGroup);
    }

    @Override
    public void selectItem(int newPos) {
        mRealOnScrollListener.selectItem(newPos);
    }

    // OnScrollListener: 代理模式
    public class RealOnScrollListener implements OnScrollListener {
        ...
        public void selectItem(int position){
            mCurPosition = position;
            Log.d("setitem", position + "");
            // 来自另一边的联动事件
            mViewUtil.smoothScrollTo(position);
//            if(mViewUtil.isVisiblePos(position))    // curSection 可见时, 不滚动
                mViewUtil.setViewSelected(position);
        }

        @Override
        public void onClick(int position) {
            isTouching = true;
            mViewUtil.setViewSelected(mCurPosition = position);
            dispatchItemSelectedEvent(position);  // 点击tab,分发事件
            isTouching = false;
        }
        ...
        @Override
        public void onScrolled() {
            mCurPosition = mViewUtil.updatePosOnScrolled(mCurPosition);
            if(isTouching)          // 来自用户, 通知 对方 联动
                onScrolledByUser();
            else                    // 来自对方, 被动滑动不响应
                onScrolledByInvoked();
        }

        @Override
        public void onScrolledByUser() {
            dispatchItemSelectedEvent(mCurPosition);    // 来自用户, 通知 对方 联动
        }
    }
}

再看(EventDispatcher):

public class LinkedLayout extends LinearLayout implements EventDispatcher {
    private BaseScrollableContainer mTabContainer;
    private BaseScrollableContainer mContentContainer;
    private SectionIndexer mSectionIndexer; // 分组接口
    ...

    @Override
    public void dispatchItemSelectedEvent(int pos, View fromView) {
        if (fromView == mContentContainer.mViewGroup) { // 来自 content, 转发给 tab
            int convertPos = mSectionIndexer.getSectionForPosition(pos);
            mTabContainer.selectItem(convertPos);
        } else {                    // 来自 tab, 转发给 content
            int convertPos = mSectionIndexer.getPositionForSection(pos);
            mContentContainer.selectItem(convertPos);
        }
    }
}


总结


到此为止,有没有一种酣畅淋漓的感觉?不管怎么说,面向对象是信仰,定义好接口以后,实现起来怎么写怎么舒服。
// TODO: 之前说了,这个联动是通用的。之后有时间会继续实现一个tablayout+viewPager的联动…

彩蛋


高清无码类图:(完整)

这里写图片描述

2017-03-01 11:48:57 jaryjun 阅读数 3855

今天给大家带来一个百度地图的综合案例,主要是仿百度外卖地址添加功能,主要涉及到的功能有以下几点:

  • 百度地图状态改变监听,用户拖动地图可以实时展示周围的poi信息
  • 打开页面定位用户的位置
  • poi搜索,根据用户搜索的关键字显示poi信息
  • 在地图设置配送范围
  • 判断拖动的位置与搜索的地址是否在配送范围内,并给出友好提示

效果图

这里写图片描述 这里写图片描述
这里写图片描述

集成百度地图api

使用百度地图api需要申请密钥,如下网址有详细操作步奏
http://lbsyun.baidu.com/index.php?title=androidsdk/guide/key
配置环境,导入jar包,参考如下网址(jar导入也可直接文章最后demo)
http://lbsyun.baidu.com/index.php?title=androidsdk/guide/buildproject

主页面布局文件

activity_main.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:clipToPadding="false"
    android:fitsSystemWindows="true"
    android:orientation="vertical" >

    <RelativeLayout
        android:id="@+id/rl_search"
        android:layout_width="match_parent"
        android:layout_height="45dp"
        android:background="@color/bg_feedback" >

        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="30dp"
            android:layout_centerInParent="true"
            android:layout_marginLeft="6dp"
            android:layout_marginRight="12dp"
            android:layout_marginTop="6dp"
            android:layout_toRightOf="@+id/iv_left"
            android:background="@color/bg_mine" >

            <ImageView
                android:id="@+id/iv_search"
                android:layout_width="26dp"
                android:layout_height="26dp"
                android:layout_centerVertical="true"
                android:layout_marginLeft="6dp"
                android:paddingRight="6dp" />

            <EditText
                android:id="@+id/et_search"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:layout_toRightOf="@+id/iv_search"
                android:background="@color/bg_mine"
                android:gravity="center_vertical"
                android:hint="查找小区,大厦,学校"
                android:paddingLeft="2dp"
                android:singleLine="true"
                android:textColor="@color/black"
                android:textSize="14sp" />
        </RelativeLayout>

        <ImageView
            android:id="@+id/iv_left"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_centerVertical="true"
            android:layout_marginLeft="6dp"
            android:padding="14dp"
            android:src="@drawable/arrow_left" />
    </RelativeLayout>

    <LinearLayout
        android:id="@+id/ll_map"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipToPadding="false"
        android:fitsSystemWindows="true"
        android:orientation="vertical"
        >

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="280dp"
        android:orientation="vertical"
        android:visibility="visible" >

        <com.baidu.mapapi.map.MapView
            android:id="@+id/map"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/white"
            android:onClick="true" >
        </com.baidu.mapapi.map.MapView>

        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:background="@color/transparent"
            android:src="@drawable/gps" />
    </RelativeLayout>

    <ListView
        android:id="@+id/lv_near_address"
        android:layout_width="fill_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:cacheColorHint="#00000000"
        android:descendantFocusability="beforeDescendants"
        android:fastScrollEnabled="true"
        android:scrollbars="none" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/ll_search"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:clipToPadding="false"
        android:fitsSystemWindows="true"
        android:orientation="vertical"
        android:visibility="gone">

        <ListView
            android:id="@+id/lv_search"
            android:layout_width="fill_parent"
            android:layout_height="0dp"
            android:layout_weight="1"
            android:cacheColorHint="#00000000"
            android:descendantFocusability="beforeDescendants"
            android:fastScrollEnabled="true"
            android:scrollbars="none" />
    </LinearLayout>

</LinearLayout>
 页面布局主要是MapView+两个listview,其中lv_search是当用户点击搜索框时显示的listview布局,默认隐藏。

主页面功能介绍

参考MainActivity.class

百度地图状态改变监听,用户拖动地图可以实时展示周围的poi信息

       ----------------------------地图状态改变设置----------------------------
        MapStatus mapStatus = new MapStatus.Builder().zoom(15).build();
        MapStatusUpdate mMapStatusUpdate = MapStatusUpdateFactory.newMapStatus(mapStatus);
        mBaiduMap.setMapStatus(mMapStatusUpdate);
        // 地图状态改变相关监听
        mBaiduMap.setOnMapStatusChangeListener(this);//让MainActivity实现OnMapStatusChangeListener
    ----------------------------反地理编码GeoCoder设置---------------------------
        // 创建GeoCoder实例对象
        geoCoder = GeoCoder.newInstance();
        // 设置查询结果监听者
        geoCoder.setOnGetGeoCodeResultListener(this);//让MainActivity实现OnGetGeoCoderResultListener

    -----------------------MapStatusChange监听回调方法----------------------

    @Override
    public void onMapStatusChangeStart(MapStatus mapStatus) {

    }

    @Override
    public void onMapStatusChange(MapStatus mapStatus) {

    }

    /**
     * 当用户拖动地图结束时,调用该方法
     */
    @Override
    public void onMapStatusChangeFinish(MapStatus mapStatus) {
        // 获取地图最后状态改变的中心点
        LatLng cenpt = mapStatus.target;
        Log.i(TAG, "最后停止点:" + cenpt.latitude+","+cenpt.longitude);
        //判断定位点是否在可配送范围内---如果需要设置配送的范围则加上此段代码
        if (!SpatialRelationUtil.isPolygonContainsPoint(mPoints, cenpt)){
            Toast.makeText(getApplicationContext(),"该地址不在配送范围,请在黄色区域内选择",Toast.LENGTH_LONG).show();
        }
        //将中心点坐标转化为具体位置信息,当转化成功后调用onGetReverseGeoCodeResult()方法
        geoCoder.reverseGeoCode(new ReverseGeoCodeOption().location(cenpt));
    }

    -----------------------地理编码监听回调方法----------------------
    @Override
    public void onGetGeoCodeResult(GeoCodeResult geoCodeResult) {
        //地址转化经纬度
    }
    /**
     * 经纬度转化地址成功后调用
     */
    @Override
    public void onGetReverseGeoCodeResult(ReverseGeoCodeResult reverseGeoCodeResult) {
       //经纬度转化地址
        final List<PoiInfo> poiInfos = reverseGeoCodeResult.getPoiList();
        for(int i=0;i<poiInfos.size();i++){
            Log.i(TAG, "这里的值:" + poiInfos.get(i).name);
        }

        if (poiInfos != null && !"".equals(poiInfos)) {
            //创建poiAdapter 将获取到的Poi数据传入,更新UI
            PoiListAdapter poiAdapter = new PoiListAdapter(MainActivity.this, poiInfos);
            lv_near_address.setAdapter(poiAdapter);
            lv_near_address.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                @Override
                public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                    String name = poiInfos.get(position).name.toString();
                    Toast.makeText(getApplicationContext(),name+"---->获取数据返回到添加地址页面",Toast.LENGTH_SHORT).show();
                }
            });
        }
    }

PoiListAdapter .class

package com.junwu.mymapdemo;

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.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.baidu.mapapi.search.core.PoiInfo;

import java.util.List;

/**
 * Author:JunWu
 * Date:2017/3/1
 * Version:v1.0.0
 * class describe:
 */

public class PoiListAdapter extends BaseAdapter {
    private Context context;
    private List<PoiInfo> pois;
    private LinearLayout linearLayout;

    PoiListAdapter(Context context, List<PoiInfo> pois) {
        this.context = context;
        this.pois = pois;
    }

    @Override
    public int getCount() {
        return pois.size();
    }

    @Override
    public Object getItem(int position) {
        return pois.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        PoiListAdapter.ViewHolder holder = null;
        if (convertView == null) {
            convertView = LayoutInflater.from(context).inflate(R.layout.pois_list_item, null);
            holder = new PoiListAdapter.ViewHolder(convertView);
            convertView.setTag(holder);
        } else {
            holder = (PoiListAdapter.ViewHolder) convertView.getTag();
        }
        PoiInfo poiInfo = pois.get(position);
        if (position == 0) {
            holder.iv_gps_icon.setVisibility(View.VISIBLE);
            holder.tv_pois_name.setTextColor(Color.parseColor("#D13600"));
            holder.tv_pois_address.setTextColor(Color.parseColor("#D13600"));
            holder.tv_pois_name.setText("[当前位置]"+poiInfo.name);
            holder.tv_pois_address.setText(poiInfo.address);
        }else{
            holder.iv_gps_icon.setVisibility(View.INVISIBLE);
            holder.tv_pois_name.setTextColor(Color.parseColor("#4A4A4A"));
            holder.tv_pois_address.setTextColor(Color.parseColor("#ffa9a9a9"));
            holder.tv_pois_name.setText(poiInfo.name);
            holder.tv_pois_address.setText(poiInfo.address);
        }

        return convertView;
    }

    class ViewHolder {
        ImageView iv_gps_icon;
        TextView tv_pois_name;
        TextView tv_pois_address;

        ViewHolder(View view) {
            tv_pois_name = (TextView) view.findViewById(R.id.tv_pois_name);
            tv_pois_address = (TextView) view.findViewById(R.id.tv_pois_address);
            iv_gps_icon = (ImageView) view.findViewById(R.id.iv_gps_icon);
        }
    }
}

主要用到百度地图sdk中

  • 开发指南/事件监听/地图事件监听

  • 开发指南/检索功能/地理编码

参考如下链接查找学习。
http://lbsyun.baidu.com/index.php?title=androidsdk/guide/listener#.E5.9C.B0.E5.9B.BE.E4.BA.8B.E4.BB.B6.E7.9B.91.E5.90.AC

http://lbsyun.baidu.com/index.php?title=androidsdk/guide/retrieval#.E5.9C.B0.E7.90.86.E7.BC.96.E7.A0.81

定位用户的位置

参考MainActivity.class

//---------------------------------------百度定位设置------------------------------------//
        // 开启定位图层
        mBaiduMap.setMyLocationEnabled(true);
        // 定位图层显示方式
        mCurrentMode = MyLocationConfiguration.LocationMode.NORMAL;
        mBaiduMap.setMyLocationConfigeration(new MyLocationConfiguration(mCurrentMode, true, null));
        mLocClient = new LocationClient(this);
        // 注册定位监听。让MainActivity实现BDLocationListener,当系统定位成功则调用onReceiveLocation()方法
        mLocClient.registerLocationListener(this);
        // 定位参数选项
        LocationClientOption option = new LocationClientOption();
        option.setCoorType("bd09ll");
        // 设置是否需要地址信息,默认为无地址
        option.setIsNeedAddress(true);
        // 设置是否需要返回位置语义化信息,可以在BDLocation.getLocationDescribe()中得到数据,ex:"在天安门附近",
        // 可以用作地址信息的补充
        option.setIsNeedLocationDescribe(true);
        // 设置是否需要返回位置POI信息,可以在BDLocation.getPoiList()中得到数据
        option.setIsNeedLocationPoiList(true);
        option.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
        // 设置是否打开gps进行定位
        option.setOpenGps(true);
        // 设置 LocationClientOption
        mLocClient.setLocOption(option);
        // 开始定位
        mLocClient.start();
    //-----------------------地图地位回调方法----------------------//
    @Override
    public void onReceiveLocation(BDLocation bdLocation) {
        // 如果bdLocation为空或mapView销毁后不再处理新数据接收的位置
        if (bdLocation == null || mBaiduMap == null) {
            return;
        }

        // 定位数据
        MyLocationData data = new MyLocationData.Builder()
                // 定位精度bdLocation.getRadius()
                .accuracy(bdLocation.getRadius())
                // 此处设置开发者获取到的方向信息,顺时针0-360
                .direction(bdLocation.getDirection())
                // 经度
                .latitude(bdLocation.getLatitude())
                // 纬度
                .longitude(bdLocation.getLongitude())
                // 构建
                .build();

        // 设置定位数据
        mBaiduMap.setMyLocationData(data);

       // 根据定位的地点,以动画方式更新地图状态
        LatLng ll = new LatLng(bdLocation.getLatitude(), bdLocation.getLongitude());
            //判断定位点是否在可配送范围内---如果需要设置配送的范围则加上此段代码
        if (!SpatialRelationUtil.isPolygonContainsPoint(mPoints, ll)){
            Toast.makeText(getApplicationContext(),"该地址不在配送范围,请在可选区域内选择",Toast.LENGTH_LONG).show();

          //ll = SpatialRelationUtil.getNearestPointFromLine(mPoints, ll);//获取离配送范围最近的点坐标
        }
        MapStatusUpdate msu = MapStatusUpdateFactory.newLatLngZoom(ll, 18);
        mBaiduMap.animateMapStatus(msu);

        locationLatLng = new LatLng(bdLocation.getLatitude(), bdLocation.getLongitude());
        // 获取城市,待会用于POISearch
        city = bdLocation.getCity();
        // 发起反地理编码请求(经纬度->地址信息)
        ReverseGeoCodeOption reverseGeoCodeOption = new ReverseGeoCodeOption();
        // 设置反地理编码位置坐标
        reverseGeoCodeOption.location(new LatLng(bdLocation.getLatitude(), bdLocation.getLongitude()));
        geoCoder.reverseGeoCode(reverseGeoCodeOption);

        //只需要打开该页面时定位一次即可,定位成功后关闭定位功能
        mLocClient.stop();
        mBaiduMap.setMyLocationEnabled(false);
    }

主要用到百度定位sdk中

  • 开发指南/获取地址

参考如下链接查找学习。
http://lbsyun.baidu.com/index.php?title=android-locsdk/guide/getloc

poi搜索,根据用户搜索的关键字显示poi信息

参考MainActivity.class

        //----------------------------poi搜索模块设置,注册搜索事件监听---------------------------//
        mPoiSearch = PoiSearch.newInstance();
        //让MainActivity实现OnGetPoiSearchResultListener,当系统定位成功则调用onGetPoiResult()方法
        mPoiSearch.setOnGetPoiSearchResultListener(this);

        //----------------------------控件点击事件处理---------------------------//
        iv_left.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (!acStateIsMap){
                    ll_map.setVisibility(View.VISIBLE);
                    ll_search.setVisibility(View.GONE);
                    acStateIsMap=true;
                }
            }
        });
        keyWorldsView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (acStateIsMap) {
                    ll_map.setVisibility(View.GONE);
                    ll_search.setVisibility(View.VISIBLE);
                    acStateIsMap = false;
                }
            }
        });
        /**
         * 当输入关键字变化时,动态更新建议列表
         */
        keyWorldsView.addTextChangedListener(new TextWatcher() {
            @Override
            public void afterTextChanged(Editable arg0) {}
            @Override
            public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {}
            @Override
            public void onTextChanged(CharSequence cs, int arg1, int arg2, int arg3) {
                //当EditText控件中文字状态发生改变时调用
                if (cs.length() <= 0) {return;}
                //根据关键字搜索poi信息
                mPoiSearch.searchInCity((new PoiCitySearchOption()).city("西安").keyword(cs.toString()));
            }
        });

//-----------------------Poi搜索回调方法----------------------//
    @Override
    public void onGetPoiResult(PoiResult result) {
        Log.i(TAG, "poiListener-----onGetPoiResult");
        //获取POI检索结果
        if (result == null || result.getAllPoi()==null) {
            Toast.makeText(getApplicationContext(),"暂时没有数据",Toast.LENGTH_LONG).show();
            return;
        }

        for (PoiInfo info : result.getAllPoi()) {
            Log.i(TAG, "当前的搜索信息:" + info.name + " " + info.address );
        }

        final List<PoiInfo> poiInfos = result.getAllPoi();
        //创建searchListAdapter ,绑定获取的poi数据并更新UI
        SearchListAdapter searchListAdapter = new SearchListAdapter(MainActivity.this, poiInfos);
        lv_search.setAdapter(searchListAdapter);
        lv_search.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                LatLng latLng = poiInfos.get(position).location;
                String name = poiInfos.get(position).name;
                //判断定位点是否在可配送范围内---如果需要设置配送的范围则加上此段代码
                if (!SpatialRelationUtil.isPolygonContainsPoint(mPoints, latLng)){
                    Toast.makeText(getApplicationContext(),"该地址不在配送范围,请在黄色区域内选择",Toast.LENGTH_LONG).show();
                    ll_map.setVisibility(View.VISIBLE);
                    ll_search.setVisibility(View.GONE);
                    acStateIsMap=true;
                    LatLng pt1 = SpatialRelationUtil.getNearestPointFromLine(mPoints, latLng);
                    geoCoder.reverseGeoCode(new ReverseGeoCodeOption().location(pt1));
                }
                Toast.makeText(getApplicationContext(),name+"---->获取数据返回到添加地址页面",Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    public void onGetPoiDetailResult(PoiDetailResult poiDetailResult) {}

    @Override
    public void onGetPoiIndoorResult(PoiIndoorResult poiIndoorResult) {}

SearchListAdapter.class

package com.junwu.mymapdemo;

import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.baidu.mapapi.search.core.PoiInfo;

import java.util.List;

import static android.content.ContentValues.TAG;

/**
 * Author:JunWu
 * Date:2017/3/1
 * Version:v1.0.0
 * class describe:
 */

public class SearchListAdapter extends BaseAdapter {
    private Context context;
    private List<PoiInfo> pois;
    private LinearLayout linearLayout;

    SearchListAdapter(Context context, List<PoiInfo> pois) {
        this.context = context;
        this.pois = pois;
    }

    @Override
    public int getCount() {
        return pois.size();
    }

    @Override
    public Object getItem(int position) {
        return pois.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        SearchListAdapter.ViewHolder holder = null;
        if (convertView == null) {
            convertView = LayoutInflater.from(context).inflate(R.layout.pois_list_item, null);
            holder = new SearchListAdapter.ViewHolder(convertView);
            convertView.setTag(holder);
        } else {
            holder = (SearchListAdapter.ViewHolder) convertView.getTag();
        }
        Log.i(TAG, "当前的position:" + position);
        PoiInfo poiInfo = pois.get(position);
        holder.tv_pois_name.setText(poiInfo.name);
        holder.tv_pois_address.setText(poiInfo.address);
        return convertView;
    }

    class ViewHolder {
        ImageView iv_gps_icon;
        TextView tv_pois_name;
        TextView tv_pois_address;

        ViewHolder(View view) {
            tv_pois_name = (TextView) view.findViewById(R.id.tv_pois_name);
            tv_pois_address = (TextView) view.findViewById(R.id.tv_pois_address);
            iv_gps_icon = (ImageView) view.findViewById(R.id.iv_gps_icon);
        }
    }
}

主要用到百度定位sdk中

  • 开发指南/搜索功能/POI检索

参考如下链接查找学习。
http://lbsyun.baidu.com/index.php?title=androidsdk/guide/retrieval#POI.E6.A3.80.E7.B4.A2

在地图设置配送范围

参考MainActivity.class

    /**
     * 设置配送的范围
     */
    private void setDeliveryScope() {
        //配送范围的点自行设置
        LatLng  latLng1=new LatLng(34.22898269265894,108.87636764022244);
        LatLng  latLng2=new LatLng(34.225323612679404,108.87819186944901);
        LatLng  latLng3=new LatLng(34.22578857521661,108.88394050365343);
        LatLng  latLng4=new LatLng(34.2297155315396,108.88647470436645);
        mPoints.add(latLng1);
        mPoints.add(latLng2);
        mPoints.add(latLng3);
        mPoints.add(latLng4);
       //构建用户绘制多边形的Option对象,绘制可配送区域
        OverlayOptions polygonOption = new PolygonOptions()
                .points(mPoints)
                .stroke(new Stroke(5, 0xAA00FF00))
                .fillColor(0xAAFFFF00);
       //在地图上添加多边形Option,用于显示
        mBaiduMap.addOverlay(polygonOption);
    }

主要用到百度定位sdk中

  • 开发指南/基础地图/几何图形覆盖物

参考如下链接查找学习。
http://lbsyun.baidu.com/index.php?title=androidsdk/guide/basicmap#.E5.87.A0.E4.BD.95.E5.9B.BE.E5.BD.A2.E8.A6.86.E7.9B.96.E7.89.A9

判断拖动的位置与搜索的地址是否在配送范围内功能
- 开发指南/计算工具/空间关系判断

http://lbsyun.baidu.com/index.php?title=androidsdk/guide/tool#.E7.A9.BA.E9.97.B4.E5.85.B3.E7.B3.BB.E5.88.A4.E6.96.AD

总结

至此所有功能已经完成,完整代码可去下面地址下载。
http://download.csdn.net/detail/jaryjun/9767320

没有更多推荐了,返回首页