总结一些 android 平常用到的自定义控件


1.阻尼效果listview

public class MyListView extends ListView implements Runnable {
	
	private float mLastDownY = 0f; 
    private int mDistance = 0; 
    private int mStep = 10; 
    private boolean mPositive = false; 
 

    public MyListView (Context context, AttributeSet attrs) { 
          super(context, attrs); 
    } 
 
    public MyListView (Context context, AttributeSet attrs, int defStyle) { 
          super(context, attrs, defStyle); 
    } 
 
    public MyListView (Context context) { 
          super(context); 
    } 
 
    
    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
         switch (event.getAction()) { 
              case MotionEvent.ACTION_DOWN: 
                   if (mLastDownY == 0f && mDistance == 0) { 
                         mLastDownY = event.getY(); 
                   return true; 
              } 
              break; 
		 
		      case MotionEvent.ACTION_CANCEL: 
		           break;
		
		      case MotionEvent.ACTION_UP: 
		          if (mDistance != 0) { 
		           mStep = 1; 
		           mPositive = (mDistance >= 0); 
		           this.post(this); 
		           return true; 
		        } 
		         mLastDownY = 0f; 
		         mDistance = 0; 
		         break; 
		 
		      case MotionEvent.ACTION_MOVE: 
		         if (mLastDownY != 0f) { 
		              mDistance = (int) (mLastDownY - event.getY()); 
		              if ((mDistance < 0 && getFirstVisiblePosition() == 0 && getChildAt(0).getTop() == 0) || (mDistance > 0 && getLastVisiblePosition() == getCount() - 1)) { 
		                   mDistance /= 2; 
		                   scrollTo(0, mDistance); 
		                   return true; 
		               } 
		        } 
        mDistance = 0; 
        break; 
        } 
        return super.onTouchEvent(event); 
    } 
 
    public void run() { 
          mDistance += mDistance > 0 ? -mStep : mStep; 
          scrollTo(0, mDistance); 
          if ((mPositive && mDistance <= 0) || (!mPositive && mDistance >= 0)) { 
                scrollTo(0, 0); 
                mDistance = 0; 
                mLastDownY = 0f; 
                return; 
           } 
          mStep += 1; 
          this.postDelayed(this, 10); 
     } 
} 

2.阻尼效果 scrollview

public class CustomScrollView extends ScrollView {

	private View inner;// 孩子View

	private float y;// 点击时y坐标

	private Rect normal = new Rect();// 矩形(这里只是个形式,只是用于判断是否需要动画.)

	private boolean isCount = false;// 是否开始计算

	private boolean isMoveing = false;// 是否开始移动.

	private ImageView imageView;

	private int initTop, initbottom;// 初始高度
	private int top, bottom;// 拖动时时高度。

	public void setImageView(ImageView imageView) {
		this.imageView = imageView;
	}

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

	/***
	 * 根据 XML 生成视图工作完成.该函数在生成视图的最后调用,在所有子视图添加完之后. 即使子类覆盖了 onFinishInflate
	 * 方法,也应该调用父类的方法,使该方法得以执行.
	 */
	@Override
	protected void onFinishInflate() {
		if (getChildCount() > 0) {
			inner = getChildAt(0);
		}
	}

	/** touch 事件处理 **/
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		if (inner != null) {
			commOnTouchEvent(ev);
		}
		return super.onTouchEvent(ev);
	}

	/***
	 * 触摸事件
	 * 
	 * @param ev
	 */
	public void commOnTouchEvent(MotionEvent ev) {
		int action = ev.getAction();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			top = initTop = imageView.getTop();
			bottom = initbottom = imageView.getBottom();
			break;

		case MotionEvent.ACTION_UP:

			isMoveing = false;
			// 手指松开.
			if (isNeedAnimation()) {

				animation();

			}
			break;
		/***
		 * 排除出第一次移动计算,因为第一次无法得知y坐标, 在MotionEvent.ACTION_DOWN中获取不到,
		 * 因为此时是MyScrollView的touch事件传递到到了LIstView的孩子item上面.所以从第二次计算开始.
		 * 然而我们也要进行初始化,就是第一次移动的时候让滑动距离归0. 之后记录准确了就正常执行.
		 */
		case MotionEvent.ACTION_MOVE:

			final float preY = y;// 按下时的y坐标

			float nowY = ev.getY();// 时时y坐标
			int deltaY = (int) (nowY - preY);// 滑动距离
			if (!isCount) {
				deltaY = 0; // 在这里要归0.
			}

			if (deltaY < 0 && top <= initTop)
				return;

			// 当滚动到最上或者最下时就不会再滚动,这时移动布局
			isNeedMove();

			if (isMoveing) {
				// 初始化头部矩形
				if (normal.isEmpty()) {
					// 保存正常的布局位置
					normal.set(inner.getLeft(), inner.getTop(),
							inner.getRight(), inner.getBottom());
				}

				// 移动布局
				inner.layout(inner.getLeft(), inner.getTop() + deltaY / 3,
						inner.getRight(), inner.getBottom() + deltaY / 3);

				top += (deltaY / 6);
				bottom += (deltaY / 6);
				imageView.layout(imageView.getLeft(), top,
						imageView.getRight(), bottom);
			}

			isCount = true;
			y = nowY;
			break;

		default:
			break;

		}
	}

	/***
	 * 回缩动画
	 */
	public void animation() {

		TranslateAnimation taa = new TranslateAnimation(0, 0, top + 200,
				initTop + 200);
		taa.setDuration(200);
		imageView.startAnimation(taa);
		imageView.layout(imageView.getLeft(), initTop, imageView.getRight(),
				initbottom);

		// 开启移动动画
		TranslateAnimation ta = new TranslateAnimation(0, 0, inner.getTop(),
				normal.top);
		ta.setDuration(200);
		inner.startAnimation(ta);
		// 设置回到正常的布局位置
		inner.layout(normal.left, normal.top, normal.right, normal.bottom);
		normal.setEmpty();

		isCount = false;
		y = 0;// 手指松开要归0.

	}

	// 是否需要开启动画
	public boolean isNeedAnimation() {
		return !normal.isEmpty();
	}

	/***
	 * 是否需要移动布局 inner.getMeasuredHeight():获取的是控件的总高度
	 * 
	 * getHeight():获取的是屏幕的高度
	 * 
	 * @return
	 */
	public void isNeedMove() {
		int offset = inner.getMeasuredHeight() - getHeight();
		int scrollY = getScrollY();
		// Log.e("jj", "scrolly=" + scrollY);
		// 0是顶部,后面那个是底部
		if (scrollY == 0 || scrollY == offset) {
			isMoveing = true;
		}
	}

}


3. 保证长宽比 缩放使图片不失真的 imageview

public class RoundedImageView extends ImageView {

	public RoundedImageView(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}

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

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

	@Override
	protected void onDraw(Canvas canvas) {

		Drawable drawable = getDrawable();

		if (drawable == null) {
			return;
		}

		if (getWidth() == 0 || getHeight() == 0) {
			return;
		}
		Bitmap b = ((BitmapDrawable) drawable).getBitmap();
		Bitmap bitmap = b.copy(Bitmap.Config.ARGB_8888, true);

		int w = getWidth(), h = getHeight();

		Bitmap roundBitmap = getCroppedBitmap(bitmap, w);
		canvas.drawBitmap(roundBitmap, 0, 0, null);

	}

	
	public static Bitmap getCroppedBitmap(Bitmap bmp, int radius) {
		Bitmap sbmp;
		if (bmp.getWidth() != radius || bmp.getHeight() != radius)
			sbmp = Bitmap.createScaledBitmap(bmp, radius, radius, false);
		else
			sbmp = bmp;
		Bitmap output = Bitmap.createBitmap(sbmp.getWidth(), sbmp.getHeight(),
				Config.ARGB_8888);
		Canvas canvas = new Canvas(output);

		final int color = 0xffa19774;
		final Paint paint = new Paint();
		final Rect rect = new Rect(0, 0, sbmp.getWidth(), sbmp.getHeight());

		paint.setAntiAlias(true);
		paint.setFilterBitmap(true);
		paint.setDither(true);
		canvas.drawARGB(0, 0, 0, 0);
		paint.setColor(Color.parseColor("#BAB399"));
		canvas.drawCircle(sbmp.getWidth() / 2 + 0.7f,
				sbmp.getHeight() / 2 + 0.7f, sbmp.getWidth() / 2 + 0.1f, paint);
		paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
		canvas.drawBitmap(sbmp, rect, rect, paint);

		return output;
	}

}
比如 设置 imageview的 w,h

 <com.example.view.RoundedImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:adjustViewBounds="true"
            android:maxHeight="80dip"
            android:maxWidth="80dip"
            android:src="@drawable/aa" />


3.开关按钮(为了兼容版本)


public class SlidButton extends View implements OnTouchListener {  
  
    private boolean nowChoose = false;// 记录当前按钮是否打开,true为打开,false为关闭  
    private boolean onSlip = false;// 记录用户是否在滑动  
    private float   downX, nowX; // 按下时的x,当前的x  
    private Rect    btn_on, btn_off;// 打开和关闭状态下,游标的Rect  
  
    private boolean isChgLsnOn = false;//是否设置监听  
    private OnChangedListener changedLis;  
    
    int begin,end;//控件当前的位置
    private Bitmap bg_on, bg_off, slip_btn;  
  
    public SlidButton(Context context, AttributeSet attrs) {  
        super(context, attrs);  
        init();  
    }  
  
    public SlidButton(Context context) {  
        super(context);  
        init();  
    }  
  
      
    private void init() {  
        // 载入图片资源  
        bg_on = BitmapFactory.decodeResource(getResources(),  
                R.drawable.sild_bg_on1);  
        bg_off = BitmapFactory.decodeResource(getResources(),  
                R.drawable.sild_bg_off1);  
        slip_btn = BitmapFactory.decodeResource(getResources(),  
                R.drawable.sild_bg_btn1);  
        
        
        // 获得需要的Rect数据  
        btn_on = new Rect(0, 0, slip_btn.getWidth() , slip_btn.getHeight());  
        btn_off = new Rect(bg_off.getWidth() - slip_btn.getWidth(), 0,  
                bg_off.getWidth(), slip_btn.getHeight());  
        setOnTouchListener(this);  
    }  
    
    
    
    @Override  
    protected void onDraw(Canvas canvas) {  
        super.onDraw(canvas);  
        Matrix matrix = new Matrix(); 
        begin			=this.getWidth() - bg_off.getWidth();
        end				=9;
        matrix.postTranslate(begin, end);
        Paint paint = new Paint();  
        float x;  
          
        {  
//            if (nowX<(bg_on.getWidth()/2)) //滑动到前半段与后半段的背景不同,在此做判断  
        	if(!nowChoose){
        		
        		 canvas.drawBitmap(bg_off, matrix, paint);//画出关闭时的背景  
        	}else{
        		 canvas.drawBitmap(bg_on, matrix, paint);//画出打开时的背景   
        	}  
               
                  
            if (onSlip) {//是否是在滑动状态,    
                if(nowX >= bg_on.getWidth()){
                	//是否划出指定范围,不能让游标跑到外头,必须做这个判断  
                   x = bg_on.getWidth() - slip_btn.getWidth()/2;//减去游标1/2的长度  
                
                }else{
                   x = nowX - slip_btn.getWidth() / 2;  	
                }  
                   
           
            }else {  
                if(nowChoose)//根据现在的开关状态设置画游标的位置   
                    x = btn_off.left;  
                else  
                    x = btn_on.left;  
            }  
              
            if (x < 0 ) //对游标位置进行异常判断..  
                x = 0;  
            else if(x > bg_on.getWidth() - slip_btn.getWidth())  
                x = bg_on.getWidth() - slip_btn.getWidth();  
              
            canvas.drawBitmap(slip_btn, x + begin, end, paint);//画出游标.     
        }  
    }  
  
    
    
    @Override  
    public boolean onTouch(View v, MotionEvent event) {  
          
        switch (event.getAction()) {//根据动作来执行代码  
              
            case MotionEvent.ACTION_MOVE:
                nowX = event.getX();  
                break;  
           
            case MotionEvent.ACTION_DOWN:  
                if (event.getX() < begin)   
                    return false;  
                onSlip = true;  
                downX = event.getX();  
                nowX = downX;  
                break;  
            
            case MotionEvent.ACTION_UP://松开  
                onSlip = false;  
                boolean lastChoose = nowChoose;  
                /*if (event.getX() >= begin+(bg_on.getWidth()/2))   
                    nowChoose = true;  
                else   
                    nowChoose = false; */ 
                nowChoose		=!nowChoose;
                if(isChgLsnOn && (lastChoose != nowChoose))//如果设置了监听器,就调用其方法.  
                    changedLis.OnChanged(nowChoose);  
                break;  
            default:  
                break;  
        }  
        invalidate();  
        return true;  
    }  
  
      
    public void SetOnChangedListener(OnChangedListener l){//设置监听器,当状态修改的时候  
        isChgLsnOn = true;  
        changedLis = l;  
    }  
      
    public interface OnChangedListener {  
        abstract void OnChanged(boolean checkState);  
    }  
}

            <com.view.SlidButton
                android:layout_width="50dip"
                android:layout_height="30dp"
                /> 



总结一些 android 平常用到的自定义控件,布布扣,bubuko.com

总结一些 android 平常用到的自定义控件

上一篇:Android使用JSON想服务器发送数据


下一篇:关于pip3 install virtualenvwrapper 报错:ERROR: Could not find a version that satisfies the requirement pbr (from versions: none)