首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Android 同步水平滾動標籤視圖 (SyncHorizontalScrollView) 完整實作

     編輯:Java 相關知識

自訂 View 實現頂部標籤與 ViewPager 聯動

本元件繼承 HorizontalScrollView,結合 RadioGroup 與指示器動畫,實現標籤點擊切換、ViewPager 滑動同步、指示器平滑移動、箭頭顯示隱藏等功能。

核心類別結構

public class SyncHorizontalScrollView extends HorizontalScrollView {
    private View view;
    private ImageView leftImage, rightImage;
    private int windowWidth;
    private Activity mContext;
    private RadioGroup rg_nav_content;
    private ImageView iv_nav_indicator;
    private LayoutInflater mInflater;
    private int indicatorWidth;       // 單個標籤寬度
    private int currentIndicatorLeft; // 當前指示器左邊距
    private ViewPager mViewPager;     // 關聯的 ViewPager
    // ... 建構子與初始化方法
}

關鍵功能實作

1. 參數設定與初始化

public void setSomeParam(ViewPager mViewPager, ImageView leftImage,
                         ImageView rightImage, String[] tabTitle, int count, Activity context) {
    this.mContext = context;
    this.mViewPager = mViewPager;
    mInflater = LayoutInflater.from(context);
    this.view = mInflater.inflate(R.layout.sync_hsv_item, null);
    this.addView(view);
    // 計算螢幕寬度與標籤寬度
    DisplayMetrics dm = new DisplayMetrics();
    context.getWindowManager().getDefaultDisplay().getMetrics(dm);
    windowWidth = dm.widthPixels;
    indicatorWidth = windowWidth / count;
    init(tabTitle);
    this.invalidate();
}

2. 動態建立標籤

private void initNavigationHSV(String[] tabTitle) {
    rg_nav_content.removeAllViews();
    for (int i = 0; i < tabTitle.length; i++) {
        RadioButton rb = (RadioButton) mInflater.inflate(R.layout.nav_radiogroup_item, null);
        rb.setId(i);
        rb.setText(tabTitle[i]);
        rb.setLayoutParams(new LayoutParams(indicatorWidth, LayoutParams.MATCH_PARENT));
        rg_nav_content.addView(rb);
    }
}

3. 標籤切換監聽與指示器動畫

private void setListener() {
    rg_nav_content.setOnCheckedChangeListener((group, checkedId) -> {
        RadioButton rb = (RadioButton) rg_nav_content.getChildAt(checkedId);
        if (rb != null) {
            // 指示器平移動畫
            TranslateAnimation animation = new TranslateAnimation(
                currentIndicatorLeft, rb.getLeft(), 0f, 0f);
            animation.setInterpolator(new LinearInterpolator());
            animation.setDuration(100);
            animation.setFillAfter(true);
            iv_nav_indicator.startAnimation(animation);
            
            // 切換 ViewPager
            mViewPager.setCurrentItem(checkedId);
            currentIndicatorLeft = rb.getLeft();
            
            // HSV 滾動跟隨
            smoothScrollTo(
                (checkedId > 1 ? rb.getLeft() : 0) 
                - rg_nav_content.getChildAt(2).getLeft(), 0);
        }
    });
}

4. 滾動時箭頭顯示邏輯

@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
    super.onScrollChanged(l, t, oldl, oldt);
    if (view.getWidth() <= windowWidth) {
        leftImage.setVisibility(View.GONE);
        rightImage.setVisibility(View.GONE);
    } else {
        if (l == 0) { // 最左邊
            leftImage.setVisibility(View.GONE);
            rightImage.setVisibility(View.VISIBLE);
        } else if (view.getWidth() - l == windowWidth) { // 最右邊
            leftImage.setVisibility(View.VISIBLE);
            rightImage.setVisibility(View.GONE);
        } else { // 中間
            leftImage.setVisibility(View.VISIBLE);
            rightImage.setVisibility(View.VISIBLE);
        }
    }
}

配套 Layout XML

主佈局 (sync_hsv_item.xml)

<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <RelativeLayout
        android:id="@+id/rl_nav"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="#5AB0EB">
        <RadioGroup
            android:id="@+id/rg_nav_content"
            android:layout_width="fill_parent"
            android:layout_height="38dip"
            android:orientation="horizontal"
            android:background="#F2F2F2" />
        <ImageView
            android:id="@+id/iv_nav_indicator"
            android:layout_width="1dip"
            android:layout_height="5dip"
            android:layout_alignParentBottom="true"
            android:background="#5AB0EB"
            android:scaleType="matrix" />
    </RelativeLayout>
</LinearLayout>

標籤項目 (nav_radiogroup_item.xml)

<RadioButton xmlns:android="https://schemas.android.com/apk/res/android"
    android:layout_width="0dip"
    android:layout_height="fill_parent"
    android:background="#F2F2F2"
    android:button="@null"
    android:gravity="center"
    android:textColor="@drawable/rb_blue_bg"
    android:textSize="14.0dip" />

使用方式

// Activity/Fragment 中
SyncHorizontalScrollView hsv = findViewById(R.id.sync_hsv);
ViewPager viewPager = findViewById(R.id.viewpager);
ImageView leftArrow = findViewById(R.id.left_arrow);
ImageView rightArrow = findViewById(R.id.right_arrow);

String[] titles = {"首頁", "發現", "消息", "我的"};
hsv.setSomeParam(viewPager, leftArrow, rightArrow, titles, 4, this);

設計亮點

  • 指示器寬度動態計算,適配不同螢幕
  • 動畫使用 TranslateAnimation,效能優於屬性動畫
  • 雙向同步:點擊標籤切換頁面、滑動頁面更新標籤選中狀態
  • 邊界箭頭智慧顯示,提升使用者體驗
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved