Изменение виджета панели поиска Android для вертикальной работы

Я пытаюсь заставить работать вертикальную панель поиска с эмулятором, но я застрял. Я могу заставить панель поиска отображать так, как я хочу, и я могу получить прогресс, чтобы делать то, что я хочу, и я могу изменить onTouchEvent, чтобы заставить большой палец двигаться вертикально, а не горизонтально. Что я не могу сделать, так это заставить большой палец переместиться за пределы 29 горизонтальных пикселей по умолчанию без использования setThumbOffset(). Это само по себе не проблема. Проблема в том, что я вообще не понимаю thumbOffset - наверное. Я думаю, что я мог (правильно) изменить размер виджета, что, я уверен, я делаю неправильно. Или, может быть, я мог бы просто использовать thumbOffset, если бы мог понять это. Так как я могу правильно рассчитать прогресс, я подумал, что просто использовал бы линейную функцию прогресса * (getTop() - getBottom()) виджета, но, похоже, это не сработало. Но я не могу понять, в чем смещение.

Как бы то ни было, я действительно не уверен, что то, что я делаю в onSizeChanged(), вменяемое, или это будет кусать меня в задницу позже.

Вот макет main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <com.mobilsemantic.mobipoll.SlideBar
        android:id="@+id/slide"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:max="100"
        android:progress="0"
        android:secondaryProgress="25" />

        <Button android:id="@+id/button"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:text="Hello, I am a Button" />

    <TextView android:id="@+id/tracking"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

</LinearLayout>

И класс (игнорируйте нежелательную отладку):

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.SeekBar;

public class SlideBar extends SeekBar {

        private int oHeight = 320, oWidth = 29;
        private int oProgress = -1, oOffset = -1;;
        private float xPos = -1, yPos = -1;
        private int top = -1, bottom = -1, left = -1, right = -1;

        public SlideBar(Context context) {
                super(context);
        }
        public SlideBar(Context context, AttributeSet attrs)
        {
                super(context, attrs);
                oOffset = this.getThumbOffset();
                oProgress = this.getProgress();
        }
        public SlideBar(Context context, AttributeSet attrs, int defStyle)
        {
                super(context, attrs, defStyle);
        }

        protected synchronized void onMeasure(int widthMeasureSpec, intheightMeasureSpec)
        {
                int height = View.MeasureSpec.getSize(heightMeasureSpec);
                oHeight = height;
                this.setMeasuredDimension(oWidth, oHeight);

        }
        protected void onSizeChanged(int w, int h, int oldw, int oldh)
        {
                super.onSizeChanged(h, w, oldw, oldh);
        }
        protected void onLayout(boolean changed, int l, int t, int r, int b)
        {
                super.onLayout(changed, l, t, r, b);
                left = l;
                right = r;
                top = t;
                bottom = b;
        }
        protected void onDraw(Canvas c)
        {
                c.rotate(90);
                c.translate(0,-29);
                super.onDraw(c);
        }
        public boolean onTouchEvent(MotionEvent event)
        {
                xPos = event.getX();
                yPos = event.getY();
                float progress = (yPos-this.getTop())/(this.getBottom()-this.getTop());
                oOffset = this.getThumbOffset();
                oProgress = this.getProgress();
                Log.d("offset" + System.nanoTime(), new Integer(oOffset).toString());
                Log.d("progress" + System.nanoTime(), new Integer(oProgress).toString());

                float offset;

                offset = progress * (this.getBottom()-this.getTop());

                this.setThumbOffset((int)offset);

                Log.d("offset_postsetprogress" + System.nanoTime(), new Integer(oOffset).toString());
                Log.d("progress_postsetprogress" + System.nanoTime(), new Integer(oProgress).toString());

                this.setProgress((int)(100*event.getY()/this.getBottom()));
                return true;
        }

}

5 ответов

Решение

За API 11 and later, можешь использовать seekbar's XML атрибуты(android:rotation="270") для вертикального эффекта.

<SeekBar
android:id="@+id/seekBar1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:rotation="270"/>

Для более старого уровня API (например, API10) используйте: https://github.com/AndroSelva/Vertical-SeekBar-Android или посмотрите этот образец здесь

Вы также должны обновить его высоту и ширину, как предлагает Ифтихар

С целью

seekBar.setLayoutParams(
                new ViewGroup.LayoutParams(convertDpToPixels(1.0f,mContext), ViewGroup.LayoutParams.WRAP_CONTENT));

// не проверял..

где

public static int convertDpToPixels(float dp, Context context){
    Resources resources = context.getResources();
    return (int) TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP,
            dp, 
            resources.getDisplayMetrics()
    );
}

Я создал решение, которое работает (по крайней мере для меня, во всяком случае) и создает вертикальный SeekBar. http://hackskrieg.wordpress.com/2012/04/20/working-vertical-seekbar-for-android/

Этот код будет правильно выбирать / отменять выбор большого пальца, перемещаться правильно, корректно обновлять слушателя (только когда прогресс меняется!), Корректно обновлять / рисовать прогресс и т. Д. Надеюсь, это поможет вам.

public class VerticalSeekBar extends SeekBar {

public VerticalSeekBar(Context context) {
    super(context);
}

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

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

protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(h, w, oldh, oldw);
}

@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(heightMeasureSpec, widthMeasureSpec);
    setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
}

protected void onDraw(Canvas c) {
    c.rotate(-90);
    c.translate(-getHeight(), 0);

    super.onDraw(c);
}

private OnSeekBarChangeListener onChangeListener;
@Override
public void setOnSeekBarChangeListener(OnSeekBarChangeListener onChangeListener){
    this.onChangeListener = onChangeListener;
}

private int lastProgress = 0;
@Override
public boolean onTouchEvent(MotionEvent event) {
    if (!isEnabled()) {
        return false;
    }

    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        onChangeListener.onStartTrackingTouch(this);
        setPressed(true);
        setSelected(true);
        break;
    case MotionEvent.ACTION_MOVE:
        // Calling the super seems to help fix drawing problems
        super.onTouchEvent(event);
        int progress = getMax() - (int) (getMax() * event.getY() / getHeight());

        // Ensure progress stays within boundaries of the seekbar
        if(progress < 0) {progress = 0;}
        if(progress > getMax()) {progress = getMax();}

        // Draw progress
        setProgress(progress);

        // Only enact listener if the progress has actually changed
        // Otherwise the listener gets called ~5 times per change
        if(progress != lastProgress) {
            lastProgress = progress;
            onChangeListener.onProgressChanged(this, progress, true);
        }

        onSizeChanged(getWidth(), getHeight() , 0, 0);
        onChangeListener.onProgressChanged(this, getMax() - (int) (getMax() * event.getY() / getHeight()), true);
        setPressed(true);
        setSelected(true);
        break;
    case MotionEvent.ACTION_UP:
        onChangeListener.onStopTrackingTouch(this);
        setPressed(false);
        setSelected(false);
        break;
    case MotionEvent.ACTION_CANCEL:
        super.onTouchEvent(event);
        setPressed(false);
        setSelected(false);
        break;
    }
    return true;
}

public synchronized void setProgressAndThumb(int progress) {
    setProgress(getMax() - (getMax()- progress));
    onSizeChanged(getWidth(), getHeight() , 0, 0);
}

public synchronized void setMaximum(int maximum) {
    setMax(maximum);
}

public synchronized int getMaximum() {
    return getMax();
}
}

Я только что поместил этот вертикальный SeekBar в LinearLayout с layout_height, установленным в FILL_PARENT, и layout_width, установленным в WRAP_CONTENT.

<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <com.safetyculture.jsadroidtablet.VerticalSeekBar
        android:id="@+id/calculatorVerticalSeekBar"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:layout_gravity="bottom"
        android:max="4"
        android:progress="2" />

</LinearLayout>

ПРИМЕЧАНИЕ. Вы должны установить OnSeekBarChangeListener, иначе взаимодействие с SeekBar приведет к исключению NullPointerException.

Вы можете скачать по адресу http://560b.sakura.ne.jp/android/VerticalSlidebarExample.zip, я надеюсь, что это может помочь вам

Взгляните на источник Android. Я думаю, что вам нужно изменить хотя бы trackTouchEvent и, возможно, есть еще несколько мест, где вам также нужно поменять координаты x,y, чтобы учесть ваше вращение элемента управления.

Не могли бы вы оставить панель поиска горизонтальной, поместить ее в рамку и повернуть ее на 90 градусов в java? звучит выполнимо...

Другие вопросы по тегам