Android에서 수직 SeekBar를 만드는 방법은 무엇입니까?
탐색 막대가 수직 일 수 있습니까? 저는 UI 디자인을 잘하지 못합니다. 그래서 Seekbar를 더 아름답게 만드는 방법은 몇 가지 템플릿과 예제를 제공해주세요.
다음은 수직 탐색 막대의 아주 좋은 구현입니다. 보세요.
http://560b.sakura.ne.jp/android/VerticalSlidebarExample.zip
그리고 여기에 기반한 Vertical 및 Inverted Seekbar에 대한 자체 구현 이 있습니다.
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>
Selva의 솔루션을 사용했지만 두 가지 문제가있었습니다.
- OnSeekbarChangeListener가 제대로 작동하지 않았습니다.
- 프로그래밍 방식으로 진행률 설정이 제대로 작동하지 않았습니다.
이 두 가지 문제를 해결했습니다. 내 프로젝트 패키지 내에서 솔루션을 찾을 수 있습니다.
다음을 사용하여 수직 SeekBar를 만들었습니다 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>
카메라 노출 보정 스크린 샷 :
너비를 변경하면 엄지 너비가 올바르게 변경되지 않는 것 같습니다. 시간을 들여 제대로 고치지 않고 제 사건을 위해 고쳤습니다. 여기 내가 한 일이 있습니다. 원래 제작자에게 연락하는 방법을 알 수 없습니다.
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로 엄지 손가락 을 움직일 때 Vertical Seekbar 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 에서 찾을 수 있습니다.
시작하기
build.gradle에 다음 행을 추가하십시오.
dependencies {
compile 'com.h6ah4i.android.widget.verticalseekbar:verticalseekbar:0.7.2'
}
용법
자바 코드
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 +에 필요합니다.
이 시도
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);
}
}
크기 문제가 없도록 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>
제 경우에는 일반 seekBar를 사용하고 레이아웃을 뒤집 었습니다.
seekbark_layout.xml-수직으로 만들어야하는 seekbar를 포함하는 내 레이아웃.
<?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()
}
}
}
I tried in many different ways, but the one which worked for me was. Use Seekbar inside 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"
/>
And in Code.
Setup Pre Draw callback on Seekbar, Where you can change the Width and height of the Seekbar I did this part in c#, so Code i used was
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;
Here i Add listener to PreDraw Event and when its triggered, I remove the PreDraw so that it doesnt go into Infinite loop.
So when Pre Draw gets executed, I fetch the Height of FrameLayout and assign it to Seekbar. And set the rotation of seekbar to 270. As my seekbar is inside frame Layout and its Gravity is set as Center. I dont need to worry about the Translation. As Seekbar always stay in middle of Frame Layout.
Reason i remove EventHandler is because seekbar.RequestLayout(); Will make this event to be executed again.
참고 URL : https://stackoverflow.com/questions/3333658/how-to-make-a-vertical-seekbar-in-android
'Program Tip' 카테고리의 다른 글
StreamReader를 처음으로 반환 (0) | 2020.11.19 |
---|---|
Linux에서 현재 rpath를 검사하는 방법이 있습니까? (0) | 2020.11.19 |
Internet Explorer의 addEventListener (0) | 2020.11.19 |
iOS 앱이 처음 실행되는시기를 감지 하시겠습니까? (0) | 2020.11.19 |
SQLite gem을 설치할 수없는 이유는 무엇입니까? (0) | 2020.11.19 |