Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Android

Tạo SeekBar dọc (Vertical SeekBar) trong Android

Tạo SeekBar dọc (Vertical SeekBar) trong Android

Hướng dẫn này minh họa cách tạo SeekBar dọc (vertical) bằng cách xoay SeekBar ngang 270 độ.

Bước 1: Tạo dự án mới

Mở Android Studio, chọn File → New Project và điền thông tin cần thiết.

Bước 2: Thiết kế giao diện (activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <SeekBar
        android:id="@+id/seekBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:rotation="270"/>
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:text=""
        android:textSize="16sp" />
</RelativeLayout>

Bước 3: Code MainActivity.java

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.SeekBar;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {
    SeekBar seekBar;
    TextView textView;
    int min = 0, max = 100, current = 50;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        textView = findViewById(R.id.textView);
        seekBar = findViewById(R.id.seekBar);
        
        // Thiết lập phạm vi và giá trị hiện tại
        seekBar.setMax(max - min); // Max = 100
        seekBar.setProgress(current - min); // Progress = 50
        
        textView.setText(String.valueOf(current));
        
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                current = progress + min;
                textView.setText(String.valueOf(current));
            }
            
            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {
                // Bắt đầu kéo
            }
            
            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {
                // Kết thúc kéo
            }
        });
    }
}

Bước 4: Cấu hình AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android" package="app.com.sample">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

Chạy ứng dụng

Kết nối thiết bị, chạy app. SeekBar hiển thị dọc giữa màn hình. Kéo lên/xuống để thay đổi giá trị (0-100), TextView trên cùng cập nhật real-time.

⚠️ Vấn đề với rotation="270":
  • Touch area có thể không khớp hiển thị (vùng chạm vẫn theo orientation gốc)
  • Layout params width/height bị đảo ngược logic
  • Trên một số thiết bị/API, rotation không hoạt động tốt

Cách tốt hơn: Custom VerticalSeekBar

Tạo class VerticalSeekBar.java:

public class VerticalSeekBar extends AppCompatSeekBar {
    public VerticalSeekBar(Context context) {
        super(context);
    }
    
    public VerticalSeekBar(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    
    public VerticalSeekBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
    
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(h, w, oldh, oldw); // Swap width/height
    }
    
    @Override
    protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(heightMeasureSpec, widthMeasureSpec); // Swap
        setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth()); // Swap
    }
    
    @Override
    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;
        
        // Invert Y coordinate
        float y = getHeight() - event.getY();
        float x = event.getX();
        
        MotionEvent invertedEvent = MotionEvent.obtain(
            event.getDownTime(), event.getEventTime(),
            event.getAction(), x, y,
            event.getMetaState()
        );
        
        boolean result = super.onTouchEvent(invertedEvent);
        invertedEvent.recycle();
        return result;
    }
}

Sử dụng trong XML:

<com.example.VerticalSeekBar
    android:id="@+id/verticalSeekBar"
    android:layout_width="wrap_content"
    android:layout_height="200dp"
    android:max="100"
    android:progress="50"
    android:thumb="@drawable/custom_thumb"
    android:progressDrawable="@drawable/custom_progress" />

SeekBar tùy chỉnh giao diện (Custom Thumb & Progress)

res/drawable/custom_thumb.xml:

<shape xmlns:android="https://schemas.android.com/apk/res/android" android:shape="oval">
    <solid android:color="#FF5722"/>
    <size android:width="24dp" android:height="24dp"/>
    <stroke android:width="2dp" android:color="#FFFFFF"/>
</shape>

res/drawable/custom_progress.xml:

<layer-list xmlns:android="https://schemas.android.com/apk/res/android">
    <!-- Background track -->
    <item android:id="@android:id/background">
        <shape>
            <corners android:radius="4dp"/>
            <solid android:color="#E0E0E0"/>
        </shape>
    </item>
    <!-- Progress track -->
    <item android:id="@android:id/progress">
        <clip>
            <shape>
                <corners android:radius="4dp"/>
                <solid android:color="#FF5722"/>
            </shape>
        </clip>
    </item>
</layer-list>