web-dev-qa-db-ja.com

Androidで垂直SeekBarを作成する方法は?

シークバーを垂直にすることはできますか?私はUIデザインがあまり得意ではないので、シークバーをより美しくする方法について、テンプレートと例をいくつか教えてください。

64
Chris

これは、垂直シークバーの非常に優れた実装です。ご覧ください。

http://560b.sakura.ne.jp/Android/VerticalSlidebarExample.Zip

そして、これが this に基づく垂直シークバーと反転シークバーの独自の実装です。

https://github.com/AndroSelva/Vertical-SeekBar-Android

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

    super.onDraw(c);
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    if (!isEnabled()) {
        return false;
    }

    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
        case MotionEvent.ACTION_MOVE:
        case MotionEvent.ACTION_UP:
            int i=0;
            i=getMax() - (int) (getMax() * event.getY() / getHeight());
            setProgress(i);
            Log.i("Progress",getProgress()+"");
            onSizeChanged(getWidth(), getHeight(), 0, 0);
            break;

        case MotionEvent.ACTION_CANCEL:
            break;
    }
    return true;
}
48
Andro Selva
  1. API 11以降では、seekbarのXML属性(Android:rotation = "270")を使用して垂直効果を得ることができます。

    <SeekBar
    Android:id="@+id/seekBar1"
    Android:layout_width="match_parent"
    Android:layout_height="wrap_content"
    Android:rotation="270"/>
    
  2. 古いAPIレベル(API10など)については、Selvaの回答のみを使用してください:
    https://github.com/AndroSelva/Vertical-SeekBar-Android

61
Saturn

実施例

import Android.content.Context;
import Android.graphics.Canvas;
import Android.util.AttributeSet;
import Android.view.MotionEvent;

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
   public synchronized void setProgress(int progress)  // it is necessary for calling setProgress on click of a button
   {
    super.setProgress(progress);
    onSizeChanged(getWidth(), getHeight(), 0, 0); 
   }
    @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);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (!isEnabled()) {
            return false;
        }

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
            case MotionEvent.ACTION_UP:
                setProgress(getMax() - (int) (getMax() * event.getY() / getHeight()));
                onSizeChanged(getWidth(), getHeight(), 0, 0);
                break;

            case MotionEvent.ACTION_CANCEL:
                break;
        }
        return true;
    }
}

そこで、コードを貼り付けて保存します。 XMLレイアウトで使用します。

<Android.widget.VerticalSeekBar
  Android:id="@+id/seekBar1"
  Android:layout_width="wrap_content"
  Android:layout_height="200dp"
  />

パッケージを作成してくださいAndroid.widgetおよび作成VerticalSeekBar.Javaこのパッケージの下

22
Xar E Ahmer

試してください:

<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"  
xmlns:tools="http://schemas.Android.com/tools" 
Android:layout_width="match_parent" 
Android:layout_height="match_parent" > 

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

</RelativeLayout> 
13

Android:rotation="270"を使用して、垂直のSeekBarを作成しました。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:orientation="horizontal"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">

    <SurfaceView
        Android:id="@+id/camera_sv_preview"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"/>

    <LinearLayout
        Android:id="@+id/camera_lv_expose"  
        Android:layout_width="32dp"
        Android:layout_height="200dp"
        Android:layout_centerVertical="true"
        Android:layout_alignParentRight="true"
        Android:layout_marginRight="15dp"
        Android:orientation="vertical">

        <TextView
            Android:id="@+id/camera_tv_expose"
            Android:layout_width="32dp"
            Android:layout_height="20dp"
            Android:textColor="#FFFFFF"
            Android:textSize="15sp"
            Android:gravity="center"/>

        <FrameLayout
            Android:layout_width="32dp"
            Android:layout_height="180dp"
            Android:orientation="vertical">

            <SeekBar
                Android:id="@+id/camera_sb_expose"
                Android:layout_width="180dp"
                Android:layout_height="32dp" 
                Android:layout_gravity="center"
                Android:rotation="270"/>

        </FrameLayout>

    </LinearLayout>

    <TextView
        Android:id="@+id/camera_tv_help"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_centerHorizontal="true"
        Android:layout_alignParentBottom="true"
        Android:layout_marginBottom="20dp"
        Android:text="@string/camera_tv"
        Android:textColor="#FFFFFF" />

</RelativeLayout>

カメラ露出補正のスクリーンショット:

enter image description here

9
Maxim Mikhisor

Selvaのソリューションを使用しましたが、2種類の問題がありました。

  • OnSeekbarChangeListenerが正しく機能しませんでした
  • プログラムによる進行状況の設定が適切に機能しませんでした。

これら2つの問題を修正しました。ソリューションは(自分のプロジェクトパッケージ内で)見つけることができます

https://github.com/jeisfeld/Augendiagnose/blob/master/AugendiagnoseIdea/augendiagnoseLib/src/main/Java/de/jeisfeld/augendiagnoselib/components/VerticalSeekBar.Java

9
Jörg Eisfeld

幅を変更すると、親指の幅が正しく変更されないように見えます。私はそれを正しく修正するために時間をかけませんでした、私はちょうど私の場合のためにそれを修正しました。これが私がしたことです。元の作成者に連絡する方法がわかりませんでした。

public void setThumb(Drawable thumb) {
    if (thumb != null) {
        thumb.setCallback(this);

        // Assuming the thumb drawable is symmetric, set the thumb offset
        // such that the thumb will hang halfway off either Edge of the
        // progress bar.
        //This was orginally divided by 2, seems you have to adjust here when you adjust width.
        mThumbOffset = (int)thumb.getIntrinsicHeight();
    }
6
user602622

これは私のために働いた、あなたがしたいレイアウトにそれを置くだけ。

<FrameLayout
    Android:layout_width="32dp"
    Android:layout_height="192dp">

    <SeekBar
        Android:layout_width="192dp"
        Android:layout_height="32dp"
        Android:layout_gravity="center"
        Android:rotation="270" />

</FrameLayout>
5
Nick

EditTextでthumbを移動すると、垂直シークバーsetProgressが機能しない場合があります。次のコードが役立ちます。

    @Override
public synchronized void setProgress(int progress) {
    super.setProgress(progress);
    updateThumb();
}

private void updateThumb() {
    onSizeChanged(getWidth(), getHeight(), 0, 0);
}

ここにあるスニペットコード: https://stackoverflow.com/a/33064140/2447726

2
Guy West

FrameLayout内にラップして、サイズの問題がないようにします。

  <FrameLayout
                Android:layout_width="@dimen/_20dp"
                Android:layout_marginStart="@dimen/_15dp"
                Android:layout_marginEnd="@dimen/_15dp"
                Android:layout_height="match_parent"
                Android:orientation="vertical">

                <SeekBar
                    Android:layout_width="150dp"
                    Android:layout_height="30dp"
                    Android:layout_gravity="center"
                    Android:rotation="270" />
  </FrameLayout>
1

これを試して

import Android.content.Context;
import Android.graphics.Canvas;
import Android.support.annotation.NonNull;
import Android.util.AttributeSet;
import Android.view.MotionEvent;
import Android.widget.SeekBar;

/**
 * Implementation of an easy vertical SeekBar, based on the normal SeekBar.
 */
public class VerticalSeekBar extends SeekBar {
    /**
     * The angle by which the SeekBar view should be rotated.
     */
    private static final int ROTATION_ANGLE = -90;

    /**
     * A change listener registrating start and stop of tracking. Need an own listener because the listener in SeekBar
     * is private.
     */
    private OnSeekBarChangeListener mOnSeekBarChangeListener;

    /**
     * Standard constructor to be implemented for all views.
     *
     * @param context The Context the view is running in, through which it can access the current theme, resources, etc.
     * @see Android.view.View#View(Context)
     */
    public VerticalSeekBar(final Context context) {
        super(context);
    }

    /**
     * Standard constructor to be implemented for all views.
     *
     * @param context The Context the view is running in, through which it can access the current theme, resources, etc.
     * @param attrs   The attributes of the XML tag that is inflating the view.
     * @see Android.view.View#View(Context, AttributeSet)
     */
    public VerticalSeekBar(final Context context, final AttributeSet attrs) {
        super(context, attrs);
    }

    /**
     * Standard constructor to be implemented for all views.
     *
     * @param context  The Context the view is running in, through which it can access the current theme, resources, etc.
     * @param attrs    The attributes of the XML tag that is inflating the view.
     * @param defStyle An attribute in the current theme that contains a reference to a style resource that supplies default
     *                 values for the view. Can be 0 to not look for defaults.
     * @see Android.view.View#View(Context, AttributeSet, int)
     */
    public VerticalSeekBar(final Context context, final AttributeSet attrs, final int defStyle) {
        super(context, attrs, defStyle);
    }

    /*
     * (non-Javadoc) ${see_to_overridden}
     */
    @Override
    protected final void onSizeChanged(final int width, final int height, final int oldWidth, final int oldHeight) {
        super.onSizeChanged(height, width, oldHeight, oldWidth);
    }

    /*
     * (non-Javadoc) ${see_to_overridden}
     */
    @Override
    protected final synchronized void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
        super.onMeasure(heightMeasureSpec, widthMeasureSpec);
        setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
    }

    /*
     * (non-Javadoc) ${see_to_overridden}
     */
    @Override
    protected final void onDraw(@NonNull final Canvas c) {
        c.rotate(ROTATION_ANGLE);
        c.translate(-getHeight(), 0);

        super.onDraw(c);
    }

    /*
     * (non-Javadoc) ${see_to_overridden}
     */
    @Override
    public final void setOnSeekBarChangeListener(final OnSeekBarChangeListener listener) {
        // Do not use super for the listener, as this would not set the fromUser flag properly
        mOnSeekBarChangeListener = listener;
    }

    /*
     * (non-Javadoc) ${see_to_overridden}
     */
    @Override
    public final boolean onTouchEvent(@NonNull final MotionEvent event) {
        if (!isEnabled()) {
            return false;
        }

        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            setProgressInternally(getMax() - (int) (getMax() * event.getY() / getHeight()), true);
            if (mOnSeekBarChangeListener != null) {
                mOnSeekBarChangeListener.onStartTrackingTouch(this);
            }
            break;

        case MotionEvent.ACTION_MOVE:
            setProgressInternally(getMax() - (int) (getMax() * event.getY() / getHeight()), true);
            break;

        case MotionEvent.ACTION_UP:
            setProgressInternally(getMax() - (int) (getMax() * event.getY() / getHeight()), true);
            if (mOnSeekBarChangeListener != null) {
                mOnSeekBarChangeListener.onStopTrackingTouch(this);
            }
            break;

        case MotionEvent.ACTION_CANCEL:
            if (mOnSeekBarChangeListener != null) {
                mOnSeekBarChangeListener.onStopTrackingTouch(this);
            }
            break;

        default:
            break;
        }

        return true;
    }

    /**
     * Set the progress by the user. (Unfortunately, Seekbar.setProgressInternally(int, boolean) is not accessible.)
     *
     * @param progress the progress.
     * @param fromUser flag indicating if the change was done by the user.
     */
    public final void setProgressInternally(final int progress, final boolean fromUser) {
        if (progress != getProgress()) {
            super.setProgress(progress);
            if (mOnSeekBarChangeListener != null) {
                mOnSeekBarChangeListener.onProgressChanged(this, progress, fromUser);
            }
        }
        onSizeChanged(getWidth(), getHeight(), 0, 0);
    }

    /*
     * (non-Javadoc) ${see_to_overridden}
     */
    @Override
    public final void setProgress(final int progress) {
        setProgressInternally(progress, false);
    }
}
1
Saef Myth

はじめに

これらの行をbuild.gradleに追加します。

dependencies {
    compile 'com.h6ah4i.Android.widget.verticalseekbar:verticalseekbar:0.7.2'
}

使用法

Javaコード

public class TestVerticalSeekbar extends AppCompatActivity {
    private SeekBar volumeControl = null;


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

        volumeControl = (SeekBar) findViewById(R.id.mySeekBar);

        volumeControl.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            int progressChanged = 0;

            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                progressChanged = progress;
            }

            public void onStartTrackingTouch(SeekBar seekBar) {
                // TODO Auto-generated method stub
            }

            public void onStopTrackingTouch(SeekBar seekBar) {
                Toast.makeText(getApplicationContext(), "seek bar progress:" + progressChanged,
                        Toast.LENGTH_SHORT).show();
            }
        });
    }

}

レイアウトXML

<!-- This library requires pair of the VerticalSeekBar and VerticalSeekBarWrapper classes -->
<com.h6ah4i.Android.widget.verticalseekbar.VerticalSeekBarWrapper
    Android:layout_width="wrap_content"
    Android:layout_height="150dp">
    <com.h6ah4i.Android.widget.verticalseekbar.VerticalSeekBar
        Android:id="@+id/mySeekBar"
        Android:layout_width="0dp"
        Android:layout_height="0dp"
        Android:max="100"
        Android:progress="0"
        Android:splitTrack="false"
        app:seekBarRotation="CW90" /> <!-- Rotation: CW90 or CW270 -->
</com.h6ah4i.Android.widget.verticalseekbar.VerticalSeekBarWrapper>

注意: Android:splitTrack="false"は、Android N +。

1
Phadadev

私は多くの異なる方法で試しましたが、私のために働いたものがありました。 FrameLayout内でSeekbarを使用する

<FrameLayout
    Android:id="@+id/VolumeLayout"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:layout_above="@id/MuteButton"
    Android:layout_below="@id/volumeText"
    Android:layout_centerInParent="true">
        <SeekBar
        Android:id="@+id/volume"
        Android:layout_width="500dp"
        Android:layout_height="60dp"
        Android:layout_gravity="center"
        Android:progress="50"
        Android:secondaryProgress="40"
        Android:progressDrawable="@drawable/seekbar_volume"
        Android:secondaryProgressTint="@color/tint_neutral"
        Android:thumbTint="@color/tint_neutral"
    />

そしてコード。

SeekbarでPre Drawコールバックをセットアップします。Seekbarの幅と高さを変更できる場所では、c#でこの部分を実行したため、使用したコードは

            var volumeSlider = view.FindViewById<SeekBar>(Resource.Id.home_link_volume);

            var volumeFrameLayout = view.FindViewById<FrameLayout>(Resource.Id.linkVolumeFrameLayout);

            void OnPreDrawVolume(object sender, ViewTreeObserver.PreDrawEventArgs e)
            {
                volumeSlider.ViewTreeObserver.PreDraw -= OnPreDrawVolume;
                var h = volumeFrameLayout.Height;
                volumeSlider.Rotation = 270.0f;
                volumeSlider.LayoutParameters.Width = h;
                volumeSlider.RequestLayout();
            }

            volumeSlider.ViewTreeObserver.PreDraw += OnPreDrawVolume;

ここで、PreDrawイベントにリスナーを追加し、トリガーされたときに、無限ループに入らないようにPreDrawを削除します。

Pre Drawが実行されると、FrameLayoutのHeightを取得してSeekbarに割り当てます。シークバーの回転を270に設定します。シークバーはフレームレイアウト内にあり、その重力はセンターとして設定されています。翻訳について心配する必要はありません。 Seekbarは常にフレームレイアウトの中央に留まるため。

EventHandlerを削除する理由は、seekbar.RequestLayout();このイベントを再度実行します。

0
soan saini

私の場合、通常のシークバーを使用し、レイアウトを反転しました。

seekbark_layout.xml-垂直にする必要があるシークバーを含む私のレイアウト。

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

<SeekBar
    Android:id="@+id/seekBar"
    Android:layout_width="match_parent"
    Android:layout_height="50dp"
    Android:layout_alignParentBottom="true"/>

</RelativeLayout>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:tools="http://schemas.Android.com/tools"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    tools:context="com.vgfit.seekbarexample.MainActivity">

<View
    Android:id="@+id/headerView"
    Android:layout_width="match_parent"
    Android:layout_height="100dp"
    Android:background="@color/colorAccent"/>

<View
    Android:id="@+id/bottomView"
    Android:layout_width="match_parent"
    Android:layout_height="100dp"
    Android:layout_alignParentBottom="true"
    Android:background="@color/colorAccent"/>

<include
    layout="@layout/seekbar_layout"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:layout_above="@id/bottomView"
    Android:layout_below="@id/headerView"/>

 </RelativeLayout>

そして、MainActivityでseekbar_layoutを回転させます。

import Android.os.Bundle
import Android.support.v7.app.AppCompatActivity
import Android.widget.RelativeLayout
import kotlinx.Android.synthetic.main.seekbar_layout.*


class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    rootView.post {
        val w = rootView.width
        val h = rootView.height

        rootView.rotation = 270.0f
        rootView.translationX = ((w - h) / 2).toFloat()
        rootView.translationY = ((h - w) / 2).toFloat()

        val lp = rootView.layoutParams as RelativeLayout.LayoutParams
        lp.height = w
        lp.width = h
        rootView.requestLayout()
    }
}
}

その結果、必要な垂直シークバーがあります: enter image description here

0
Vdovin