欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android自定義控件實(shí)現(xiàn)可左右滑動(dòng)的導(dǎo)航條

 更新時(shí)間:2020年04月08日 11:04:39   作者:鳳求凰丶  
這篇文章主要介紹了Android自定義控件實(shí)現(xiàn)可左右滑動(dòng)的導(dǎo)航條,能響應(yīng)快速滑動(dòng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

本文實(shí)例為大家分享了Android實(shí)現(xiàn)可左右滑動(dòng)導(dǎo)航條的具體代碼,供大家參考,具體內(nèi)容如下

先上效果圖:

這個(gè)控件其實(shí)算是比較輕量級(jí)的,相信不少小伙伴都能做出來(lái)。因?yàn)轫?xiàng)目中遇到了一些特殊的定制要求,所以就自己寫(xiě)了一個(gè),這里放出來(lái)。

首先來(lái)分析下這個(gè)控件的功能:

•能夠響應(yīng)左右滑動(dòng),并且能響應(yīng)快速滑動(dòng)
•選擇項(xiàng)和未選擇項(xiàng)有不同的樣式表現(xiàn),比如前景色,背景色,字體大小變粗之內(nèi)的
•在切換選項(xiàng)的時(shí)候,如果當(dāng)前選項(xiàng)未完全呈現(xiàn)在界面前,則自動(dòng)滾動(dòng)直至當(dāng)前選項(xiàng)完全暴露顯示

前兩條還有,簡(jiǎn)簡(jiǎn)單單就實(shí)現(xiàn)了,主要是第三點(diǎn),這才是我自定義這個(gè)控件的原因!那么如果要實(shí)現(xiàn)這個(gè)控件,需要用到哪些知識(shí)呢? 
•用Scroller來(lái)實(shí)現(xiàn)控件的滾動(dòng)
•用VelocityTracker來(lái)實(shí)現(xiàn)控件的快速滾動(dòng) 

如果上面兩種技術(shù)你都已經(jīng)會(huì)了,那么我們就可以開(kāi)始講解代碼了。首先是一些屬性的Getter/Setter方法,這里采用的鏈?zhǔn)皆O(shè)置法:

 public IndicatorView color(int colorDefault, int colorSelected, int colorBg){
 this.colorDefault = colorDefault;
 this.colorSelected = colorSelected;
 this.colorBg = colorBg;
 return this;
 }

 public IndicatorView textSize(int textSize){
 this.textSize = textSize;
 return this;
 }

 public IndicatorView text(String[] texts){
 this.texts = texts;
 return this;
 }

 public IndicatorView padding(int[] padding){
 this.padding = padding;
 return this;
 }

 public IndicatorView defaultSelect(int defaultSelect){
 this.selectItem = defaultSelect;
 return this;
 }

 public IndicatorView lineHeight(int lineHeight){
 this.lineHeight = lineHeight;
 return this;
 }

 public IndicatorView listener(OnIndicatorChangedListener listener){
 this.listener = listener;
 return this;
 }

 public IndicatorView type(Type type){
 this.type = type;
 return this;
 }

這里我們將每一個(gè)選項(xiàng)抽象成了一個(gè)Item類(lèi):

 public class Item {
 String text;
 int colorDefault;
 int colorSelected;
 int textSize;
 boolean isSelected = false;
 int width;
 Point drawPoint;
 int[] padding = new int[4];
 Rect rect = new Rect();
 }

然后是控件的初始化操作,主要根據(jù)當(dāng)前控件的寬高,以及設(shè)置的一些屬性,進(jìn)行Item選項(xiàng)的初始化:

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
 width = MeasureSpec.getSize(widthMeasureSpec);
 height = MeasureSpec.getSize(heightMeasureSpec);
 //初始化Item
 initItems();
 super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 }

 private void initItems(){
 items.clear();
 measureWidth = 0;
 for(int i = 0; i < texts.length; i++){
  Item item = new Item();
  item.text = texts[i];
  item.colorDefault = colorDefault;
  item.colorSelected = colorSelected;
  item.textSize = textSize;
  for(int j = 0; j < item.padding.length; j++){
  item.padding[j] = padding[j];
  }
  mPaint.setTextSize(item.textSize);
  item.width = (int)mPaint.measureText(item.text);
  int dx = 0;
  if(i - 1 < 0){
  dx = 0;
  }else{
  for(int j = 0; j < i; j++){
   dx += items.get(j).padding[0] + items.get(j).width + items.get(j).padding[2];
  }
  }
  int startX = item.padding[0] + dx;
  Paint.FontMetrics metrics = mPaint.getFontMetrics();
  int startY = (int)(height / 2 + (metrics.bottom - metrics.top) / 2 - metrics.bottom);
  item.drawPoint = new Point(startX, startY);
  //設(shè)置區(qū)域
  item.rect.left = item.drawPoint.x - item.padding[0];
  item.rect.top = 0;
  item.rect.right = item.drawPoint.x + item.width + item.padding[2];
  item.rect.bottom = height;
  //設(shè)置默認(rèn)
  if(i == selectItem){
  item.isSelected = true;
  }
  measureWidth += item.rect.width();
  items.add(item);
 }
 //重繪
 invalidate();
 }

 接下來(lái)是事件處理,邏輯很簡(jiǎn)單。在DOWN時(shí)間記錄坐標(biāo)值,在MOVE中處理控件的滾動(dòng),在UP中處理滾動(dòng)超屏?xí)r的恢復(fù)操作,以及點(diǎn)擊的操作。

 @Override
 public boolean onTouchEvent(MotionEvent event){
 if(mVelocityTracker == null) {
  mVelocityTracker = VelocityTracker.obtain();
 }
 mVelocityTracker.addMovement(event);
 switch(event.getAction()){
  case MotionEvent.ACTION_DOWN:
  mTouchX = (int)event.getX();
  mTouchY = (int)event.getY();
  mMoveX = mTouchX;
  return true;

  case MotionEvent.ACTION_MOVE:
  if(measureWidth > width){
   int dx = (int)event.getX() - mMoveX;
   if(dx > 0){ // 右滑
   if(mScroller.getFinalX() > 0){
    mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), -dx, 0);
   }else{
    mScroller.setFinalX(0);
   }
   }else{ //左滑
   if(mScroller.getFinalX() + width - dx < measureWidth){
    mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), -dx, 0);
   }else{
    mScroller.setFinalX(measureWidth - width);
   }
   }
   mMoveX = (int)event.getX();
   invalidate();
  }
  break;

  case MotionEvent.ACTION_UP:
  case MotionEvent.ACTION_CANCEL:
  if(measureWidth > width){
   mVelocityTracker.computeCurrentVelocity(1000);
   int max = Math.max(Math.abs(mScroller.getCurrX()), Math.abs(measureWidth - width - mScroller.getCurrX()));
   mScroller.fling(mScroller.getFinalX(), mScroller.getFinalY(), (int)-mVelocityTracker.getXVelocity(), (int)-mVelocityTracker.getYVelocity(), 0, max, mScroller.getFinalY(), mScroller.getFinalY());
   //手指抬起時(shí),根據(jù)滾動(dòng)偏移量初始化位置
   if(mScroller.getCurrX() < 0){
   mScroller.abortAnimation();
   mScroller.startScroll(mScroller.getCurrX(), mScroller.getCurrY(), -mScroller.getCurrX(), 0);
   }else if(mScroller.getCurrX() + width > measureWidth){
   mScroller.abortAnimation();
   mScroller.startScroll(mScroller.getCurrX(), mScroller.getCurrY(), measureWidth - width - mScroller.getCurrX(), 0);
   }
  }
  if(event.getAction() == MotionEvent.ACTION_UP){
   int mUpX = (int)event.getX();
   int mUpY = (int)event.getY();
   //模擬點(diǎn)擊操作
   if(Math.abs(mUpX - mTouchX) <= mTouchSlop && Math.abs(mUpY - mTouchY) <= mTouchSlop){
   for(int i = 0; i < items.size(); i++){
    if(items.get(i).rect.contains(mScroller.getCurrX() + mUpX, getScrollY() + mUpY)){
    setSelected(i);
    return super.onTouchEvent(event);
    }
   }
   }
  }
  break;

  default:
  break;
 }
 return super.onTouchEvent(event);
 }

 接下來(lái)就是很重要的一段代碼,因?yàn)檫@段代碼,才可以讓未完全顯示的Item選項(xiàng)被選中時(shí)自動(dòng)滾動(dòng)至完全顯示:

 public void setSelected(int position){
 if(position >= items.size()){
  return;
 }
 for(int i = 0; i < items.size(); i++){
  if(i == position){
  items.get(i).isSelected = true;
  if(i != selectItem){
   selectItem = i;
   //判斷是否需要滑動(dòng)到完全可見(jiàn)
   if(mScroller.getCurrX() + width < items.get(i).rect.right){
   mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), items.get(i).rect.right - mScroller.getCurrX() - width, mScroller.getFinalY());
   }
   if(items.get(i).rect.left < mScroller.getCurrX()){
   mScroller.startScroll(mScroller.getFinalX(), mScroller.getFinalY(), items.get(i).rect.left - mScroller.getCurrX(), mScroller.getFinalY());
   }
   if(listener != null){
   listener.onChanged(selectItem);
   }
  }
  }else{
  items.get(i).isSelected = false;
  }
 }
 invalidate();
 }

然后就是繪制方法了,相當(dāng)于完全代理給了Item來(lái)實(shí)現(xiàn):

 @Override
 protected void onDraw(Canvas canvas){
 mPaint.setAntiAlias(true);
 canvas.drawColor(colorBg);
 for(Item item : items){
  mPaint.setTextSize(item.textSize);
  if(item.isSelected){
  if(type == Type.SelectByLine){
   //繪制紅線(xiàn)
   mPaint.setColor(item.colorSelected);
   mPaint.setStyle(Paint.Style.FILL);
   canvas.drawRoundRect(new RectF(item.rect.left, item.rect.bottom - lineHeight, item.rect.right, item.rect.bottom), 3, 3, mPaint);
  }else if(type == Type.SelectByFill){
   //繪制紅色背景
   mPaint.setColor(getContext().getResources().getColor(android.R.color.holo_red_light));
   mPaint.setStyle(Paint.Style.FILL);
   canvas.drawRoundRect(new RectF(item.rect.left + 6, item.rect.top, item.rect.right - 6, item.rect.bottom), item.rect.height() * 5 / 12, item.rect.height() * 5 / 12, mPaint);
  }
  mPaint.setColor(item.colorSelected);
  }else{
  mPaint.setColor(item.colorDefault);
  }
  canvas.drawText(item.text, item.drawPoint.x, item.drawPoint.y, mPaint);
 }
 }

接下來(lái)就是怎么使用這個(gè)控件了,布局文件:

 <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:id="@+id/listView"
 android:layout_width="match_parent"
 android:layout_height="match_parent">

 <cc.wxf.androiddemo.indicator.IndicatorView
 android:id="@+id/indicator"
 android:layout_width="match_parent"
 android:layout_height="38dp" />
</RelativeLayout>

MainActvity中:

package cc.wxf.androiddemo;

import android.content.Context;
import android.content.res.Resources;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;

import cc.wxf.androiddemo.indicator.IndicatorView;

public class MainActivity extends FragmentActivity {

 private IndicatorView indicatorView;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 initIndicator();
 }

 private void initIndicator(){
 indicatorView = (IndicatorView)findViewById(R.id.indicator);
 Resources resources = getResources();
 indicatorView.color(resources.getColor(android.R.color.black),
  resources.getColor(android.R.color.holo_red_light),
  resources.getColor(android.R.color.darker_gray))
  .textSize(sp2px(this, 16))
  .padding(new int[]{dip2px(this, 14), dip2px(this, 14), dip2px(this, 14), dip2px(this, 14)})
  .text(new String[]{"電視劇","電影","綜藝","片花","動(dòng)漫","娛樂(lè)","會(huì)員1","會(huì)員2","會(huì)員3","會(huì)員4","會(huì)員5","會(huì)員6"})
  .defaultSelect(0).lineHeight(dip2px(this, 3))
  .listener(new IndicatorView.OnIndicatorChangedListener(){

   @Override
   public void onChanged(int position){

   }
  }).commit();
 }

 public static int dip2px(Context context, float dipValue){
 final float scale = context.getResources().getDisplayMetrics().density;
 return (int)(dipValue * scale + 0.5f);
 }

 public static int sp2px(Context context, float spValue){
 final float scale = context.getResources().getDisplayMetrics().scaledDensity;
 return (int)(spValue * scale + 0.5f);
 }

 @Override
 protected void onDestroy() {
 super.onDestroy();
 indicatorView.release();
 }
}

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論