シークバーを垂直にすることはできますか?私はUIデザインがあまり得意ではないので、シークバーをより美しくする方法について、テンプレートと例をいくつか教えてください。
これは、垂直シークバーの非常に優れた実装です。ご覧ください。
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;
}
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"/>
古いAPIレベル(API10など)については、Selvaの回答のみを使用してください:
https://github.com/AndroSelva/Vertical-SeekBar-Android
実施例
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
このパッケージの下
試してください:
<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>
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>
カメラ露出補正のスクリーンショット:
Selvaのソリューションを使用しましたが、2種類の問題がありました。
これら2つの問題を修正しました。ソリューションは(自分のプロジェクトパッケージ内で)見つけることができます
幅を変更すると、親指の幅が正しく変更されないように見えます。私はそれを正しく修正するために時間をかけませんでした、私はちょうど私の場合のためにそれを修正しました。これが私がしたことです。元の作成者に連絡する方法がわかりませんでした。
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();
}
これは私のために働いた、あなたがしたいレイアウトにそれを置くだけ。
<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>
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
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>
これを試して
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);
}
}
はじめに
これらの行を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 +。
私は多くの異なる方法で試しましたが、私のために働いたものがありました。 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();このイベントを再度実行します。
私の場合、通常のシークバーを使用し、レイアウトを反転しました。
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()
}
}
}