修改Android的seekbar小部件垂直操作

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/631238/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 02:21:15  来源:igfitidea点击:

Modifying the Android seekbar widget to operate vertically

androidlayoutwidgetseekbar

提问by Neil

I'm trying to get a vertical seekbar going with the emulator, but I'm sort of stuck. I can get the seekbar to display the way I want it to, and I can get the progress to do what I want, and I can modify the onTouchEvent to get the thumb to go vertically instead of horizontally. What I can't do is get the thumb to move outside of the default 29 horizontal pixels without using setThumbOffset(). This in itself isn't a problem. The problem is coming from the fact that I don't understand the thumbOffset at all -- I guess. I think I could (properly) resize the widget, which I am pretty sure I'm not doing right. Or maybe I could just use the thumbOffset if I could figure it out. Since I can calculate the progress correctly I thought I would just use a linear function of progress * (getTop() - getBottom()) of the widget but that doesn't seem to do it. But I can't figure out what the offset is centered around.

我试图让模拟器使用垂直搜索栏,但我有点卡住了。我可以让搜索栏以我想要的方式显示,我可以获得我想做的事情的进度,我可以修改 onTouchEvent 使拇指垂直而不是水平移动。我不能做的是在不使用 setThumbOffset() 的情况下让拇指移动到默认的 29 个水平像素之外。这本身不是问题。问题出在我根本不了解 thumbOffset 的事实 - 我猜。我想我可以(适当地)调整小部件的大小,我很确定我做得不对。或者,如果我能弄清楚的话,也许我可以只使用拇指偏移量。由于我可以正确计算进度,我以为我只会使用小部件的进度线性函数 * (getTop() - getBottom()) 但这似乎并没有做到。但我无法弄清楚偏移量以什么为中心。

As a somewhat aside, I am really unsure if what I am doing in onSizeChanged() is sane or if it's going to bite me in the ass later on.

顺便说一句,我真的不确定我在 onSizeChanged() 中所做的是否理智,或者它是否会在以后咬我的屁股。

Here's the main.xml layout:

这是 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>

And the class (ignore the debugging junk):

和类(忽略调试垃圾):

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;
        }

}

采纳答案by Jawad Zeb

For API 11 and later, can use seekbar's XMLattributes(android:rotation="270")for vertical effect.

对于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"/>

For older API level (ex API10),use: https://github.com/AndroSelva/Vertical-SeekBar-Androidor see this sample here

对于较旧的 API 级别(例如 API10),请使用:https: //github.com/AndroSelva/Vertical-SeekBar-Android在此处查看此示例

You also have to update it's height & width as suggest by Iftikhar

您还必须按照 Iftikhar 的建议更新它的高度和宽度

In order

为了

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

//haven't tested..

//没有测试..

where

在哪里

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

回答by TechnIx

I've created a solution which works (at least for me, anyway) and creates a vertical SeekBar. http://hackskrieg.wordpress.com/2012/04/20/working-vertical-seekbar-for-android/

我已经创建了一个有效的解决方案(至少对我来说,无论如何)并创建一个垂直的 SeekBar。 http://hackskrieg.wordpress.com/2012/04/20/working-vertical-seekbar-for-android/

This code will correctly select/deselect the thumb, move correctly, update the listener correctly (only when the progress changes!), update/draw the progress correctly, etc. I hope it helps you.

此代码将正确选择/取消选择拇指、正确移动、正确更新侦听器(仅当进度更改时!)、正确更新/绘制进度等。希望对您有所帮助。

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();
}
}

I just placed this vertical SeekBar inside a LinearLayout with layout_height set to FILL_PARENT and layout_width set to WRAP_CONTENT.

我只是将这个垂直的 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>

NOTE: You must set an OnSeekBarChangeListener, otherwise interacting with the SeekBar will produce NullPointerException.

注意:您必须设置 OnSeekBarChangeListener,否则与 SeekBar 交互将产生 NullPointerException。

回答by pengwang

you can download at http://560b.sakura.ne.jp/android/VerticalSlidebarExample.zip, i hope this may can help you

你可以在http://560b.sakura.ne.jp/android/VerticalSlidebarExample.zip下载 ,我希望这可以帮助你

回答by hacken

Take a look at android source. I think you need to change at least trackTouchEvent and there maybe a few other places where you also need to swap the x,y coordinates to take into account your rotation of the control.

看看android源码。我认为您至少需要更改 trackTouchEvent 并且可能还有其他一些地方您还需要交换 x,y 坐标以考虑控件的旋转。

回答by Kyle Clegg

Could you leave the seekbar as horizontal, put it in a frame layout, then rotate the layout 90 degrees in the java? sounds doable...

你可以让seekbar保持水平,把它放在框架布局中,然后在java中将布局旋转90度吗?听起来可行...