欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android自定义View实现等级滑动条的实例

程序员文章站 2023-10-26 20:40:34
 android自定义view实现等级滑动条的实例 实现效果图: 思路: 首先绘制直线,然后等分直线绘制点; 绘制点的时候把x值存到集合中...

 android自定义view实现等级滑动条的实例

实现效果图:

Android自定义View实现等级滑动条的实例

思路:

首先绘制直线,然后等分直线绘制点;

绘制点的时候把x值存到集合中。

然后绘制背景图片,以及图片上的数字。

点击事件down的时候,换小图片为大图片。move的时候跟随手指移动。

up的时候根据此时的x计算最近的集合中的点,然后自动吸附回去。

1,自定义属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
   <declare-styleable name="beautyseekbarview"> 
    <attr name="valuecountent" format="integer"/> 
     <attr name="padding" format="dimension"/>   
    <attr name="pointcolor" format="color"/> 
    <attr name="linecolor" format="color"/>
    <attr name="smallpic" format="reference"/> 
    <attr name="bigpic" format="reference"/>  
  </declare-styleable> 
</resources>

然后获取属性:

 /** 
     * 获得我们所定义的自定义样式属性 
     */ 
    typedarray a = context.gettheme().obtainstyledattributes(attrs, r.styleable.beautyseekbarview, defstyleattr, 0);
    //等级数量即点的个数
    valuecountent=a.getinteger(r.styleable.beautyseekbarview_valuecountent, 5);
    //点的颜色
    pointcolor = a.getcolor(r.styleable.beautyseekbarview_pointcolor, color.white); 
    //线的颜色
    linecolor = a.getcolor(r.styleable.beautyseekbarview_linecolor, color.white);
    //小图片
    smallpic=a.getresourceid(r.styleable.beautyseekbarview_smallpic, r.drawable.ic_launcher);
    //滑动过程中的大图片
    bigpic=a.getresourceid(r.styleable.beautyseekbarview_bigpic, r.drawable.ic_launcher);  
    //控件的内边距
    viewpadding=a.getdimensionpixelsize(r.styleable.beautyseekbarview_padding, (int) typedvalue.applydimension( 
            typedvalue.complex_unit_sp, 16, getresources().getdisplaymetrics()));

    a.recycle();    

2.绘制

@override
  protected void ondraw(canvas canvas) {
    // todo auto-generated method stub
    super.ondraw(canvas);

    float pointx = 0;
    float pointy=getheight()/2;   
    canvas.drawline(0+getpaddingleft(),pointy, getwidth()-getpaddingright(), pointy, linepaint); //绘制直线

    int averagelength =(getwidth()-getpaddingleft()-getpaddingright())/(valuecountent-1);
    for(int i=0;i<valuecountent;i++){
      pointx=i*averagelength+getpaddingleft();
      canvas.drawpoint(pointx, pointy, pointpaint);//绘制点

      if(pointlist!=null && pointlist.size()<valuecountent){
      pointlist.add(pointx);//把每个点都放入集合中;
      }      
    }
    sepoolth.release();
    canvas.drawbitmap(mbitmap, bitmappointx-bitmapwidth/2, pointy-bitmapheight/2, null);//绘制拖动的图片 
    canvas.drawtext(""+index, bitmappointx, (getheight() - fontmetrics.ascent - fontmetrics.descent) / 2, textpaint); //绘制文字
  }

全部代码如下

import java.util.arraylist;
import java.util.hashmap;
import java.util.concurrent.semaphore;


import android.r.integer;
import android.animation.valueanimator;
import android.content.context;
import android.content.res.typedarray;
import android.graphics.bitmap;
import android.graphics.bitmapfactory;
import android.graphics.canvas;
import android.graphics.color;
import android.graphics.paint;
import android.graphics.paint.fontmetricsint;
import android.util.attributeset;
import android.util.log;
import android.util.typedvalue;
import android.view.motionevent;
import android.view.view;

public class beautyseekbarview extends view {

  private semaphore sepoolth=new semaphore(0);//信号量,解决并发问题

  private int valuecountent;//等级点的数量
  private int pointcolor;
  private int linecolor;
  private bitmap mbitmap;
  private int bitmapwidth;
  private int bitmapheight;
  private float bitmappointx;
  private arraylist<float> pointlist;//储存画出的点的point值
  private hashmap<float, float> mhashmap;////把差值和listx当做键值对保存起来,便于后期找出
  private int index=1;//索引
  private float mlistx;//移动后最小的点
  private int smallpic;
  private int bigpic;
  private int viewpadding; 

  private paint pointpaint;
  private paint linepaint;
  private paint textpaint;
  private fontmetricsint fontmetrics;


  public beautyseekbarview(context context) {
    this(context,null);   
  }
  public beautyseekbarview(context context, attributeset attrs) {
    this(context, attrs,0);   
  }
  public beautyseekbarview(context context, attributeset attrs, int defstyleattr) {
    super(context, attrs, defstyleattr);        
     /** 
     * 获得我们所定义的自定义样式属性 
     */ 
    typedarray a = context.gettheme().obtainstyledattributes(attrs, r.styleable.beautyseekbarview, defstyleattr, 0);
    //等级数量即点的个数
    valuecountent=a.getinteger(r.styleable.beautyseekbarview_valuecountent, 5);
    //点的颜色
    pointcolor = a.getcolor(r.styleable.beautyseekbarview_pointcolor, color.white); 
    //线的颜色
    linecolor = a.getcolor(r.styleable.beautyseekbarview_linecolor, color.white);
    //小图片
    smallpic=a.getresourceid(r.styleable.beautyseekbarview_smallpic, r.drawable.ic_launcher);
    //滑动过程中的大图片
    bigpic=a.getresourceid(r.styleable.beautyseekbarview_bigpic, r.drawable.ic_launcher);  
    //控件的内边距
    viewpadding=a.getdimensionpixelsize(r.styleable.beautyseekbarview_padding, (int) typedvalue.applydimension( 
            typedvalue.complex_unit_sp, 16, getresources().getdisplaymetrics()));

    a.recycle();    

    initdata();//初始化数据 
    initpaint();//初始化画笔  
  }
  public void initdata() {
//   valuecountent=7;
//   pointcolor=color.white;
//   linecolor=color.white;     
//   setbackgroundcolor(color.black);    
    setpadding(viewpadding, viewpadding, viewpadding, viewpadding);
    bitmappointx=getpaddingleft();
    mbitmap=bitmapfactory.decoderesource(getresources(), smallpic);
    bitmapwidth=mbitmap.getwidth();
    bitmapheight=mbitmap.getheight();
    pointlist=new arraylist<float>();
    mhashmap=new hashmap<float, float>();
  }
  public void initpaint() {
    pointpaint=new paint();
    pointpaint.setcolor(pointcolor);
    pointpaint.setstyle(paint.style.fill);
    pointpaint.setstrokewidth(10);
    pointpaint.setstrokejoin(paint.join.round);
    pointpaint.setstrokecap(paint.cap.round);
    pointpaint.setantialias(true); 

    linepaint=new paint();
    linepaint.setcolor(linecolor);
    linepaint.setstyle(paint.style.stroke);
    linepaint.setstrokewidth(4);
    linepaint.setantialias(true); 

    textpaint=new paint();
    textpaint.setstrokewidth(3);  
    textpaint.settextsize(24);  
    textpaint.setcolor(color.white); 
    textpaint.settextalign(paint.align.center);    
    fontmetrics = textpaint.getfontmetricsint(); 
    textpaint.setantialias(true); 

  }

@override
protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
  // todo auto-generated method stub
  super.onmeasure(widthmeasurespec, heightmeasurespec);
}

  @override
  protected void ondraw(canvas canvas) {
    // todo auto-generated method stub
    super.ondraw(canvas);

    float pointx = 0;
    float pointy=getheight()/2;   
    canvas.drawline(0+getpaddingleft(),pointy, getwidth()-getpaddingright(), pointy, linepaint); //绘制直线

    int averagelength =(getwidth()-getpaddingleft()-getpaddingright())/(valuecountent-1);
    for(int i=0;i<valuecountent;i++){
      pointx=i*averagelength+getpaddingleft();
      canvas.drawpoint(pointx, pointy, pointpaint);//绘制点

      if(pointlist!=null && pointlist.size()<valuecountent){
      pointlist.add(pointx);//把每个点都放入集合中;
      }      
    }
    sepoolth.release();
    canvas.drawbitmap(mbitmap, bitmappointx-bitmapwidth/2, pointy-bitmapheight/2, null);//绘制拖动的图片 
    canvas.drawtext(""+index, bitmappointx, (getheight() - fontmetrics.ascent - fontmetrics.descent) / 2, textpaint); //绘制文字
  }

  long starttime = 0;
  @override
  public boolean ontouchevent(motionevent event) {       
        //获取手指的操作--》按下、移动、松开
        int action = event.getaction();
        switch (action) {
        case motionevent.action_down:  
          starttime=system.currenttimemillis();
          mbitmap=bitmapfactory.decoderesource(getresources(), bigpic);
          bitmapwidth=mbitmap.getwidth();
          bitmapheight=mbitmap.getheight();
          textpaint.settextsize(30); 
          //invalidate();
          break;       
        case motionevent.action_move:        
          long endtimemove=system.currenttimemillis();        
          if(endtimemove-starttime>100){//如果按下,抬起时间过大才认为是拖动,要执行动画。
           bitmappointx=event.getx();
           updateindex(bitmappointx);
           invalidate();
          }
          break;
        case motionevent.action_up:
          long endtime=system.currenttimemillis();
          bitmappointx=event.getx();
          mbitmap=bitmapfactory.decoderesource(getresources(),smallpic);
          bitmapwidth=mbitmap.getwidth();
          bitmapheight=mbitmap.getheight();
          textpaint.settextsize(24);             
          if(endtime-starttime>200){//如果按下,抬起时间过大才认为是拖动,要执行动画。
          updatebitmapui(bitmappointx);
          }else{           
            bitmappointx=updateindex(bitmappointx);
            invalidate();
          }
          starttime = 0;
          break;
        }
        return true;
  }
  //更新索引
  public float updateindex(float pointx){
    float lastvalue=100000;
    float currentvalue=0;
    float minvalue=0;
     for(float listx:pointlist){
       currentvalue= math.abs(pointx-listx);
       mhashmap.put(currentvalue, listx);//把差值和listx当做键值对保存起来,便于后期找出
       minvalue=math.min(lastvalue,currentvalue);
       lastvalue=minvalue;
      }      
    if(mhashmap.containskey(minvalue)){
      mlistx=mhashmap.get(minvalue);
    }else{
      log.e("beautyseekbarview", "updatebitmapui--->mhashmap.containskey(minvalue) is null");
      return -1;
    } 
    if(pointlist.contains(mlistx)){
    index=pointlist.indexof(mlistx)+1;
    if(mlistener!=null){
      mlistener.getindex(index);
    }
    }else{
      log.e("beautyseekbarview", "updatebitmapui--->pointlist.contains(mlistx) is null");
        return -1;
    }
    return mlistx;
  }

  //当手指抬起后更新bitmap的位置
  private void updatebitmapui(float pointx2) {
    mlistx=updateindex(pointx2);
    //执行动画   
    valueanimator anim = valueanimator.offloat(pointx2, mlistx);
    anim.setduration(50);
    anim.addupdatelistener(new valueanimator.animatorupdatelistener() {
      @override
      public void onanimationupdate(valueanimator animation) {
        bitmappointx =(float) animation.getanimatedvalue();
        invalidate();
      }
    });
    anim.start();
  }

  //设置等级点的数量
  public void pointvaluecountent(int countent){
    if(countent<2){
      valuecountent=2;
    }else{
      valuecountent=countent;
    }
    invalidate();
  }

  //设置默认位置
  public void setpointlocation(final int location){
    new thread(new runnable() {

      @override
      public void run() {       
         try {
            sepoolth.acquire();
          } catch (interruptedexception e) {
            // todo auto-generated catch block
            e.printstacktrace();
          }    
          if(location>0&&pointlist!=null&& !pointlist.isempty()){
            bitmappointx=pointlist.get(location-1);
            postinvalidate();
          }

      }
    }).start();

  }

  //提供接口回调,获取索引
  private indexlistener mlistener=null;
  public interface indexlistener{
    void getindex(int index);
  }
  public void setindexlistener(indexlistener listener){
    mlistener=listener;
  }

}

外部调用:

xml:

 <com.example.hello.beautyseekbarview 
    android:id="@+id/myview"
    android:layout_centervertical="true"
    android:layout_width="match_parent"
    android:layout_height="100dp"
    ws:padding="20dp"     
    ws:valuecountent="6"   
    ws:pointcolor="#ffffff"
    ws:linecolor="#ffffff"
    ws:smallpic="@drawable/beauty_seekbar_point"
    ws:bigpic="@drawable/beauty_seekbar_point_big"/>

java:

@override
  protected void oncreate(bundle savedinstancestate) {
    super.oncreate(savedinstancestate);  
    setcontentview(r.layout.activity_main);

   initview(); 

   beautyseekbarview.setpointlocation(2) ;
    //

  }

  private void initview() {
  mtextview=(textview) findviewbyid(r.id.tv);
  beautyseekbarview=(beautyseekbarview) findviewbyid(r.id.myview);
  beautyseekbarview.setindexlistener(new indexlistener() {  
    @override
    public void getindex(int index) {
      mtextview.settext("index="+index); 
    }
  });
  }

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!