Android:三级城市联动控件
来源:互联网 发布:非编软件是什么意思 编辑:程序博客网 时间:2024/05/30 23:10
import android.content.Context;import android.content.Intent;import android.os.Bundle;import android.view.Display;import android.view.Gravity;import android.view.View;import android.view.View.OnClickListener;import android.view.ViewGroup;import android.view.WindowManager;import android.widget.Button;import android.widget.TextView;import com...Contants;import com...R;import com...domain.AdressInfo;import com...ui.activity.LotteryBaseActivity;import com...ui.widget.wheel.AbstractWheelTextAdapter;import com...ui.widget.wheel.OnWheelChangedListener;import com...ui.widget.wheel.WheelView;import java.util.ArrayList;/** * 归属地选择对话框 */public class AdressDialog extends LotteryBaseActivity implements OnClickListener { private WheelView mProvinceWv, mCityWv, mCountyWv; private ArrayWheelAdapter mProvinceAdapter, mCityAdapter, mCountyAdapter; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.adressdialog); Button cancelBtn = (Button) findViewById(R.id.btn_adressdialog_cancel); cancelBtn.setOnClickListener(this); Button okBtn = (Button) findViewById(R.id.btn_adressdialog_ok); okBtn.setOnClickListener(this); WindowManager m = getWindowManager(); Display d = m.getDefaultDisplay(); android.view.WindowManager.LayoutParams p = getWindow().getAttributes(); p.y = 0; p.width = d.getWidth(); p.gravity = Gravity.BOTTOM; getWindow().setAttributes(p); String fullname = getIntent().getStringExtra("fullname"); mProvinceWv = (WheelView) findViewById(R.id.wv_adressdialog_province); mProvinceWv.setVisibleItems(5); mProvinceWv.setShowLeftLine(true); mProvinceAdapter = new ArrayWheelAdapter(this, mAdressDao.getProvinces()); mProvinceWv.setViewAdapter(mProvinceAdapter); mProvinceWv.setCyclic(true); mProvinceWv.addChangingListener(new OnWheelChangedListener() { public void onChanged(WheelView wheel, int oldValue, int newValue) { mCityAdapter = new ArrayWheelAdapter(AdressDialog.this, mAdressDao.getCitys(mProvinceAdapter.getId(mProvinceWv.getCurrentItem()))); mCityWv.setViewAdapter(mCityAdapter); mCityWv.setCurrentItem(mCityAdapter.getItemsCount() / 2); } }); mCityWv = (WheelView) findViewById(R.id.wv_adressdialog_city); mCityWv.setVisibleItems(5); mCityWv.setShowLeftLine(false); mCityAdapter = new ArrayWheelAdapter(this, mAdressDao.getCitys(mProvinceAdapter.getId(mProvinceWv.getCurrentItem()))); mCityWv.setViewAdapter(mCityAdapter); mCityWv.setCyclic(true); mCityWv.addChangingListener(new OnWheelChangedListener() { public void onChanged(WheelView wheel, int oldValue, int newValue) { mCountyAdapter = new ArrayWheelAdapter(AdressDialog.this, mAdressDao.getCountys(mCityAdapter.getId(mCityWv.getCurrentItem()))); mCountyWv.setViewAdapter(mCountyAdapter); mCountyWv.setCurrentItem(mCountyAdapter.getItemsCount() / 2); } }); mCountyWv = (WheelView) findViewById(R.id.wv_adressdialog_county); mCountyWv.setVisibleItems(5); mCountyWv.setShowLeftLine(false); mCountyAdapter = new ArrayWheelAdapter(this, mAdressDao.getCountys(mCityAdapter.getId(mCityWv.getCurrentItem()))); mCountyWv.setViewAdapter(mCountyAdapter); mCountyWv.setCyclic(true); mProvinceWv.setCurrentItem(mProvinceAdapter.getItemsCount() / 2); mCityWv.setCurrentItem(mCityAdapter.getItemsCount() / 2); mCountyWv.setCurrentItem(mCountyAdapter.getItemsCount() / 2); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_adressdialog_cancel: finish(); break; case R.id.btn_adressdialog_ok: String province = mProvinceAdapter.getItemText(mProvinceWv.getCurrentItem()).toString(); String city = mCityAdapter.getItemText(mCityWv.getCurrentItem()).toString(); String county = mCountyAdapter.getItemText(mCountyWv.getCurrentItem()).toString(); String countyFullname = mCountyAdapter.getItemFullname(mCountyWv.getCurrentItem()).toString(); Intent data = new Intent(); data.putExtra("adressName", province + " " + city + " " + county); data.putExtra("fullname", countyFullname); data.putExtra("adressId", mCountyAdapter.getCode(mCountyWv.getCurrentItem())); setResult(Contants.ACTIVITY_CODE_ADRESS, data); finish(); break; } } /** * 滑动内容adapter */ private class ArrayWheelAdapter extends AbstractWheelTextAdapter { private ArrayList<AdressInfo> infos = new ArrayList<AdressInfo>(); public int getPositionByName(String adress) { int len = infos.size(); for (int i = 0; i < len; i++) { if (adress.equals(infos.get(i).name)) { return i; } } return 0; } protected ArrayWheelAdapter(Context context) { super(context, R.layout.adressdialog_item, NO_RESOURCE); } public ArrayWheelAdapter(Context context, ArrayList<AdressInfo> infos) { super(context, R.layout.adressdialog_item, NO_RESOURCE); this.infos = infos; } @Override public View getItem(int position, View cachedView, ViewGroup parent) { View view = super.getItem(position, cachedView, parent); TextView tv = (TextView) view.findViewById(R.id.tv_adressdialog_item); tv.setText(infos.get(position).name); return view; } @Override public int getItemsCount() { return infos.size(); } @Override protected CharSequence getItemText(int position) { if (infos.size() > 0 && position < infos.size()) { return infos.get(position).name; } return ""; } public String getItemFullname(int position) { if (infos.size() > 0 && position < infos.size()) { return infos.get(position).fullname; } return ""; } public long getId(int position) { if (infos.size() > 0 && position < infos.size()) { return infos.get(position).id; } return 0; } public long getCode(int position) { if (infos.size() > 0 && position < infos.size()) { return infos.get(position).code; } return 0; } }}
adressdialog.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="wrap_content" android:background="#f0f0f0" android:orientation="vertical" > <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingBottom="5dp" android:paddingLeft="15dp" android:paddingRight="15dp" android:paddingTop="5dp" > <Button android:id="@+id/btn_adressdialog_cancel" android:layout_width="60dp" android:layout_height="40dp" android:layout_alignParentLeft="true" android:layout_centerVertical="true" android:background="@drawable/edit_bg" android:gravity="center" android:text="取消" android:textColor="#5f5f5f" android:textSize="16dp" /> <Button android:id="@+id/btn_adressdialog_ok" android:layout_width="60dp" android:layout_height="40dp" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:background="@drawable/btn_red_round_rectangle_selector" android:gravity="center" android:text="确定" android:textColor="#fdffff" android:textSize="16dp" /> </RelativeLayout> <View android:layout_width="match_parent" android:layout_height="1dp" android:background="#d7d9dc" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:weightSum="3" > <com.dacai.main.ui.widget.wheel.WheelView android:id="@+id/wv_adressdialog_province" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" /> <View android:layout_width="1dp" android:layout_height="match_parent" android:background="#d7d9dc" /> <com.dacai.main.ui.widget.wheel.WheelView android:id="@+id/wv_adressdialog_city" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" /> <View android:layout_width="1dp" android:layout_height="match_parent" android:background="#d7d9dc" /> <com.dacai.main.ui.widget.wheel.WheelView android:id="@+id/wv_adressdialog_county" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" /> </LinearLayout></LinearLayout>
package com...ui.widget.wheel;import java.util.LinkedList;import java.util.List;import android.content.Context;import android.database.DataSetObserver;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.drawable.Drawable;import android.graphics.drawable.GradientDrawable;import android.graphics.drawable.GradientDrawable.Orientation;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup.LayoutParams;import android.view.animation.Interpolator;import android.widget.LinearLayout;import com...R;import com...utils.CommonUtil;/**此类在开源的基础上做了一些修改**/public class WheelView extends View { private int[] SHADOWS_COLORS = new int[]{0xefE9E9E9, 0xcfE9E9E9, 0x3fE9E9E9}; private final int ITEM_OFFSET_PERCENT = 0; private final int PADDING = 10; private final int DEF_VISIBLE_ITEMS = 5; private int currentItem = 0; private int visibleItems = DEF_VISIBLE_ITEMS; private int itemHeight = 0; private Drawable centerDrawable; private int wheelBackground = 0; private int wheelForeground = R.drawable.adressdialog_select; private GradientDrawable topShadow; private GradientDrawable bottomShadow; private boolean drawShadows = true; private WheelScroller scroller; private boolean isScrollingPerformed; private int scrollingOffset; boolean isCyclic = false; private LinearLayout itemsLayout; private int firstItem; private WheelViewAdapter viewAdapter; private WheelRecycle recycle = new WheelRecycle(this); private List<OnWheelChangedListener> changingListeners = new LinkedList<OnWheelChangedListener>(); private List<OnWheelScrollListener> scrollingListeners = new LinkedList<OnWheelScrollListener>(); private boolean isShowLeftLine; private Context context; public WheelView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initData(context); } public WheelView(Context context, AttributeSet attrs) { super(context, attrs); initData(context); } public WheelView(Context context) { super(context); initData(context); } private void initData(Context context) { this.context = context; scroller = new WheelScroller(getContext(), scrollingListener); } public void setShowLeftLine(boolean isShowLeftLine) { this.isShowLeftLine = isShowLeftLine; } WheelScroller.ScrollingListener scrollingListener = new WheelScroller.ScrollingListener() { @Override public void onStarted() { isScrollingPerformed = true; notifyScrollingListenersAboutStart(); } @Override public void onScroll(int distance) { doScroll(distance); int height = getHeight(); if (scrollingOffset > height) { scrollingOffset = height; scroller.stopScrolling(); } else if (scrollingOffset < -height) { scrollingOffset = -height; scroller.stopScrolling(); } } @Override public void onFinished() { if (isScrollingPerformed) { notifyScrollingListenersAboutEnd(); isScrollingPerformed = false; } scrollingOffset = 0; invalidate(); } @Override public void onJustify() { if (Math.abs(scrollingOffset) > WheelScroller.MIN_DELTA_FOR_SCROLLING) { scroller.scroll(scrollingOffset, 0); } } }; public void setInterpolator(Interpolator interpolator) { scroller.setInterpolator(interpolator); } public int getVisibleItems() { return visibleItems; } public void setVisibleItems(int count) { visibleItems = count; } public WheelViewAdapter getViewAdapter() { return viewAdapter; } private DataSetObserver dataObserver = new DataSetObserver() { @Override public void onChanged() { invalidateWheel(false); } @Override public void onInvalidated() { invalidateWheel(true); } }; public void setViewAdapter(WheelViewAdapter viewAdapter) { if (this.viewAdapter != null) { this.viewAdapter.unregisterDataSetObserver(dataObserver); } this.viewAdapter = viewAdapter; if (this.viewAdapter != null) { this.viewAdapter.registerDataSetObserver(dataObserver); } invalidateWheel(true); } public void addChangingListener(OnWheelChangedListener listener) { changingListeners.add(listener); } public void removeChangingListener(OnWheelChangedListener listener) { changingListeners.remove(listener); } protected void notifyChangingListeners(int oldValue, int newValue) { for (OnWheelChangedListener listener : changingListeners) { listener.onChanged(this, oldValue, newValue); } } public void addScrollingListener(OnWheelScrollListener listener) { scrollingListeners.add(listener); } public void removeScrollingListener(OnWheelScrollListener listener) { scrollingListeners.remove(listener); } protected void notifyScrollingListenersAboutStart() { for (OnWheelScrollListener listener : scrollingListeners) { listener.onScrollingStarted(this); } } protected void notifyScrollingListenersAboutEnd() { for (OnWheelScrollListener listener : scrollingListeners) { listener.onScrollingFinished(this); } } public int getCurrentItem() { return currentItem; } public void setCurrentItem(int index, boolean animated) { if (viewAdapter == null || viewAdapter.getItemsCount() == 0) { return; } int itemCount = viewAdapter.getItemsCount(); if (index < 0 || index >= itemCount) { if (isCyclic) { while (index < 0) { index += itemCount; } index %= itemCount; } else { return; } } if (index != currentItem) { if (animated) { int itemsToScroll = index - currentItem; if (isCyclic) { int scroll = itemCount + Math.min(index, currentItem) - Math.max(index, currentItem); if (scroll < Math.abs(itemsToScroll)) { itemsToScroll = itemsToScroll < 0 ? scroll : -scroll; } } scroll(itemsToScroll, 0); } else { scrollingOffset = 0; int old = currentItem; currentItem = index; notifyChangingListeners(old, currentItem); invalidate(); } } } public void setCurrentItem(int index) { setCurrentItem(index, false); } public boolean isCyclic() { return isCyclic; } public void setCyclic(boolean isCyclic) { this.isCyclic = isCyclic; invalidateWheel(false); } public boolean drawShadows() { return drawShadows; } public void setDrawShadows(boolean drawShadows) { this.drawShadows = drawShadows; } public void setShadowColor(int start, int middle, int end) { SHADOWS_COLORS = new int[]{start, middle, end}; } public void setWheelBackground(int resource) { wheelBackground = resource; setBackgroundResource(wheelBackground); } public void setWheelForeground(int resource) { wheelForeground = resource; centerDrawable = getContext().getResources().getDrawable(wheelForeground); } public void invalidateWheel(boolean clearCaches) { if (clearCaches) { recycle.clearAll(); if (itemsLayout != null) { itemsLayout.removeAllViews(); } scrollingOffset = 0; } else if (itemsLayout != null) { recycle.recycleItems(itemsLayout, firstItem, new ItemsRange()); } invalidate(); } private void initResourcesIfNecessary() { if (centerDrawable == null) { centerDrawable = getContext().getResources().getDrawable(wheelForeground); } if (topShadow == null) { topShadow = new GradientDrawable(Orientation.TOP_BOTTOM, SHADOWS_COLORS); } if (bottomShadow == null) { bottomShadow = new GradientDrawable(Orientation.BOTTOM_TOP, SHADOWS_COLORS); } setBackgroundResource(wheelBackground); } private int getDesiredHeight(LinearLayout layout) { if (layout != null && layout.getChildAt(0) != null) { itemHeight = layout.getChildAt(0).getMeasuredHeight(); } int desired = itemHeight * visibleItems - itemHeight * ITEM_OFFSET_PERCENT / 50; return Math.max(desired, getSuggestedMinimumHeight()); } private int getItemHeight() { if (itemHeight != 0) { return itemHeight; } if (itemsLayout != null && itemsLayout.getChildAt(0) != null) { itemHeight = itemsLayout.getChildAt(0).getHeight(); return itemHeight; } return getHeight() / visibleItems; } private int calculateLayoutWidth(int widthSize, int mode) { initResourcesIfNecessary(); itemsLayout.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); itemsLayout.measure(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); int width = itemsLayout.getMeasuredWidth(); if (mode == MeasureSpec.EXACTLY) { width = widthSize; } else { width += 2 * PADDING; width = Math.max(width, getSuggestedMinimumWidth()); if (mode == MeasureSpec.AT_MOST && widthSize < width) { width = widthSize; } } itemsLayout.measure(MeasureSpec.makeMeasureSpec(width - 2 * PADDING, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); return width; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); buildViewForMeasuring(); int width = calculateLayoutWidth(widthSize, widthMode); int height; if (heightMode == MeasureSpec.EXACTLY) { height = heightSize; } else { height = getDesiredHeight(itemsLayout); if (heightMode == MeasureSpec.AT_MOST) { height = Math.min(height, heightSize); } } setMeasuredDimension(width, height); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { layout(r - l, b - t); } private void layout(int width, int height) { int itemsWidth = width - 2 * PADDING; itemsLayout.layout(0, 0, itemsWidth, height); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (viewAdapter != null && viewAdapter.getItemsCount() > 0) { updateView(); drawItems(canvas); drawCenterRect(canvas); } if (drawShadows) drawShadows(canvas); } private void drawShadows(Canvas canvas) { int height = CommonUtil.convertDipOrPx(context, 26); topShadow.setBounds(0, 0, getWidth(), height); topShadow.draw(canvas); bottomShadow.setBounds(0, getHeight() - height, getWidth(), getHeight()); bottomShadow.draw(canvas); } private void drawItems(Canvas canvas) { canvas.save(); int top = (currentItem - firstItem) * getItemHeight() + (getItemHeight() - getHeight()) / 2; canvas.translate(PADDING, -top + scrollingOffset); itemsLayout.draw(canvas); canvas.restore(); } private void drawCenterRect(Canvas canvas) { int center = getHeight() / 2; int offset = (int) (getItemHeight() / 2 * 1.2); Paint paint = new Paint(); paint.setColor(Color.parseColor("#d7d9dc")); paint.setStrokeWidth((float) CommonUtil.convertDipOrPx(context, 1)); canvas.drawLine(0, center - offset, getWidth(), center - offset, paint); canvas.drawLine(0, center + offset, getWidth(), center + offset, paint); if(isShowLeftLine){ Paint leftPaint = new Paint(); leftPaint.setColor(context.getResources().getColor(R.color.theme_red)); canvas.drawRect(0, center - offset, CommonUtil.convertDipOrPx(context, 4), center + offset, leftPaint); } } @Override public boolean onTouchEvent(MotionEvent event) { if (!isEnabled() || getViewAdapter() == null) { return true; } switch (event.getAction()) { case MotionEvent.ACTION_MOVE: if (getParent() != null) { getParent().requestDisallowInterceptTouchEvent(true); } break; case MotionEvent.ACTION_UP: if (!isScrollingPerformed) { int distance = (int) event.getY() - getHeight() / 2; if (distance > 0) { distance += getItemHeight() / 2; } else { distance -= getItemHeight() / 2; } int items = distance / getItemHeight(); } break; } return scroller.onTouchEvent(event); } private void doScroll(int delta) { scrollingOffset += delta; int itemHeight = getItemHeight(); int count = scrollingOffset / itemHeight; int pos = currentItem - count; int itemCount = viewAdapter.getItemsCount(); int fixPos = scrollingOffset % itemHeight; if (Math.abs(fixPos) <= itemHeight / 2) { fixPos = 0; } if (isCyclic && itemCount > 0) { if (fixPos > 0) { pos--; count++; } else if (fixPos < 0) { pos++; count--; } while (pos < 0) { pos += itemCount; } pos %= itemCount; } else { if (pos < 0) { count = currentItem; pos = 0; } else if (pos >= itemCount) { count = currentItem - itemCount + 1; pos = itemCount - 1; } else if (pos > 0 && fixPos > 0) { pos--; count++; } else if (pos < itemCount - 1 && fixPos < 0) { pos++; count--; } } int offset = scrollingOffset; if (pos != currentItem) { if (pos > itemCount - 1) { pos = itemCount - 1; } if (pos < 0) { pos = 0; } setCurrentItem(pos, false); } else { invalidate(); } scrollingOffset = offset - count * itemHeight; if (scrollingOffset > getHeight()) { scrollingOffset = scrollingOffset % getHeight() + getHeight(); } } public void scroll(int itemsToScroll, int time) { int distance = itemsToScroll * getItemHeight() - scrollingOffset; scroller.scroll(distance, time); } private ItemsRange getItemsRange() { if (getItemHeight() == 0) { return null; } int first = currentItem; int count = 1; while (count * getItemHeight() < getHeight()) { first--; count += 2; } if (scrollingOffset != 0) { if (scrollingOffset > 0) { first--; } count++; int emptyItems = scrollingOffset / getItemHeight(); first -= emptyItems; count += Math.asin(emptyItems); } return new ItemsRange(first, count); } private boolean rebuildItems() { boolean updated = false; ItemsRange range = getItemsRange(); if (itemsLayout != null) { int first = recycle.recycleItems(itemsLayout, firstItem, range); updated = firstItem != first; firstItem = first; } else { createItemsLayout(); updated = true; } if (!updated) { updated = firstItem != range.getFirst() || itemsLayout.getChildCount() != range.getCount(); } if (firstItem > range.getFirst() && firstItem <= range.getLast()) { for (int i = firstItem - 1; i >= range.getFirst(); i--) { if (!addViewItem(i, true)) { break; } firstItem = i; } } else { firstItem = range.getFirst(); } int first = firstItem; for (int i = itemsLayout.getChildCount(); i < range.getCount(); i++) { if (!addViewItem(firstItem + i, false) && itemsLayout.getChildCount() == 0) { first++; } } firstItem = first; return updated; } private void updateView() { if (rebuildItems()) { calculateLayoutWidth(getWidth(), MeasureSpec.EXACTLY); layout(getWidth(), getHeight()); } } private void createItemsLayout() { if (itemsLayout == null) { itemsLayout = new LinearLayout(getContext()); itemsLayout.setOrientation(LinearLayout.VERTICAL); } } private void buildViewForMeasuring() { if (itemsLayout != null) { recycle.recycleItems(itemsLayout, firstItem, new ItemsRange()); } else { createItemsLayout(); } int addItems = visibleItems / 2; for (int i = currentItem + addItems; i >= currentItem - addItems; i--) { if (addViewItem(i, true)) { firstItem = i; } } } private boolean addViewItem(int index, boolean first) { View view = getItemView(index); if (view != null) { if (first) { itemsLayout.addView(view, 0); } else { itemsLayout.addView(view); } return true; } return false; } private boolean isValidItemIndex(int index) { return viewAdapter != null && viewAdapter.getItemsCount() > 0 && (isCyclic || index >= 0 && index < viewAdapter.getItemsCount()); } private View getItemView(int index) { if (viewAdapter == null || viewAdapter.getItemsCount() == 0) { return null; } int count = viewAdapter.getItemsCount(); if (!isValidItemIndex(index)) { return viewAdapter.getEmptyItem(recycle.getEmptyItem(), itemsLayout); } else { while (index < 0) { index = count + index; } } index %= count; return viewAdapter.getItem(index, recycle.getItem(), itemsLayout); } public void stopScrolling() { scroller.stopScrolling(); }}效果图:
0 0
- Android:三级城市联动控件
- Android 城市三级联动
- Android城市三级联动选择器
- android 城市选择三级联动
- android选择城市三级联动
- Android省市区三级联动控件
- 城市三级联动
- 城市三级联动
- js 城市三级联动
- 城市的三级联动
- 城市三级联动
- 城市的三级联动
- 省份城市三级联动
- 全国城市三级联动
- 城市列表-三级联动
- 城市三级联动
- 城市三级联动
- 城市三级联动
- 数字三角形
- uml(三) 类图
- MR中的combiner问题
- laravel:路由地址和方法
- UVALive 4255 前缀和 拓扑排序
- Android:三级城市联动控件
- 用typescript写react和node是怎样的一种体验
- 打造万能的ListView GridView 适配器
- tomcat使用及常见问题
- JSONP跨域的原理解析
- linux常用命令
- Z=X+Y型概率密度的求解
- 新博客关于redis、git、nginx、mongodb、lua、python等热文
- 闭包