android开发地址选择器,Android地址选择器 类似于京东的地址选择
簡介
最近東西寫的挺多的,這不又要弄一個類似于京東的地址選擇器,然后剛開始我是不愿意自己去寫的,這東西真的是浪費時間。但是下班后回到家找了一圈沒找到一個合適的,好吧,那我就自己來封裝一個唄,反正生命在于coding,是吧~哈哈哈!先看看效果圖,不知道是不是大家想要的。區別就是京東是用在一個從下而上的彈窗里面的。
主要功能
1.大致分為三個模塊:頂部的Tab模塊,中間的移動指示器模塊,還有就是下面的list了。
2.支持點擊數據后自動跳到下一個Tab
3.支持點擊Tab后回到當前Tab的狀態
4.還有就是可以隨意設置你想要的。
還是來說說怎么用吧。
項目地址:http://www.apkbus.com/thread-600090-1-1.html
集成導入(gradle)
1.Add the JitPack repository to your build file .Add it in your root build.gradle at the end of repositories:allprojects?{
repositories?{????????????...
maven?{?url?'https://jitpack.io'?}
}
}
2.Add the dependencydependencies?{
compile?'com.github.Blincheng:AddressSelector:v1.0.4'
}
使用
XML直接使用
android:id="@+id/address"
android:layout_width="match_parent"
android:layout_height="match_parent">
Java中使用AddressSelector?addressSelector?=?(AddressSelector)?findViewById(R.id.address);
設置Tab數量addressSelector.setTabAmount(3);
也可以不設置,默認3級。
設置數據列表的Itme回調OnItemClickListeneraddressSelector.setOnItemClickListener(new?OnItemClickListener()?{????????????@Override
public?void?itemClick(AddressSelector?addressSelector,?CityInterface?city,?int?tabPosition)?{
}
});
設置Tab的點擊事件回調OnTabSelectedListeneraddressSelector.setOnTabSelectedListener(new?AddressSelector.OnTabSelectedListener()?{????????????@Override
public?void?onTabSelected(AddressSelector?addressSelector,?AddressSelector.Tab?tab)?{
}????????????@Override
public?void?onTabReselected(AddressSelector?addressSelector,?AddressSelector.Tab?tab)?{
}
});
注意,一般來說這兩個點擊事件都要設置,并且數據的處理一定要搞清楚。
其他的一些屬性的設置
此處表示很憂傷,剛才不知道按了什么快捷鍵,剛寫的東西全丟了!!!不開心
實現
現在我們開始說說實現方式吧,從需求上面來講,我們需要寫出來的東西具有以下幾點:
1.有指示器(Tab),
2.有一條會動的橫線
3.下方有個列表
4.上方的Tab和下方的列表都是可點擊的。
其實,從功能角度實現上來講,其實我們用google提供的現成的控件堆以下,其實也可以寫出來。比如舉個例子啊,上面的tab就用google自己的TabLayout,下方的列表就用RecyclerView,然后把數據什么的綁定以下,點擊事件做一下,把異常處理掉,也能出來,就是說不方便二次使用。
然后實現思路:我這邊直接繼承LinearLayout,然后一個一個往里面addView就好,簡單粗暴。
Tab的話可以繼承TextView,Line的話繼承View應該也行,下面的列表就直接用RecyclerView。好了,看看如何實現吧。
Tab的實現
先thinking,我們的Tab需要有文字,選中狀態,然后應該還要一個index。看代碼:/**
*?標簽控件
*?*/
public?class?Tab?extends?TextView{
private?int?index?=?0;????????private?int?TextSelectedColor?=?Color.parseColor("#11B57C");????????private?int?TextEmptyColor?=?Color.parseColor("#333333");????????/**
*?是否選中狀態
*?*/
private?boolean?isSelected?=?false;????????public?Tab(Context?context)?{????????????super(context);
init();
}????????public?Tab(Context?context,?AttributeSet?attrs)?{????????????super(context,?attrs);
init();
}????????public?Tab(Context?context,?AttributeSet?attrs,?int?defStyleAttr)?{????????????super(context,?attrs,?defStyleAttr);
init();
}????????private?void?init(){
setTextSize(15);
}????????@Override
public?void?setText(CharSequence?text,?BufferType?type)?{????????????if(isSelected)
setTextColor(TextSelectedColor);????????????else
setTextColor(TextEmptyColor);????????????super.setText(text,?type);
}????????@Override
public?void?setSelected(boolean?selected)?{
isSelected?=?selected;
setText(getText());
}????????public?int?getIndex()?{????????????return?index;
}????????public?void?setIndex(int?index)?{????????????this.index?=?index;
}????????public?void?resetState(){
isSelected?=?false;
setText(getText());
}????????public?void?setTextSelectedColor(int?textSelectedColor)?{
TextSelectedColor?=?textSelectedColor;
}????????public?void?setTextEmptyColor(int?textEmptyColor)?{
TextEmptyColor?=?textEmptyColor;
}
}
很簡單,就是重寫一下setText,然后根據選中的狀態來設置對應的顏色即可。
實現Line
本來想了一下直接用View也能實現,但是后來想想既然要移動,有點小動畫,外層既然用了線性布局,這邊的橫線還有長度的問題,所以也直接用橫向的線性布局了。如下:/**
*?橫線控件
*?*/
private?class?Line?extends?LinearLayout{
private?int?sum?=?3;????????private?int?oldIndex?=?0;????????private?int?nowIndex?=?0;????????private?View?indicator;????????private?int?SelectedColor?=?Color.parseColor("#11B57C");????????public?Line(Context?context)?{????????????super(context);
init(context);
}????????public?Line(Context?context,?AttributeSet?attrs)?{????????????super(context,?attrs);
init(context);
}????????public?Line(Context?context,?AttributeSet?attrs,?int?defStyleAttr)?{????????????super(context,?attrs,?defStyleAttr);
init(context);
}????????private?void?init(Context?context){
setOrientation(HORIZONTAL);
setLayoutParams(new?LayoutParams(
LayoutParams.MATCH_PARENT,6));
setWeightSum(tabAmount);
indicator=?new?View(context);
indicator.setLayoutParams(new?LayoutParams(0,LayoutParams.MATCH_PARENT,1));
indicator.setBackgroundColor(SelectedColor);
addView(indicator);
}????????public?void?setIndex(int?index){????????????int?onceWidth?=?getWidth()/sum;????????????this.nowIndex?=?index;
ObjectAnimator?animator?=?ObjectAnimator.ofFloat(indicator,?"translationX",?indicator.getTranslationX(),?(nowIndex-oldIndex)*onceWidth);
animator.setDuration(300);
animator.start();
}????????public?void?setSum(int?sum)?{????????????this.sum?=?sum;
}????????public?void?setSelectedColor(int?selectedColor)?{
SelectedColor?=?selectedColor;
}
}
其實和Tab差不多,唯一不同的是需要之前選中的oldIndex,因為畢竟有個動畫嘛。public?void?setIndex(int?index){????????????int?onceWidth?=?getWidth()/sum;????????????this.nowIndex?=?index;
ObjectAnimator?animator?=?ObjectAnimator.ofFloat(indicator,?"translationX",?indicator.getTranslationX(),?(nowIndex-oldIndex)*onceWidth);
animator.setDuration(300);
animator.start();
}
看看這個接口,在設置index的同時,把移動的動畫也一起做了。
AddressSelectord 實現
因為之前就想好用繼承LinearLayout的形式,所以也簡單粗暴,直接一層一層去addView是吧,需要注意的是,這邊有個這樣的方法:/**
*?得到一個新的tab對象
*?*/
private?Tab?newTab(CharSequence?text,boolean?isSelected){
Tab?tab?=?new?Tab(mContext);
tab.setLayoutParams(new?LayoutParams(0,LayoutParams.WRAP_CONTENT,1));
tab.setGravity(Gravity.CENTER);
tab.setPadding(0,40,0,40);
tab.setSelected(isSelected);
tab.setText(text);
tab.setTextEmptyColor(TextEmptyColor);
tab.setTextSelectedColor(TextSelectedColor);
tab.setOnClickListener(this);????????return?tab;
}
看出來了吧,其實就是去創建需要的Tab,然后把點擊事件等其他參數都設置好了,主要用來AddressSelectord 內部來創建Tab時候用。
然后必要的屬性還是要提供接口設置的:/**
*?設置tab的數量,默認3個,不小于2個
*?@param?tabAmount?tab的數量
*?*/
public?void?setTabAmount(int?tabAmount)?{????????if(tabAmount?>=?2){????????????this.tabAmount?=?tabAmount;
init(mContext);
}????????else
throw?new?RuntimeException("AddressSelector?tabAmount?can?not?less-than?2?!");
}
需要設置當前tab的數量,然后看這邊又調用了init()方法,也就是說其實這個時候AddressSelectord 又重置了。所以在init()方法中有一個removeAllViews();?需要調用。
下邊兒列表的實現RecyclerView
然后一開始我就在想要不要提供什么Adapter可以讓大家自己來綁定數據,然后又想了想,為了簡單方便大家使用,所以我覺得還是暫時不寫Adapter了。但是想想每個item的Entity不應該是死的,畢竟大家的項目還是不一樣的,所以我最終采取了一種方式去實現。public?interface?CityInterface?{
String?getCityName();
}
就是這個接口了,大家在設置數據源的時候,盡管設置自己的,然后唯一需要注意的是大家的 Item需要去實現這個接口,返回我列表需要展示的文本,我用來展示列表的內容。只能要求大家做這么一點點了。所以在設置數據的時候也要求大家這么做了。/**
*?設置列表的數據源,設置后立即生效
*?*/
public?void?setCities(ArrayList?cities)?{????????if(cities?==?null||cities.size()?<=?0)????????????return;????????if(cities.get(0)?instanceof?CityInterface){????????????this.cities?=?cities;????????????if(addressAdapter?==?null){
addressAdapter?=?new?AddressAdapter();
list.setAdapter(addressAdapter);
}
addressAdapter.notifyDataSetChanged();
}else{????????????throw?new?RuntimeException("AddressSelector?cities?must?implements?CityInterface");
}
}
不然就簡單粗暴拋出throw new RuntimeException("AddressSelector cities must implements CityInterface"
這樣就好說了,我在setOnItemClickListener可以直接返回CityInterface,就解決一切問題了。
最后就是把要開放的接口開放一下,測測調調~
總結
然后,其實也是很簡單的,就是練練手,做一些讓自己和大家都覺得方便可行的事情。如果有什么地方有問題,或者有更好的建議真的很歡迎大家多多提出建議和意見,還有一句話就是說沒事不要閑著,要多動動。
總結
以上是生活随笔為你收集整理的android开发地址选择器,Android地址选择器 类似于京东的地址选择的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android四大组件 简书,andro
- 下一篇: android studio 执行不了,