MyException - 我的异常网
当前位置:我的异常网» Android » android水准循环滚动控件

android水准循环滚动控件

www.MyException.Cn  网友分享于:2013-09-10  浏览:382次
android水平循环滚动控件

CycleScrollView.java

package com.example.test;

import android.content.Context;
import android.graphics.Rect;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Scroller;

@SuppressWarnings("deprecation")
public class CycleScrollView<T> extends ViewGroup implements OnGestureListener {

    static final String TAG = "CycleScrollView";
    Context mContext;

    /**
     * Scroll velocity.
     */
    public static final long SCROLL_VELOCITY = 50;

    /**
     * Scroll offset.
     */
    public static final int SCROLL_OFFSET = -1;

    /**
     * Touch delay.
     */
    public static final long TOUCH_DELAYMILLIS = 2000;

    /**
     * Fling duration.
     */
    public static final int FLING_DURATION = 2000;

    /**
     * Filing max velocity x.
     */
    public static final int MAX_VELOCITY_X = 1000;

    private GestureDetector detector;
    private Handler mHandler;
    private Scroller mScroller;

    /**
     * Callback interface adapter and OnItemClick.
     */
    private CycleScrollAdapter<T> mAdapter;
    private OnItemClickListener mOnItemClickListener;

    /**
     * Scroll index
     */
    private int mPreIndex;
    private int mCurrentIndex;
    private int mNextIndex;
    private View mCurrentView;
    private View mPreView;
    private View mNextView;

    private float mLastMotionX;

    // The reLayout is false can not invoke onLayout.
    private boolean reLayout = false;

    // If the item count more than screen that can scroll.
    private boolean canScroll = false;

    // A flag for switch current view.
    private boolean mCurrentViewAtLeft = true;

    // Fling distance.
    private int mFlingX = 0;

    private boolean isMoveAction = false;

    private int defaultItemY = 10;
        
    private int maxItemCount = 7;

    private int initItemX = 20;

    /**
     * The screen width.
     */
    private int screenWidth;

    /**
     * Item view height.
     */
    private int itemHeight;

    /**
     * Item view width.
     */
    private int itemWidth;

    /**
     * Item view layout x.
     */
    private int itemX = getInitItemX();

    /**
     * Item view layout y.
     */
    private int itemY = defaultItemY;

    // Auto scroll view task.
    private final Runnable mScrollTask = new Runnable() {

        @Override
        public void run() {
            if (canScroll) {
                scrollView(SCROLL_OFFSET);
                mHandler.postDelayed(this, SCROLL_VELOCITY);// Loop self.
            }
        }
    };

    public CycleScrollView(Context context) {
        super(context);
        onCreate(context);
    }

    public CycleScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        onCreate(context);
    }

    public CycleScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        onCreate(context);
    }

    private void onCreate(Context context) {
        mContext = context;
        detector = new GestureDetector(this);
        mHandler = new Handler();
        mScroller = new Scroller(context);
    }

    /**
     * Create scroll index.
     */
    public void createIndex() {
        if (canScroll) {
            mPreIndex = maxItemCount - 1;
            mCurrentIndex = 0;
            mNextIndex = 1;
            mPreView = getChildAt(mPreIndex);
            mCurrentView = getChildAt(mCurrentIndex);
            mNextView = getChildAt(mNextIndex);
        }
    }

    /**
     * Set item click callback.
     * 
     * @param onItemClickListener
     *            The callback
     */
    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        mOnItemClickListener = onItemClickListener;
    }

    /**
     * Set itemAdapter for addItem and bindItem.
     * 
     * @param itemAdapter
     */
    public void setAdapter(CycleScrollAdapter<T> adapter) {
        mAdapter = adapter;
    }

    /**
     * Start auto scroll.
     */
    public void startScroll() {
        if (canScroll) {
            mHandler.post(mScrollTask);
        }
    }

    /**
     * Stop auto scroll and filing scroll task.
     */
    public void stopScroll() {
        mHandler.removeCallbacks(mScrollTask);
    }

    /**
     * Delay start auto scroll task.
     */
    public void delayStartScroll() {
        if (canScroll) {
            mHandler.postDelayed(mScrollTask, TOUCH_DELAYMILLIS);
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int count = this.getChildCount();
        for (int i = 0; i < count; i++) {
            View child = this.getChildAt(i);
            child.measure(widthMeasureSpec, heightMeasureSpec);
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        /**
         * On layout set the child view layout by x y width and height.
         */
        if (reLayout) {// Run one times.
            for (int i = 0; i < getChildCount(); i++) {
                View child = this.getChildAt(i);
                child.setVisibility(View.VISIBLE);
                child.layout(itemX, getItemY(), itemX + getItemWidth(),
                        getItemY() + getItemHeight());
                itemX += getItemMargin();
            }
            reLayout = !reLayout;
        }
    }

    /**
     * When fling view run the fling task scroll view.
     */
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
            float velocityY) {

        if (e1 == null || e2 == null) {
            return false;
        }

        // When deltaX and velocityX not good return false.
        if (Math.abs(velocityX) < MAX_VELOCITY_X) {
            return false;
        }

        // Get the delta x.
        float deltaX = (e1.getX() - e2.getX());

        /**
         * If can fling stop other scroll task at first , delay the task after
         * fling.
         */
        mHandler.removeCallbacks(mScrollTask);
        if (canScroll) {
            mHandler.postDelayed(mScrollTask, TOUCH_DELAYMILLIS
                    + FLING_DURATION - 1000);
        }

        /**
         * The flingX is fling distance.
         */
        mFlingX = (int) deltaX;

        // Start scroll with fling x.
        mScroller.startScroll(0, 0, mFlingX, 0, FLING_DURATION);
        return false;
    }

    @Override
    public void computeScroll() {
        if (canScroll && mScroller.computeScrollOffset()) {
            /**
             * The Scroller.getCurrX() approach mFlingX , the deltaX more and
             * more small.
             */
            int deltaX = mFlingX - mScroller.getCurrX();
            scrollView(-deltaX / 10);
            postInvalidate();
        }
    }

    /**
     * When touch event is move scroll child view.
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {

        // Get event x,y at parent view.
        final float x = ev.getX();

        /**
         * Get event x,y at screen.
         */
        final int rawX = (int) ev.getRawX();
        final int rawY = (int) ev.getRawY();

        switch (ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            // Reset isMoveAction.
            isMoveAction = false;
            // Get motionX.
            mLastMotionX = x;
            break;
        case MotionEvent.ACTION_MOVE:
            // When action move set isMoveAction true.
            isMoveAction = true;
            // Only support one pointer.
            if (ev.getPointerCount() == 1) {
                // Compute delta X.
                int deltaX = 0;
                deltaX = (int) (x - mLastMotionX);
                mLastMotionX = x;
                // When canScroll is true, scrollView width deltaX.
                if (canScroll) {
                    scrollView(deltaX);
                }
            }
            break;
        case MotionEvent.ACTION_UP:
            /**
             * If not move find click item and invoke click event.
             */
            if (!isMoveAction) {
                View view = getClickItem(rawX, rawY);
                if (view != null) {
                    mOnItemClickListener.onItemClick(Integer.valueOf(view
                            .getTag().toString()));
                }
            }
            break;
        }
        return this.detector.onTouchEvent(ev);
    }

    /**
     * Get click item view by rawX and rawY.
     * @param rawX the x at screen.
     * @param rawY the y at screen.
     * @return the click item view.
     */
    private View getClickItem(final int rawX, final int rawY) {
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            // Get item view rect.
            Rect rect = new Rect();
            child.getGlobalVisibleRect(rect);
            // If click point on the item view, invoke the click event.
            if (rect.contains(rawX, rawY)) {
                return child;
            }
        }
        return null;
    }

    /**
     * Scroll view by delta x.
     * 
     * @param deltaX
     *            The scroll distance.
     */
    private void scrollView(int deltaX) {
        // Move child view by deltaX.
        moveChildView(deltaX);
        // After move change index.
        if (deltaX < 0) {// move left
            // If current at right switch current view to left.
            switchCurrentViewToLeft();
            // change previous current next index.
            moveToNext();
        } else {// move right
            // If current at left switch current view to right.
            switchCurrentViewToRight();
            // change previous current next index.
            moveToPre();
        }
        invalidate();
    }

    /**
     * Move view by delta x.
     * 
     * @param deltaX
     *            The move distance.
     */
    private void moveChildView(int deltaX) {
        for (int i = 0; i < getChildCount(); i++) {
            View child = getChildAt(i);
            child.layout(child.getLeft() + deltaX, child.getTop(),
                    child.getRight() + deltaX, child.getBottom());
        }
    }

    /**
     * Current event is move to left, if current view at right switch current
     * view to left.
     */
    private void switchCurrentViewToLeft() {
        if (!mCurrentViewAtLeft) {
            mPreIndex = mCurrentIndex;
            mCurrentIndex = mNextIndex;
            mNextIndex++;
            if (mNextIndex > maxItemCount - 1) {
                mNextIndex = 0;
            }
            mCurrentView = getChildAt(mCurrentIndex);
            mPreView = getChildAt(mPreIndex);
            mNextView = getChildAt(mNextIndex);
            mCurrentViewAtLeft = !mCurrentViewAtLeft;
        }
    }

    /**
     * Current event is move to right, if current view at left switch current
     * view to right.
     */
    private void switchCurrentViewToRight() {
        if (mCurrentViewAtLeft) {
            mNextIndex = mCurrentIndex;
            mCurrentIndex = mPreIndex;
            mPreIndex--;
            if (mPreIndex < 0) {
                mPreIndex = maxItemCount - 1;
            }
            mCurrentView = getChildAt(mCurrentIndex);
            mPreView = getChildAt(mPreIndex);
            mNextView = getChildAt(mNextIndex);
            mCurrentViewAtLeft = !mCurrentViewAtLeft;
        }
    }

    /**
     * Current event is move to left,if current view move out of screen move the
     * current view to right and reBind the item change index.
     */
    private void moveToNext() {
        if (mCurrentView.getRight() < 0) {
            mCurrentView.layout(mPreView.getLeft() + getItemMargin(),
                    getItemY(), mPreView.getLeft() + getItemMargin()
                            + getItemWidth(), getItemY() + getItemHeight());

            if (mCurrentView.getTag() != null) {
                int listIndex = (Integer) mCurrentView.getTag();
                int index = (listIndex + maxItemCount) % mAdapter.getCount();
                mAdapter.bindView(mCurrentView, mAdapter.get(index));
                mCurrentView.setTag(index);
            }

            mPreIndex = mCurrentIndex;
            mCurrentIndex = mNextIndex;
            mNextIndex++;
            if (mNextIndex > maxItemCount - 1) {
                mNextIndex = 0;
            }
            mCurrentView = getChildAt(mCurrentIndex);
            mPreView = getChildAt(mPreIndex);
            mNextView = getChildAt(mNextIndex);
            moveToNext();
        }
    }

    /**
     * Current event is move to right,if current view move out of screen move
     * the current view to left and reBind the item change index.
     */
    private void moveToPre() {
        if (mCurrentView.getLeft() > getScreenWidth()) {
            mCurrentView.layout(mNextView.getLeft() - getItemMargin(),
                    getItemY(), mNextView.getLeft() - getItemMargin()
                            + getItemWidth(), getItemY() + getItemHeight());

            if (mCurrentView.getTag() != null) {
                int listIndex = (Integer) mCurrentView.getTag();
                int index = (listIndex - maxItemCount + mAdapter.getCount())
                        % mAdapter.getCount();
                mAdapter.bindView(mCurrentView, mAdapter.get(index));
                mCurrentView.setTag(index);
            }

            mNextIndex = mCurrentIndex;
            mCurrentIndex = mPreIndex;
            mPreIndex--;
            if (mPreIndex < 0) {
                mPreIndex = maxItemCount - 1;
            }
            mCurrentView = getChildAt(mCurrentIndex);
            mPreView = getChildAt(mPreIndex);
            mNextView = getChildAt(mNextIndex);
            moveToPre();
        }
    }

    @Override
    public boolean onDown(MotionEvent e) {
        return true;
    }

    @Override
    public void onShowPress(MotionEvent e) {
    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        return false;
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
            float distanceY) {
        return false;
    }

    @Override
    public void onLongPress(MotionEvent e) {
    }

    public int getMaxItemCount() {
        return maxItemCount;
    }

    public void setMaxItemCount(int maxItemCount) {
        this.maxItemCount = maxItemCount;
    }

    public void setReLayout(boolean reLayout) {
        this.reLayout = reLayout;
    }

    public void setCanScroll(boolean canScroll) {
        this.canScroll = canScroll;
    }

    public int getItemX() {
        return itemX;
    }

    public void setItemX(int itemX) {
        this.itemX = itemX;
    }

    public int getItemY() {
        return itemY;
    }

    public void setItemY(int itemY) {
        this.itemY = itemY;
    }

    public int getItemWidth() {
        return itemWidth;
    }

    public void setItemWidth(int itemWidth) {
        this.itemWidth = itemWidth;
    }

    public int getItemHeight() {
        return itemHeight;
    }

    public void setItemHeight(int itemHeight) {
        this.itemHeight = itemHeight;
    }

    public int getItemMargin() {
        return (screenWidth - itemWidth * (maxItemCount - 1) - initItemX * 2)/(maxItemCount - 2) + itemWidth;
    }

    public int getScreenWidth() {
        return screenWidth;
    }

    public void setScreenWidth(int screenWidth) {
        this.screenWidth = screenWidth;
    }

    public int getInitItemX() {
        return initItemX;
    }

    public void setInitItemX(int initItemX) {
        this.initItemX = initItemX;
    }

    /**
     * The interface for item click callback.
     */
    interface OnItemClickListener {
        public boolean onItemClick(int position);
    }

}

CycleScrollAdapter.java

package com.example.test;

import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.util.DisplayMetrics;
import android.view.View;

public abstract class CycleScrollAdapter<T> {

    private List<T> list;
    private CycleScrollView<T> mCycleScrollView;
    Context mContext;

    /**
     * Initial CycleScrollAdapter bind list to view.
     * 
     * @param list
     *            The list data.
     * @param cycleScrollView
     *            The CycleScrollView.
     * @param context
     *            The Context.
     */
    public CycleScrollAdapter(List<T> list, CycleScrollView<T> cycleScrollView,
            Context context) {
        this.list = list;
        mContext = context;
        mCycleScrollView = cycleScrollView;
        mCycleScrollView.setAdapter(this);
        GetScreenWidthPixels();
        initView(list);
    }

    /**
     * Get screen width pixels.
     */
    private void GetScreenWidthPixels() {
        DisplayMetrics dm = new DisplayMetrics();  
        Activity a = (Activity) mContext;
        a.getWindowManager().getDefaultDisplay().getMetrics(dm);  
        mCycleScrollView.setScreenWidth(dm.widthPixels);
    }

    /**
     * Bind list to view.
     * 
     * @param list
     *            The list data.
     */
    protected void initView(List<T> list) {
        if (list == null || list.size() == 0) {
            return;
        }
        
        // Clear all view from ViewGroup at first.
        mCycleScrollView.removeAllViewsInLayout();

        // Loop list.
        for (int i = 0; i < list.size(); i++) {
            /**
             * If list size more than MaxItemCount break the loop, only create
             * view count is MaxItemCount.
             */
            if (i == mCycleScrollView.getMaxItemCount()) {
                break;
            }

            /**
             * If list size less than MaxItemCount at the last loop reLayout
             * otherwise at the MaxItemCount index reLayout.
             */
            if (i == list.size() - 1
                    || i == mCycleScrollView.getMaxItemCount() - 1) {
                mCycleScrollView.setItemX(mCycleScrollView.getInitItemX());
                mCycleScrollView.setReLayout(true);
            }
            add(list.get(i), i);
        }

        /**
         * If list count more than MaxItemCount the view can scroll otherwise
         * can not scroll.
         */
        if (list.size() >= mCycleScrollView.getMaxItemCount()) {
            mCycleScrollView.setCanScroll(true);
        } else {
            mCycleScrollView.setCanScroll(false);
        }

        /**
         * If list count more than MaxItemCount reBuild index.
         */
        mCycleScrollView.createIndex();
    }

    /**
     * Get list size.
     * 
     * @return The list size.
     */
    public int getCount() {
        return list.size();
    }

    /**
     * Returns the element at the specified location in this
     * 
     * @param index
     *            the index of the element to return.
     * @return the element at the specified location.
     */
    public T get(int index) {
        return list.get(index);
    }

    /**
     * Adds the specified object at the end of this and refresh view.
     * 
     * @param t
     *            the object to add.
     */
    public void addItem(T t) {
        list.add(t);
        initView(list);
    }

    /**
     * Removes the first occurrence of the specified object from this and
     * refresh view.
     * 
     * @param t
     *            the object to remove.
     */
    public void removeItem(T t) {
        list.remove(t);
        initView(list);
    }

    /**
     * Add the specified view to the index.
     * 
     * @param t
     *            The data to add.
     * @param index
     *            the index.
     */
    private void add(T t, int index) {
        View view = getView(t);
        ComputeItemSize(view);
        mCycleScrollView.addView(view);
        view.setTag(index);
    }

    /**
     * If item size is null compute item size.
     * 
     * @param view
     *            the item view.
     */
    private void ComputeItemSize(View view) {
        if (mCycleScrollView.getItemWidth() == 0
                || mCycleScrollView.getItemHeight() == 0) {
            int w = View.MeasureSpec.makeMeasureSpec(0,
                    View.MeasureSpec.UNSPECIFIED);
            int h = View.MeasureSpec.makeMeasureSpec(0,
                    View.MeasureSpec.UNSPECIFIED);
            view.measure(w, h);
            int height = view.getMeasuredHeight();
            int width = view.getMeasuredWidth();
            mCycleScrollView.setItemHeight(height);
            mCycleScrollView.setItemWidth(width);
        }
    }

    /**
     * Get item view.
     * 
     * @param t
     *            the data need bind to view.
     * @return the view.
     */
    public abstract View getView(T t);

    /**
     * Bind the item to view.
     * 
     * @param child
     *            the item view need bind.
     * @param t
     *            the item.
     */
    public abstract void bindView(View child, T t);
}
以上两个是核心类,下面是测试代码。

实现CycleScrollAdapter

AppCycleScrollAdapter.java绑定视图和应用数据

package com.example.test;

import java.util.List;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

public class AppCycleScrollAdapter extends CycleScrollAdapter<PackageInfo> {
    
    public AppCycleScrollAdapter(List<PackageInfo> list,
            CycleScrollView<PackageInfo> cycleScrollView, Context context) {
        super(list, cycleScrollView, context);
    }
    
    @Override
    protected void initView(List<PackageInfo> list) {
        super.initView(list);
    }

    @Override
    public void bindView(View child, PackageInfo pi) {
        ImageView image = (ImageView) child.findViewById(R.id.item_image);
        TextView text = (TextView) child.findViewById(R.id.item_text);
        image.setImageDrawable(pi.applicationInfo.loadIcon(mContext
                .getPackageManager()));
        text.setText(pi.applicationInfo.loadLabel(mContext.getPackageManager()));  
    }

    @Override
    public View getView(PackageInfo pi) {
        View view = View.inflate(mContext, R.layout.view_item, null);
        // inflate APP icon view
        ImageView image = (ImageView) view.findViewById(R.id.item_image);
        // inflate APP name view
        TextView text = (TextView) view.findViewById(R.id.item_text);
        image.setImageDrawable(pi.applicationInfo.loadIcon(mContext
                .getPackageManager()));
        text.setText(pi.applicationInfo.loadLabel(mContext.getPackageManager()));
        return view;
    }
}

入口Activity

package com.example.test;


import java.util.List;


import android.app.Activity;
import android.content.pm.PackageInfo;
import android.os.Bundle;
import android.view.Menu;

public class MainActivity extends Activity{
   
    private CycleScrollView<PackageInfo> mCycleScrollView;
    private AppCycleScrollAdapter mAdapter;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        mCycleScrollView = ((CycleScrollView<PackageInfo>) this.findViewById(R.id.cycle_scroll_view));

        /**
         * Get APP list and sort by update time.
         */
        List<PackageInfo> list = this.getPackageManager()
                .getInstalledPackages(0);

        mAdapter = new AppCycleScrollAdapter(list, mCycleScrollView, this);
        
    }
    


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }

}

布局文件

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

    <ImageView
        android:id="@+id/item_image"
        android:layout_width="60dip"
        android:layout_height="60dip"
        android:layout_y="5dip"
        android:layout_x="10dip"
         />

    <TextView
        android:id="@+id/item_text"
        android:layout_width="80dip"
        android:layout_height="20dip"
        android:layout_y="65dip"
        android:layout_x="0dip"
        android:gravity="center_horizontal" />

</AbsoluteLayout>
<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" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="@string/hello_world"
        tools:context=".MainActivity" />
    
		<com.example.test.CycleScrollView
        android:id="@+id/cycle_scroll_view"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="#B9000000"
        />

</RelativeLayout>



文章评论

程序员和编码员之间的区别
程序员和编码员之间的区别
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
程序员的鄙视链
程序员的鄙视链
总结2014中国互联网十大段子
总结2014中国互联网十大段子
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
如何成为一名黑客
如何成为一名黑客
一个程序员的时间管理
一个程序员的时间管理
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
5款最佳正则表达式编辑调试器
5款最佳正则表达式编辑调试器
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
如何区分一个程序员是“老手“还是“新手“?
如何区分一个程序员是“老手“还是“新手“?
10个调试和排错的小建议
10个调试和排错的小建议
旅行,写作,编程
旅行,写作,编程
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
程序员必看的十大电影
程序员必看的十大电影
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
中美印日四国程序员比较
中美印日四国程序员比较
为什么程序员都是夜猫子
为什么程序员都是夜猫子
程序员都该阅读的书
程序员都该阅读的书
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
编程语言是女人
编程语言是女人
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
老程序员的下场
老程序员的下场
我的丈夫是个程序员
我的丈夫是个程序员
10个帮程序员减压放松的网站
10个帮程序员减压放松的网站
程序员应该关注的一些事儿
程序员应该关注的一些事儿
代码女神横空出世
代码女神横空出世
初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
那些争议最大的编程观点
那些争议最大的编程观点
每天工作4小时的程序员
每天工作4小时的程序员
我是如何打败拖延症的
我是如何打败拖延症的
 程序员的样子
程序员的样子
鲜为人知的编程真相
鲜为人知的编程真相
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
漫画:程序员的工作
漫画:程序员的工作
团队中“技术大拿”并非越多越好
团队中“技术大拿”并非越多越好
Java程序员必看电影
Java程序员必看电影
我跳槽是因为他们的显示器更大
我跳槽是因为他们的显示器更大
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有