среда, 31 августа 2011 г.

Создаем свой скролбар, поведение которого не будет изменятся в зависимости от телефона.

Постановка задачи: Нужно чтобы ScrollView всегда показывал, в какой части списка мы сейчас находимся.
Проблема: Линия прокрутки (ScrollView) пропадает, на некоторых телефонах, и появляется только когда идет процес прокручивания списка.
Версия Android-а: 1.6


Решение.
Код своего скролбара CustomFastScrollView.java :

import com.evos.R;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.FrameLayout;
import android.widget.ListView;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.Shape;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup.OnHierarchyChangeListener;

public class CustomFastScrollView extends FrameLayout
    implements OnScrollListener, OnHierarchyChangeListener {
  private final int ITEM_HEIGHT = 100;
  private final int COLOR = Color.GRAY;
  private Drawable _murrentThumb;
  private int _thumbW;
  private int _thumbY;
  private int _overlayScrollThumbWidth;
  private boolean _dragging;
  private ListView _list = null;
  private boolean _drawOverlay;
  private boolean _changedBounds;
  private int _heightScrollDrawable = 40;
  private int _amount = 0;
  private int _screenHeight = 0;
  boolean _globalListenerBeCalled = false;

  public CustomFastScrollView(Context context) {
    super(context);
    init(context, null);
  }


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

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

  private void useThumbDrawable(Drawable drawable) {
    _murrentThumb = drawable;
    _thumbW = _overlayScrollThumbWidth;
    _changedBounds = true;
  }

  private void init(Context context, AttributeSet attrs) {

    if (attrs != null) {
      TypedArray typedArray = context.obtainStyledAttributes(attrs,
          R.styleable.CustomFastScrollView);
      _overlayScrollThumbWidth = typedArray.getDimensionPixelSize(
          R.styleable.CustomFastScrollView_overlayScrollThumbWidth, 0);

    }

    ShapeDrawable shapeDrawable = new ShapeDrawable();
    shapeDrawable.setShape(new Shape() {
    
      @Override
      public void draw(Canvas canvas, Paint paint) {
        paint.setColor(COLOR);
        paint.setAntiAlias(true);
        if (getAmountElements() != 0) {
          _heightScrollDrawable = _screenHeight * _screenHeight / (getAmountElements() * ITEM_HEIGHT);
          canvas.drawRect(0, 0, 5, _heightScrollDrawable, paint);
        }
      
      }
    });
    useThumbDrawable(shapeDrawable);
    setWillNotDraw(false);
    setOnHierarchyChangeListener(this);
  
  }

  @Override
  public void draw(Canvas canvas) {
    super.draw(canvas);
    final int y = _thumbY;
    final int viewWidth = getWidth();
    canvas.translate(0, y);
    _murrentThumb.draw(canvas);
    canvas.translate(0, -y);

    if (_dragging && _drawOverlay) {
    } else {
      invalidate(viewWidth - _thumbW, y, viewWidth, y + _heightScrollDrawable);    
    }
  }

  @Override
  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    if (_screenHeight == 0) _screenHeight = h;
    if (_murrentThumb != null) {
      _murrentThumb.setBounds(w - _thumbW, 0, w, _heightScrollDrawable);
    }
  }

  public void onScrollStateChanged(AbsListView view, int scrollState) {
  }

  public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
      int totalItemCount) {
    if (totalItemCount - visibleItemCount > 0 && !_dragging) {
      _thumbY = ((getHeight() - _heightScrollDrawable) * firstVisibleItem) / (totalItemCount - visibleItemCount);
      if (_changedBounds) {
        final int viewWidth = getWidth();
        _murrentThumb.setBounds(viewWidth - _thumbW, 0, viewWidth, _heightScrollDrawable);
        _changedBounds = false;
      }
    }  
  }

  public void onChildViewAdded(View parent, View child) {
    if (child instanceof ListView) {
      _list = (ListView)child;
      _list.setOnScrollListener(this);
    }
  }

  public void onChildViewRemoved(View parent, View child) {
    if (child == _list) {
      _list = null;
    }
  }

  public synchronized void setAmountElements(int amount) {
    _amount = amount;
  }

  public synchronized int getAmountElements() {
    return _amount;
  }
}

Для того чтобы им воспользоваться нужно:

1) в проект добавить файл res/values/attrs.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CustomFastScrollView">
  <attr name="overlayScrollThumbWidth" format="dimension"/>
</declare-styleable>
</resources>



2) использовать в main.xml :
 android:layout_height="fill_parent">
    <
test.test.view.CustomFastScrollView
    android:id="@+id/custom_fast_scroll_view"
     android:layout_width="fill_parent"
    android:layout_height="fill_parent" 
    test:overlayScrollThumbWidth="7dp" 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:test="http://schemas.android.com/apk/res/test
.test">
       <ListView
       android:id="@+id/list_view"
      android:layout_width="fill_parent"
      android:layout_height="fill_parent" />
    </
test.test.view.CustomFastScrollView> 
    в выделенных местах: test.test.view и test.test  подставить свои значения.

3) задать количество елементов в листе (для вычисления высоты скорлбара, в коде прописан костыль: считается что велечина одного елемента 100 пикселей:

private final int ITEM_HEIGHT = 100;


, а количество задается методом: setAmountElements ).



 






Комментариев нет:

Отправить комментарий