Est-ce qu'une seekbar peut être verticale? Je ne suis pas très bon en design d’interface utilisateur, alors comment faire une recherche plus belle, donnez-moi quelques modèles et exemples.
Voici une très bonne implémentation de seekbar vertical . Regardez.
http://560b.sakura.ne.jp/Android/VerticalSlidebarExample.Zip
Et voici ma propre implémentation pour Seekbar vertical et inversé basé sur 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;
}
Pour les API 11 et ultérieures, vous pouvez utiliser les attributs XML de seekbar (Android: rotation = "270") pour un effet vertical.
<SeekBar
Android:id="@+id/seekBar1"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:rotation="270"/>
Pour les anciens niveaux API (ex API10), utilisez uniquement la réponse de Selva:
https://github.com/AndroSelva/Vertical-SeekBar-Android
Exemple de travail
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;
}
}
Là, collez le code et enregistrez-le. Maintenant, utilisez-le dans votre mise en page XML:
<Android.widget.VerticalSeekBar
Android:id="@+id/seekBar1"
Android:layout_width="wrap_content"
Android:layout_height="200dp"
/>
Assurez-vous de créer un package Android.widget
et de créer VerticalSeekBar.Java
sous ce package
Essayer:
<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>
Nous avons créé une barre de recherche verticale en utilisant Android:rotation="270"
:
<?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>
Capture d'écran pour la compensation d'exposition de l'appareil photo:
J'ai utilisé la solution de Selva mais j'avais deux types de problèmes:
J'ai corrigé ces deux problèmes. Vous pouvez trouver la solution (dans mon propre package de projet) à
Notez, il me semble que si vous modifiez la largeur, la largeur du pouce ne change pas correctement ..__ Je n'ai pas pris le temps de la corriger, je l'ai juste corrigée pour mon cas. Voici ce que j’ai fait ... Je ne savais pas comment contacter le créateur original.
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();
}
Cela a fonctionné pour moi, il suffit de le mettre dans n'importe quelle mise en page que vous voulez.
<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>
Lorsque vous déplacez le thumb avec un EditText, la barre de recherche verticale setProgress peut ne pas fonctionner. Le code suivant peut aider:
@Override
public synchronized void setProgress(int progress) {
super.setProgress(progress);
updateThumb();
}
private void updateThumb() {
onSizeChanged(getWidth(), getHeight(), 0, 0);
}
Ce code d'extrait se trouve ici: https://stackoverflow.com/a/33064140/2447726
Essaye ça
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);
}
}
Commencer
Ajoutez ces lignes à build.gradle.
dependencies {
compile 'com.h6ah4i.Android.widget.verticalseekbar:verticalseekbar:0.7.2'
}
Utilisation
Code 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();
}
});
}
}
Mise en page 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>
REMARQUE: Android:splitTrack="false"
est requis pour Android N +.
J'ai essayé de différentes manières, mais celle qui a fonctionné pour moi a été. Utiliser Seekbar dans FrameLayout
<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"
/>
Et dans le code.
Setup Pre Draw callback sur la barre de recherche, où vous pouvez modifier la largeur et la hauteur de la barre de recherche. J'ai fait cette partie en c #, donc le code i utilisé était
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;
Ici, j’ajoute le programme d’écoute à l’événement PreDraw et lorsqu’il est déclenché, j’élimine le PreDraw afin qu’il ne passe pas en boucle infinie.
Ainsi, lorsque Pre Draw est exécuté, je récupère la hauteur de FrameLayout et l'assigne à Seekbar. Et définissez la rotation de seekbar sur 270. Comme ma seekbar se trouve dans la mise en page du cadre et que sa gravité est définie sur Centre. Je n'ai pas besoin de m'inquiéter de la traduction. En tant que Seekbar, restez toujours au milieu de la disposition du cadre.
La raison pour laquelle je supprime EventHandler est parce que seekbar.RequestLayout (); Fera en sorte que cet événement soit exécuté à nouveau.
Enveloppez-le dans un FrameLayout afin d'éviter tout problème de taille.
<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>
Dans mon cas, j'ai utilisé un seekBar ordinaire et ai simplement inversé la mise en page.
seekbark_layout.xml - ma mise en page qui contient la barre de recherche que nous devons rendre verticale.
<?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>
Et dans MainActivity, je fais pivoter 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()
}
}
}
En conséquence, nous avons la barre de recherche verticale nécessaire: