亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

好用的城市選擇(三級聯動)

2019-11-06 09:57:27
字體:
來源:轉載
供稿:網友

最近公司項目中用到了關于收貨地址的功能,所以就根據實際情況剖析一下我做的三級聯動,也算是總結和回顧吧。

說起三級聯動肯定都不陌生,因為現在很多項目中都會有應用,比如 淘寶、京東、美團、餓了么等等,這些都有,我項目中做的其實就是和淘寶的差不多當然我們都叫做仿淘寶項目。廢話不多說了下面就直接上代碼,根據代碼來分析具體的用法,我們主要貼出來一些關鍵代碼。 源碼地址: http://download.csdn.net/detail/army_jun/9765371

一、首先地址頁面

package myaddressselector.myaddressselector;import android.content.Context;import android.content.Intent;import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.view.View;import android.widget.EditText;import android.widget.TextView;import android.widget.Toast;import myaddressselector.myaddressselector.callback.SelectAddressInterface;import myaddressselector.myaddressselector.view.AddressDialog;import myaddressselector.myaddressselector.view.AddressSelectorDialog;import myaddressselector.myaddressselector.view.SettingItemView;public class AddAddressActivity extends AppCompatActivity implements SelectAddressInterface { EditText mConsignee; SettingItemView mSivAddress; EditText mDetailsAddress; EditText mPostcode; EditText mPhoneNum; TextView mAddressSave; PRivate AddressSelectorDialog addressSelectorDialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_add_address); initView(); } private void initView() { mConsignee = (EditText) findViewById(R.id.consignee); mSivAddress = (SettingItemView) findViewById(R.id.siv_address); mDetailsAddress = (EditText) findViewById(R.id.details_address); mPostcode = (EditText) findViewById(R.id.postcode); mPhoneNum = (EditText) findViewById(R.id.phoneNum); mAddressSave = (TextView) findViewById(R.id.address_save); addAddressAreaData(); mAddressSave.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(AddAddressActivity.this, "已經保存了地址", Toast.LENGTH_SHORT).show(); } }); } private void addAddressAreaData() { mSivAddress.setItemT可以看到這個activity實現了一個接口,這個接口就是通過回調可以拿到的選擇后的城市數據,使用接口目的就是能夠實時的監控并得到城市改變的數據。接口代碼 SelectAddressInterface

public interface SelectAddressInterface { /** * 用于地址選擇器完成選擇后更新最新的地址 * @param area */ void setAreaString(String area); void setAreaString(String currentProvinceName, String currentCityName, String currentDistrictName, String currentZipCode); void setAreaString(String currentProvinceName, String currentCityName);}

從上面activity可以看到我把地址三級聯動選擇封裝在了一個dialog里面也就是AddressSelectorDialog 這就相當于一個工具了無論放在那個項目都可以用,只需要new一下就ok了dialog的代碼如下

package myaddressselector.myaddressselector.view;import android.content.Context;import android.os.Bundle;import android.os.Handler;import android.os.Looper;import android.view.View;import android.widget.TextView;import
java.util.ArrayList;import myaddressselector.myaddressselector.R;/** * Created by Army on 2017/2/24 */public class AddressSelectorDialog extends AddressDialog implements View.OnClickListener { private WheelView mViewProvince; private WheelView mViewCity; private WheelView mViewDistrict; private Context mContext; private TextView tvCancel; private TextView tvConfirm; protected boolean isDataLoaded = false; public AddressSelectorDialog(Context context, int themeResId) { super(context, themeResId); this.mContext = context; } public AddressSelectorDialog(Context context) { super(context); this.mContext = context; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.dialog_address); setUpViews(); setUpListener(); } private void setUpViews() { mViewProvince = (WheelView) findViewById(R.id.id_province); mViewCity = (WheelView) findViewById(R.id.id_city); mViewDistrict = (WheelView) findViewById(R.id.id_district); tvCancel = (TextView) findViewById(R.id.btn_cancel); tvConfirm = (TextView) findViewById(R.id.btn_confirm); initProvinceSelectView(); } private void setUpListener() { // 取消和確定 tvCancel.setOnClickListener(this); tvConfirm.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_cancel: if (null != listener) { listener.onCanceled(); } break; case R.id.btn_confirm: if (null != listener) { listener.onConfirmed(mCurrentProvinceName, mCurrentCityName, mCurrentDistrictName, mCurrentZipCode); } break; default: break; } } private void initProvinceSelectView() { mViewProvince.setOnSelectListener(new WheelView.OnSelectListener() { @Override public void endSelect(int id, String text) { String provinceText = mProvinceDatas.get(id); if (!mCurrentProvinceName.equals(provinceText)) { mCurrentProvinceName = provinceText; ArrayList<String> mCityData = mCitisDatasMap.get(mCurrentProvinceName); mViewCity.resetData(mCityData); mViewCity.setDefault(0); mCurrentCityName = mCityData.get(0); ArrayList<String> mDistrictData = mDistrictDatasMap.get(mCurrentCityName); mViewDistrict.resetData(mDistrictData); mViewDistrict.setDefault(0); mCurrentDistrictName = mDistrictData.get(0); } mCurrentZipCode = mZipcodeDatasMap.get(mCurrentDistrictName); } @Override public void selecting(int id, String text) { } }); mViewCity.setOnSelectListener(new WheelView.OnSelectListener() { @Override public void endSelect(int id, String text) { ArrayList<String> mCityData = mCitisDatasMap.get(mCurrentProvinceName); String cityText = mCityData.get(id); if (!mCurrentCityName.equals(cityText)) { mCurrentCityName = cityText; ArrayList<String> mCountyData = mDistrictDatasMap.get(mCurrentCityName); mViewDistrict.resetData(mCountyData); mViewDistrict.setDefault(0); mCurrentDistrictName = mCountyData.get(0); } mCurrentZipCode = mZipcodeDatasMap.get(mCurrentDistrictName); } @Override public void selecting(int id, String text) { } }); mViewDistrict.setOnSelectListener(new WheelView.OnSelectListener() { @Override public void endSelect(int id, String text) { ArrayList<String> mDistrictData = mDistrictDatasMap.get(mCurrentCityName); String districtText = mDistrictData.get(id); if (!mCurrentDistrictName.equals(districtText)) { mCurrentDistrictName = districtText; } mCurrentZipCode = mZipcodeDatasMap.get(mCurrentDistrictName); } @Override public void selecting(int id, String text) { } }); getData(); } private void getData() { // 啟動線程讀取數據 new Thread() { @Override public void run() { // 讀取數據 isDataLoaded = initProvinceDatas(); // 通知界面線程 new Handler(Looper.getMainLooper()).post(new Runnable() { @Override public void run() { setDefaultData(); } }); } }.start(); } private void setDefaultData() { mViewProvince.setData(mProvinceDatas); mViewProvince.setDefault(0); mCurrentProvinceName = mProvinceDatas.get(0); ArrayList<String> mCityData = mCitisDatasMap.get(mCurrentProvinceName); mViewCity.setData(mCityData); mViewCity.setDefault(0); mCurrentCityName = mCityData.get(0); ArrayList<String> mDistrictData = mDistrictDatasMap.get(mCurrentCityName); mViewDistrict.setData(mDistrictData); mViewDistrict.setDefault(0); mCurrentDistrictName = mDistrictData.get(0); mCurrentZipCode = mZipcodeDatasMap.get(0); }}

二、數據來源

城市的數據來源其實就是解析的xml文件 關于XML的解析,一共有SAX、PULL、DOM三種解析方式。

此次項目中使用的是SAX解析方式,因為它占用內存少,并且速度快,代碼如下

package myaddressselector.myaddressselector.service;import org.xml.sax.Attributes;import org.xml.sax.SAXException;import org.xml.sax.helpers.DefaultHandler;import java.util.ArrayList;import java.util.List;import myaddressselector.myaddressselector.bean.CityModel;import myaddressselector.myaddressselector.bean.DistrictModel;import myaddressselector.myaddressselector.bean.ProvinceModel;public class XmlParserHandler extends DefaultHandler { /** * 城市數據 */ private List<ProvinceModel> provinceList = new ArrayList<ProvinceModel>(); public XmlParserHandler() { } public List<ProvinceModel> getDataList() { return provinceList; } @Override public void startDocument() throws SAXException { } ProvinceModel provinceModel = new ProvinceModel(); CityModel cityModel = new CityModel(); DistrictModel districtModel = new DistrictModel(); @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (qName.equals("province")) { provinceModel = new ProvinceModel(); provinceModel.setName(attributes.getValue(0)); provinceModel.setCityList(new ArrayList<CityModel>()); } else if (qName.equals("city")) { cityModel = new CityModel(); cityModel.setName(attributes.getValue(0)); cityModel.setDistrictList(new ArrayList<DistrictModel>()); } else if (qName.equals("district")) { districtModel = new DistrictModel(); districtModel.setName(attributes.getValue(0)); districtModel.setZipcode(attributes.getValue(1)); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (qName.equals("district")) { cityModel.getDistrictList().add(districtModel); } else if (qName.equals("city")) { provinceModel.getCityList().add(cityModel); } else if (qName.equals("province")) { provinceList.add(provinceModel); } } @Override public void characters(char[] ch, int start, int length) throws SAXException { }}

三、造輪子

和前面的封裝一樣,這次輪子造好了以后就可以直接用了,自定義了一個滾動組件WheelView

package myaddressselector.myaddressselector.view;import android.annotation.SuppressLint;import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.LinearGradient;import android.graphics.Paint;import android.graphics.Rect;import android.graphics.Shader.TileMode;import android.os.Handler;import android.os.Message;import android.text.TextPaint;import android.text.TextUtils;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import java.util.ArrayList;import myaddressselector.myaddressselector.R;/** * WheelView滾輪 * */public class WheelView extends View { /** * 控件寬度 */ private float controlWidth; /** * 控件高度 */ private float controlHeight; /** * 是否滑動中 */ private boolean isScrolling = false; /** * 選擇的內容 */ private ArrayList<ItemObject> itemList = new ArrayList<ItemObject>(); /** * 設置數據 */ private ArrayList<String> dataList = new ArrayList<String>(); /** * 按下的坐標 */ private int downY; /** * 按下的時間 */ private long downTime = 0; /** * 短促移動 */ private long goonTime = 200; /** * 短促移動距離 */ private int goonDistence = 100; /** * 畫線畫筆 */ private Paint linePaint; /** * 線的默認顏色 */ private int lineColor = 0xff000000; /** * 線的默認寬度 */ private float lineWidth = 2f; /** * 默認字體 */ private float normalFont = 14.0f; /** * 選中的時候字體 */ private float selectedFont = 22.0f; /** * 單元格高度 */ private int unitHeight = 50; /** * 顯示多少個內容 */ private int itemNumber = 7; /** * 默認字體顏色 */ private int normalColor = 0xff000000; /** * 選中時候的字體顏色 */ private int selectedColor = 0xffff0000; /** * 蒙板高度 */ private float maskHight = 48.0f; /** * 選擇監聽 */ private OnSelectListener onSelectListener; /** * 是否可用 */ private boolean isEnable = true; /** * 刷新界面 */ private static final int REFRESH_VIEW = 0x001; /** * 移動距離 */ private static final int MOVE_NUMBER = 5; /** * 是否允許選空 */ private boolean noEmpty = true; /** * 正在修改數據,避免ConcurrentModificationException異常 */ private boolean isClearing = false; public WheelView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context, attrs); initData(); } public WheelView(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs); initData(); } public WheelView(Context context) { super(context); initData(); } @Override public boolean onTouchEvent(MotionEvent event) { if (!isEnable) return true; int y = (int) event.getY(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: isScrolling = true; downY = (int) event.getY(); downTime = System.currentTimeMillis(); break; case MotionEvent.ACTION_MOVE: actionMove(y - downY); onSelectListener(); break; case MotionEvent.ACTION_UP: int move = Math.abs(y - downY); // 判斷段時間移動的距離 if (System.currentTimeMillis() - downTime < goonTime && move > goonDistence) { goonMove(y - downY); } else { actionUp(y - downY); } noEmpty(); isScrolling = false; break; default: break; } return true; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); drawLine(canvas); drawList(canvas); drawMask(canvas); } private synchronized void drawList(Canvas canvas) { if (isClearing) return; try { for (ItemObject itemObject : itemList) { itemObject.drawSelf(canvas, getMeasuredWidth()); } } catch (Exception e) { } } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); controlWidth = getWidth(); if (controlWidth != 0) { setMeasuredDimension(getWidth(), itemNumber * unitHeight); controlWidth = getWidth(); } } /** * 繼續移動一定距離 */ private synchronized void goonMove(final int move) { new Thread(new Runnable() { @Override public void run() { int distence = 0; while (distence < unitHeight * MOVE_NUMBER) { try { Thread.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } actionThreadMove(move > 0 ? distence : distence * (-1)); distence += 10; } actionUp(move > 0 ? distence - 10 : distence * (-1) + 10); noEmpty(); } }).start(); } /** * 不能為空,必須有選項 */ private void noEmpty() { if (!noEmpty) return; for (ItemObject item : itemList) { if (item.isSelected()) return; } int move = (int) itemList.get(0).moveToSelected(); if (move < 0) { defaultMove(move); } else { defaultMove((int) itemList.get(itemList.size() - 1) .moveToSelected()); } for (ItemObject item : itemList) { if (item.isSelected()) { if (onSelectListener != null) onSelectListener.endSelect(item.id, item.itemText); break; } } } /** * 初始化數據 */ private void initData() { isClearing = true; itemList.clear(); for (int i = 0; i < dataList.size(); i++) { ItemObject itmItemObject = new ItemObject(); itmItemObject.id = i; itmItemObject.itemText = dataList.get(i); itmItemObject.x = 0; itmItemObject.y = i * unitHeight; itemList.add(itmItemObject); } isClearing = false; } /** * 移動的時候 * * @param move */ private void actionMove(int move) { for (ItemObject item : itemList) { item.move(move); } invalidate(); } /** * 移動,線程中調用 * * @param move */ private void actionThreadMove(int move) { for (ItemObject item : itemList) { item.move(move); } Message rMessage = new Message(); rMessage.what = REFRESH_VIEW; handler.sendMessage(rMessage); } /** * 松開的時候 * * @param move */ private void actionUp(int move) { int newMove = 0; if (move > 0) { for (int i = 0; i < itemList.size(); i++) { if (itemList.get(i).isSelected()) { newMove = (int) itemList.get(i).moveToSelected(); if (onSelectListener != null) onSelectListener.endSelect(itemList.get(i).id, itemList.get(i).itemText); break; } } } else { for (int i = itemList.size() - 1; i >= 0; i--) { if (itemList.get(i).isSelected()) { newMove = (int) itemList.get(i).moveToSelected(); if (onSelectListener != null) onSelectListener.endSelect(itemList.get(i).id, itemList.get(i).itemText); break; } } } for (ItemObject item : itemList) { item.newY(move + 0); } slowMove(newMove); Message rMessage = new Message(); rMessage.what = REFRESH_VIEW; handler.sendMessage(rMessage); } /** * 緩慢移動 * * @param move */ private synchronized void slowMove(final int move) { new Thread(new Runnable() { @Override public void run() { // 判斷政府 int m = move > 0 ? move : move * (-1); int i = move > 0 ? 1 : (-1); // 移動速度 int speed = 1; while (true) { m = m - speed; if (m <= 0) { for (ItemObject item : itemList) { item.newY(m * i); } Message rMessage = new Message(); rMessage.what = REFRESH_VIEW; handler.sendMessage(rMessage); try { Thread.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } break; } for (ItemObject item : itemList) { item.newY(speed * i); } Message rMessage = new Message(); rMessage.what = REFRESH_VIEW; handler.sendMessage(rMessage); try { Thread.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } } for (ItemObject item : itemList) { if (item.isSelected()) { if (onSelectListener != null) onSelectListener.endSelect(item.id, item.itemText); break; } } } }).start(); } /** * 移動到默認位置 * * @param move */ private void defaultMove(int move) { for (ItemObject item : itemList) { item.newY(move); } Message rMessage = new Message(); rMessage.what = REFRESH_VIEW; handler.sendMessage(rMessage); } /** * 滑動監聽 */ private void onSelectListener() { if (onSelectListener == null) return; for (ItemObject item : itemList) { if (item.isSelected()) { onSelectListener.selecting(item.id, item.itemText); } } } /** * 繪制線條 * * @param canvas */ private void drawLine(Canvas canvas) { if (linePaint == null) { linePaint = new Paint(); linePaint.setColor(lineColor); linePaint.setAntiAlias(true); linePaint.setStrokeWidth(lineWidth); } canvas.drawLine(0, controlHeight / 2 - unitHeight / 2 + 2, controlWidth, controlHeight / 2 - unitHeight / 2 + 2, linePaint); canvas.drawLine(0, controlHeight / 2 + unitHeight / 2 - 2, controlWidth, controlHeight / 2 + unitHeight / 2 - 2, linePaint); } /** * 繪制遮蓋板 * * @param canvas */ private void drawMask(Canvas canvas) { LinearGradient lg = new LinearGradient(0, 0, 0, maskHight, 0x00f2f2f2, 0x00f2f2f2, TileMode.MIRROR); Paint paint = new Paint(); paint.setShader(lg); canvas.drawRect(0, 0, controlWidth, maskHight, paint); LinearGradient lg2 = new LinearGradient(0, controlHeight - maskHight, 0, controlHeight, 0x00f2f2f2, 0x00f2f2f2, TileMode.MIRROR); Paint paint2 = new Paint(); paint2.setShader(lg2); canvas.drawRect(0, controlHeight - maskHight, controlWidth, controlHeight, paint2); } /** * 初始化,獲取設置的屬性 * * @param context * @param attrs */ private void init(Context context, AttributeSet attrs) { TypedArray attribute = context.obtainStyledAttributes(attrs, R.styleable.WheelView); unitHeight = (int) attribute.getDimension( R.styleable.WheelView_unitHight, 32); normalFont = attribute.getDimension( R.styleable.WheelView_normalTextSize, 14.0f); selectedFont = attribute.getDimension( R.styleable.WheelView_selectedTextSize, 22.0f); itemNumber = attribute.getInt(R.styleable.WheelView_itemNumber, 7); normalColor = attribute.getColor( R.styleable.WheelView_normalTextColor, 0xff000000); selectedColor = attribute.getColor( R.styleable.WheelView_selectedTextColor, 0xffff0000); lineColor = attribute.getColor(R.styleable.WheelView_lineColor, 0xff000000); lineWidth = attribute.getDimension(R.styleable.WheelView_lineHeight, 2f); maskHight = attribute.getDimension(R.styleable.WheelView_maskHight, 48.0f); noEmpty = attribute.getBoolean(R.styleable.WheelView_noEmpty, true); isEnable = attribute .getBoolean(R.styleable.WheelView_isEnable, true); attribute.recycle(); controlHeight = itemNumber * unitHeight; } /** * 設置數據 (第一次) * * @param data */ public void setData(ArrayList<String> data) { this.dataList = data; initData(); } /** * 重置數據 * * @param data */ public void resetData(ArrayList<String> data) { setData(data); //invalidate(); postInvalidate(); } /** * 獲取返回項 id * * @return */ public int getSelected() { for (ItemObject item : itemList) { if (item.isSelected()) return item.id; } return -1; } /** * 獲取返回的內容 * * @return */ public String getSelectedText() { for (ItemObject item : itemList) { if (item.isSelected()) return item.itemText; } return ""; } /** * 是否正在滑動 * * @return */ public boolean isScrolling() { return isScrolling; } /** * 是否可用 * * @return */ public boolean isEnable() { return isEnable; } /** * 設置是否可用 * * @param isEnable */ public void setEnable(boolean isEnable) { this.isEnable = isEnable; } /** * 設置默認選項 * * @param index */ public void setDefault(int index) { if (index > itemList.size() - 1) return; float move = itemList.get(index).moveToSelected(); defaultMove((int) move); } /** * 獲取列表大小 * * @return */ public int getListSize() { if (itemList == null) return 0; return itemList.size(); } /** * 獲取某項的內容 * * @param index * @return */ public String getItemText(int index) { if (itemList == null) return ""; return itemList.get(index).itemText; } /** * 監聽 * * @param onSelectListener */ public void setOnSelectListener(OnSelectListener onSelectListener) { this.onSelectListener = onSelectListener; } @SuppressLint("HandlerLeak") Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case REFRESH_VIEW: invalidate(); break; default: break; } } }; /** * 單條內容 * * @author JiangPing */ private class ItemObject { /** * id */ public int id = 0; /** * 內容 */ public String itemText = ""; /** * x坐標 */ public int x = 0; /** * y坐標 */ public int y = 0; /** * 移動距離 */ public int move = 0; /** * 字體畫筆 */ private TextPaint textPaint; /** * 字體范圍矩形 */ private Rect textRect; public ItemObject() { super(); } /** * 繪制自身 * * @param canvas 畫板 * @param containerWidth 容器寬度 */ public void drawSelf(Canvas canvas, int containerWidth) { if (textPaint == null) { textPaint = new TextPaint(); textPaint.setAntiAlias(true); } if (textRect == null) textRect = new Rect(); // 判斷是否被選擇 if (isSelected()) { textPaint.setColor(selectedColor); // 獲取距離標準位置的距離 float moveToSelect = moveToSelected(); moveToSelect = moveToSelect > 0 ? moveToSelect : moveToSelect * (-1); // 計算當前字體大小 float textSize = (float) normalFont + ((float) (selectedFont - normalFont) * (1.0f - (float) moveToSelect / (float) unitHeight)); textPaint.setTextSize(textSize); } else { textPaint.setColor(normalColor); textPaint.setTextSize(normalFont); } // 返回包圍整個字符串的最小的一個Rect區域 itemText = (String) TextUtils.ellipsize(itemText, textPaint, containerWidth, TextUtils.TruncateAt.END); textPaint.getTextBounds(itemText, 0, itemText.length(), textRect); // 判斷是否可視 if (!isInView()) return; // 繪制內容 canvas.drawText(itemText, x + controlWidth / 2 - textRect.width() / 2, y + move + unitHeight / 2 + textRect.height() / 2, textPaint); } /** * 是否在可視界面內 * * @return */ public boolean isInView() { if (y + move > controlHeight || (y + move + unitHeight / 2 + textRect.height() / 2) < 0) return false; return true; } /** * 移動距離 * * @param _move */ public void move(int _move) { this.move = _move; } /** * 設置新的坐標 * * @param _move */ public void newY(int _move) { this.move = 0; this.y = y + _move; } /** * 判斷是否在選擇區域內 * * @return */ public boolean isSelected() { if ((y + move) >= controlHeight / 2 - unitHeight / 2 + 2 && (y + move) <= controlHeight / 2 + unitHeight / 2 - 2) return true; if ((y + move + unitHeight) >= controlHeight / 2 - unitHeight / 2 + 2 && (y + move + unitHeight) <= controlHeight / 2 + unitHeight / 2 - 2) return true; if ((y + move) <= controlHeight / 2 - unitHeight / 2 + 2 && (y + move + unitHeight) >= controlHeight / 2 + unitHeight / 2 - 2) return true; return false; } /** * 獲取移動到標準位置需要的距離 */ public float moveToSelected() { return (controlHeight / 2 - unitHeight / 2) - (y + move); } } /** * 選擇監聽 * * @author JiangPing */ public interface OnSelectListener { /** * 結束選擇 * * @param id * @param text */ public void endSelect(int id, String text); /** * 選中的內容 * * @param id * @param text */ public void selecting(int id, String text); }}

這個自定義組件最大的好處是可以直接在布局文件中改變選擇和未選中的城市的字體大小和字體顏色非常方便這些自定義的屬性都在attr文件中

<?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" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/sc_white" android:orientation="vertical"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/btn_cancel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="15dp" android:text="取消" android:textColor="@color/text_sub" android:textSize="@dimen/text_size_small" /> <TextView android:id="@+id/btn_confirm" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:padding="15dp" android:text="確定" android:textColor="@color/text_sub" android:textSize="@dimen/text_size_small" /> </RelativeLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal"> <myaddressselector.myaddressselector.view.WheelView android:id="@+id/id_province" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" app:itemNumber="5" app:lineColor="#cccccc" app:lineHeight="1dp" app:maskHight="30dp" app:noEmpty="true" app:normalTextColor="#777" app:normalTextSize="16sp" app:selectedTextColor="#ff000000" app:selectedTextSize="22sp" app:unitHight="40dp"/> <myaddressselector.myaddressselector.view.WheelView android:id="@+id/id_city" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" app:itemNumber="5" app:lineColor="#cccccc" app:lineHeight="1dp" app:maskHight="30dp" app:noEmpty="true" app:normalTextColor="#777" app:normalTextSize="16sp" app:selectedTextColor="#ff000000" app:selectedTextSize="22sp" app:unitHight="40dp"/> <myaddressselector.myaddressselector.view.WheelView android:id="@+id/id_district" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" app:itemNumber="5" app:lineColor="#cccccc" app:lineHeight="1dp" app:maskHight="30dp" app:noEmpty="true" app:normalTextColor="#777" app:normalTextSize="16sp" app:selectedTextColor="#ff000000" app:selectedTextSize="22sp" app:unitHight="40dp"/> </LinearLayout></LinearLayout>

四、最后界面實現

) git地址:https://github.com/Army1990/AddressSelectorDemo 源碼地址:http://download.csdn.net/detail/army_jun/9765371


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
2021久久精品国产99国产精品| 色偷偷888欧美精品久久久| 亚洲免费av电影| 亚洲大胆人体视频| 2019中文字幕在线免费观看| 日韩一区在线视频| 久久成人人人人精品欧| 国产精品十八以下禁看| 精品视频久久久| 国产精品欧美在线| 亚洲欧洲午夜一线一品| 日韩精品视频中文在线观看| 9.1国产丝袜在线观看| 欧美成人手机在线| 日韩在线观看精品| 欧美电影在线观看| 国产精品私拍pans大尺度在线| 国产精品青草久久久久福利99| 97香蕉久久超级碰碰高清版| 亚洲三级黄色在线观看| 国产成人福利视频| 精品久久久久久久久国产字幕| 精品国产欧美一区二区五十路| 欧美极品美女视频网站在线观看免费| 午夜精品一区二区三区在线视| 中文字幕亚洲一区二区三区五十路| 91精品国产99久久久久久| 欧美激情精品久久久久久久变态| 日韩精品免费在线视频观看| 在线观看精品自拍私拍| 日韩在线一区二区三区免费视频| 亚洲成人激情图| 日韩精品极品在线观看播放免费视频| 久久久91精品国产一区不卡| 亚洲加勒比久久88色综合| 992tv成人免费视频| 国模精品视频一区二区三区| 国产精品久久久久久久久久久久| 国产精品成人一区| 国产女精品视频网站免费| 日韩在线观看网址| 久久久久久亚洲精品| 亚洲欧美日韩国产中文专区| 日韩久久午夜影院| 成人做爽爽免费视频| 精品国产一区av| 久久亚洲私人国产精品va| 国产精品久久久久久久9999| 亚洲精品一区在线观看香蕉| 国产亚洲成av人片在线观看桃| 亚洲国产精品久久精品怡红院| 欧美日韩一区免费| 精品女同一区二区三区在线播放| 国产精品一区二区3区| 一本色道久久88综合日韩精品| xxav国产精品美女主播| 91精品视频在线看| 中文字幕久热精品视频在线| 一本一道久久a久久精品逆3p| 久久这里有精品| 国产精品视频免费在线观看| 成人性生交大片免费观看嘿嘿视频| 欧美午夜影院在线视频| 国产视频丨精品|在线观看| 日日狠狠久久偷偷四色综合免费| 国产欧美日韩中文字幕在线| 亚洲伊人一本大道中文字幕| 成人免费自拍视频| 亚洲成人av资源网| 亚洲精品91美女久久久久久久| 久久精品视频中文字幕| 国产99久久精品一区二区永久免费| 中文字幕无线精品亚洲乱码一区| 成人av在线亚洲| 91精品视频在线播放| 97在线精品视频| 日韩欧美在线字幕| 久久久999精品免费| 91精品国产综合久久久久久蜜臀| 26uuu亚洲国产精品| 国产午夜精品理论片a级探花| 蜜臀久久99精品久久久无需会员| 国产精品老女人视频| 俺也去精品视频在线观看| 欧美日在线观看| 亚洲国产成人一区| 亚洲美女黄色片| 亚洲天堂av在线免费观看| 久久久精品2019中文字幕神马| 日韩中文字幕免费看| 欧美午夜精品久久久久久久| 久久久久久国产精品美女| 久久亚洲精品中文字幕冲田杏梨| 国产成人精品电影久久久| 一本一道久久a久久精品逆3p| 最新69国产成人精品视频免费| 国产xxx69麻豆国语对白| 中文国产成人精品久久一| 成人综合网网址| 日韩av123| 久久免费精品日本久久中文字幕| 精品国产乱码久久久久久天美| 日韩毛片在线看| 欧美日韩国产区| 亚洲国产成人精品久久久国产成人一区| 九九久久久久99精品| 日韩性生活视频| 国产精品专区第二| 深夜福利91大全| 免费91麻豆精品国产自产在线观看| 亚洲区在线播放| 日韩成人中文电影| 久久中文字幕视频| 国产精品爽爽爽爽爽爽在线观看| 欧美与黑人午夜性猛交久久久| 国产97人人超碰caoprom| 亚洲最大成人免费视频| 亚洲欧美色婷婷| 日韩av片免费在线观看| 久久久国产影院| 国产精品成人aaaaa网站| 亚洲最大福利视频网站| 欧美大全免费观看电视剧大泉洋| 91精品综合久久久久久五月天| 精品视频久久久| 日产精品99久久久久久| 懂色av影视一区二区三区| 91久久国产综合久久91精品网站| 国产精品999999| 色狠狠久久aa北条麻妃| 亚洲第一综合天堂另类专| 久久久久久免费精品| www国产亚洲精品久久网站| 深夜精品寂寞黄网站在线观看| 91嫩草在线视频| 久久伊人精品视频| 日韩中文字幕av| 色综合五月天导航| 日韩在线中文字| 国产精品最新在线观看| 2018国产精品视频| 久久久久久久久久久免费| 中文字幕视频一区二区在线有码| 欧美亚洲国产日韩2020| 性色av一区二区三区| 国产999精品| 91精品久久久久久| 亚洲国产精品电影在线观看| 国产日本欧美视频| 国产日韩av在线播放| 亚洲激情视频网站| 久久久这里只有精品视频| 国产精品一二区| 国产精品黄页免费高清在线观看| 亚洲国产成人av在线| 日本精品视频在线观看| 3344国产精品免费看| 久久6精品影院| 午夜精品99久久免费| 日韩欧美精品免费在线| 国产精品视频xxxx| 国产精品精品久久久| 亚洲精品一区在线观看香蕉| 国产成人精品一区二区在线|