• 自定义控件(模仿微信ToggleButton控件)


    弄过android开发的都知道,系统有一个默认的ToggleButton,但很多人都觉得他很难看,当然也包括我。如果你感觉他不难看,那你就继续使用系统的吧,这篇文章对你来说是多余的了。

    今天来写一个模仿微信的ToggleButton控件,是啊,模仿都是模仿"大家之作",腾讯、360等等,也确实,他们设计出来的东西确实好看。

    下面看效果图打开状态,关闭状态

    先奉献上三张图片的素材,打开背景图,关闭背景图,滑块背景图。这里背景图高度是小于前两个背景图2个像素的。这样才能出现最终的打开和关闭后的滑块上下出现1个像素背景的效果。

    开始我们的控件代码,这里我们自定义一个ToggleButton控件,当然要继承自View,下面贴出我的代码

      1 public class ToggleButton extends View {
      2 
      3     private Bitmap onBackgroundImage;
      4     private Bitmap offBackgroundImage;
      5     private Bitmap blockImage;
      6     private ToggleState state = ToggleState.Open;
      7     private int currentX;
      8     private int mouseDownX = -1;
      9     private boolean isMove = false;
     10     private ToggleState preState;
     11     private boolean isInvalidate = true;
     12      public ToggleButton(Context context) {
     13      super(context);
     14      // TODO Auto-generated constructor stub
     15      }
     16 
     17     
     18     private OnClickListener clickListener = null;
     19 
     20     /*
     21      * 其实应该是stateChange事件,懒得改了
     22      */
     23     public void SetOnClickListener(OnClickListener listener) {
     24         if (listener != null)
     25             clickListener = listener;
     26     }
     27 
     28     @Override
     29     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
     30         // TODO Auto-generated method stub
     31         super.onLayout(changed, left, top, right, bottom);
     32         //layout方法是在ondraw方法之前执行,
     33         //在这个做判断是防止用户在设置Image之前setState,
     34         //这样Image为null,系统无法获取block宽度,也就无法设置currentX坐标,
     35         //系统将采用默认Open状态,会出现即使用户设置状态为close,而界面显示仍未open状态,
     36         //在这里判断,是因为当前image和state肯定已经设置完毕了
     37         if (state == ToggleState.Open) {
     38             currentX = 2;
     39         } else {
     40             if (blockImage == null || offBackgroundImage == null || onBackgroundImage == null)
     41                 return;
     42             currentX=offBackgroundImage.getWidth()-blockImage.getWidth()-2;
     43         }
     44     }
     45     public enum ToggleState {
     46         Open, Close
     47     }
     48 
     49     public ToggleButton(Context context, AttributeSet attrs) {
     50         super(context, attrs);
     51         // TODO Auto-generated constructor stub
     52     }
     53 
     54     public void setOnBackgroundResource(int id) {
     55 
     56         onBackgroundImage = BitmapFactory.decodeResource(getResources(), id);
     57     }
     58 
     59     public void setOffBackgroundResource(int id) {
     60         offBackgroundImage = BitmapFactory.decodeResource(getResources(), id);
     61 
     62     }
     63 
     64     public void setState(ToggleState state) {
     65         preState = this.state = state;
     66         if (state == ToggleState.Open) {
     67             currentX = 2;
     68         } else {
     69             if (blockImage != null && offBackgroundImage != null)
     70                 currentX = offBackgroundImage.getWidth() - blockImage.getWidth() - 2;
     71         }
     72         invalidate();
     73     }
     74 
     75     public ToggleState getState() {
     76         return state;
     77     }
     78 
     79     public void setBlockResource(int id) {
     80         blockImage = BitmapFactory.decodeResource(getResources(), id);
     81     }
     82 
     83 
     84     @Override
     85     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
     86         // TODO Auto-generated method stub
     87         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     88         setMeasuredDimension(onBackgroundImage.getWidth(), onBackgroundImage.getHeight());
     89 
     90     }
     91 
     92     @Override
     93     protected void onDraw(Canvas canvas) {
     94         // TODO Auto-generated method stub
     95         super.onDraw(canvas);
     96         // 有效性判断,如果其中有一个为空,拒绝绘制,继续绘制也没有意义
     97         if (blockImage == null || offBackgroundImage == null || onBackgroundImage == null)
     98             return;
     99         if ((currentX + blockImage.getWidth() / 2) > onBackgroundImage.getWidth() / 2) {
    100             canvas.drawBitmap(offBackgroundImage, 0, 0, null);
    101         } else {
    102             canvas.drawBitmap(onBackgroundImage, 0, 0, null);
    103         }
    104         canvas.drawBitmap(blockImage, currentX, 1, null);
    105     }
    106 
    107     @Override
    108     public boolean onTouchEvent(MotionEvent event) {
    109         currentX = (int) event.getX();
    110         switch (event.getAction()) {
    111         case MotionEvent.ACTION_DOWN:
    112             // 记录鼠标按下时的x
    113             mouseDownX = (int) event.getX();
    114             // 按下的时候不进行重绘
    115             isInvalidate = false;
    116             break;
    117         case MotionEvent.ACTION_MOVE:
    118             // 记录鼠标发生了移动
    119             isMove = true;
    120             break;
    121         case MotionEvent.ACTION_UP:
    122             // 判断鼠标按下和抬起过程中是否发生了移动
    123             // 鼠标抬起时,判断当前x坐标位置
    124             if (isMove) {
    125                 // 发生了移动,判断当前位置
    126                 if ((currentX + blockImage.getWidth() / 2) > onBackgroundImage.getWidth() / 2) {
    127                     // 背景图的后半段
    128                     currentX = onBackgroundImage.getWidth() - blockImage.getWidth();
    129                     state = ToggleState.Close;
    130                 } else {
    131                     // 背景图的前半段
    132                     currentX = 2;
    133                     state = ToggleState.Open;
    134                 }
    135             } else {
    136                 // 没有发生移动,即为点击事件,更改状态,同时改变滑块位置
    137                 if (state == ToggleState.Open) {
    138                     state = ToggleState.Close;
    139                     currentX = onBackgroundImage.getWidth() - blockImage.getWidth() - 2;
    140                 } else {
    141                     state = ToggleState.Open;
    142                     currentX = 2;
    143                 }
    144             }
    145             // 复位,以免影响下一次的触摸事件
    146             isMove = false;
    147             if (preState != state && clickListener != null) {
    148                 clickListener.onClick(this);
    149                 preState = state;
    150             }
    151             break;
    152         }
    153         if (currentX < 2)
    154             currentX = 2;
    155         if (currentX + blockImage.getWidth() >= onBackgroundImage.getWidth())
    156             currentX = onBackgroundImage.getWidth() - blockImage.getWidth() - 2;
    157         // 通知控件绘制
    158         if (isInvalidate)
    159             invalidate();
    160         else
    161             isInvalidate = true;
    162         return true;
    163     }
    164 
    165 }
    View Code

    代码里的注释够多吧,哈哈,所以就不进行讲解了。

    接下来我们在activity布局文件里面使用这个ToggleButton 控件

    1 <包名.ToggleButton 
    2         android:layout_width="wrap_content"
    3         android:layout_height="wrap_content"
    4         android:id="@+id/testToggleButton"
    5         />
    View Code

    我们在activity里面使用吧

     1 final ToggleButton toggle=(ToggleButton) findViewById(R.id.testToggleButton);
     2         toggle.setState(ToggleState.Close);
     3         toggle.setOnBackgroundResource(R.drawable.on);
     4         toggle.setOffBackgroundResource(R.drawable.off);
     5         toggle.setBlockResource(R.drawable.block);
     6         
     7         toggle.SetOnClickListener(new OnClickListener() {
     8             @Override
     9             public void onClick(View v) {
    10                 // TODO Auto-generated method stub
    11                 String state=(toggle.getState()==ToggleState.Open?"打开":"关闭");
    12                 Toast.makeText(MainActivity.this, "当前状态:"+state, Toast.LENGTH_SHORT).show();
    13             }
    14         });
    View Code

    注意啊,我上面的一行代码的位置

    toggle.setState(ToggleState.Close);

    设置状态这行代码放在了设置图片之前,但效果仍然是关闭状态。

    但ToggleButton里面如果不重写OnLayout方法,显示出来的状态就只能是打开状态。

  • 相关阅读:
    [BZOJ3829][Poi2014]FarmCraft 贪心
    【BZOJ 3144】 [Hnoi2013]切糕 真·最小割
    【BZOJ1458】士兵占领 最大流的模板题
    【COGS 14】 [网络流24题] 搭配飞行员 网络流板子题
    【BZOJ 4832】 [Lydsy2017年4月月赛] 抵制克苏恩 期望概率dp
    【BZOJ4325】NOIP2015 斗地主 搜索+贪心
    【BZOJ 1409】 Password 数论(扩展欧拉+矩阵快速幂+快速幂)
    【NOIP模拟赛】天神下凡 动态开点线段树
    【NOIP模拟赛】藏宝图 最小生成树
    【NOIP模拟赛】黑红树 期望概率dp
  • 原文地址:https://www.cnblogs.com/ljs0322/p/5717850.html
Copyright © 2020-2023  润新知