1. 程式人生 > >Android之自定義橫向滾動選單

Android之自定義橫向滾動選單

##前言

已經好長時間沒更新部落格了,今天給大家帶來一個橫向滾動的選單,用的是HorizontalScrollView,但HorizontalScrollView不能在滾動時定位到某個選單,因此監聽了onScrollChanged方法,程式碼比較簡單,大家看程式碼就行了,主要是封裝了一下,方便大家使用,專案github在底部會給出的。廢話不多說,先上效果圖:

這裡寫圖片描述

##怎麼用

這個控制元件已經進行了非常給力的封裝了,想必大家一定用的比較酸爽。

這裡寫圖片描述

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.horizontalscrollview.view.HorizontalScrollMenuView
        android:id="@+id/hs_menu"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/white"
        android:layout_centerVertical="true"/>


</RelativeLayout>

package com.horizontalscrollview;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import com.horizontalscrollview.view.HorizontalScrollMenuView;
import com.horizontalscrollview.view.adapter.BaseMenuAdapter;

public class MainActivity extends AppCompatActivity {

    private int[] mDrawableId={R.drawable.image1,R.drawable.image3,R.drawable.image3};
    private String[] mTitle={"選單一","選單二","選單三"};

    private HorizontalScrollMenuView mHorizontalScrollMenuView;
    private MyMenuAdapter mMyMenuAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initViews();
    }

    private void initViews(){
        mHorizontalScrollMenuView= (HorizontalScrollMenuView) findViewById(R.id.hs_menu);
        mMyMenuAdapter=new MyMenuAdapter();
        mHorizontalScrollMenuView.setAdapter(mMyMenuAdapter);
        mHorizontalScrollMenuView.notifyDataSetChanged();
    }


    class MyMenuAdapter extends BaseMenuAdapter{
        @Override
        public int getCount() {
            return mTitle.length;
        }

        @Override
        public View getView(final int position) {
            View root= LayoutInflater.from(MainActivity.this).inflate(R.layout.menu_layout,null);
            ImageView imageView= (ImageView) root.findViewById(R.id.iv_icon);
            TextView tv_title= (TextView) root.findViewById(R.id.tv_title);
            tv_title.setText(mTitle[position]);
            imageView.setImageResource(mDrawableId[position]);
            imageView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Toast.makeText(MainActivity.this,"點選了"+mTitle[position],Toast.LENGTH_SHORT).show();
                }
            });
            return root;
        }

        @Override
        public int getViewWidth() {
            return 250;
        }
    }


}

用法已經貼出來了,下面有興趣的話看看原始碼,沒興趣的話,我也沒轍,呵呵。。。

##裝B原始碼

package com.horizontalscrollview.view.adapter;

import android.view.View;

/**
 * Created by glh on 2016-08-11.
 */
public interface MenuAdapter {
    int getCount();
    View getView(int position);
}

package com.horizontalscrollview.view.adapter;

import android.util.SparseArray;
import android.view.View;

/**
 * 選單的抽象類,使用者子選單View的儲存
 * Created by glh on 2016-08-11.
 */
public abstract class BaseMenuAdapter implements MenuAdapter{

    private SparseArray<View> mMenuArray=new SparseArray<>();

    /**
     * 獲取子View的寬度,必傳
     * @return
     */
    public abstract int getViewWidth();

    public SparseArray<View> getView(){
        mMenuArray.clear();
        for(int index=0,length=getCount();index<length;index++){
            mMenuArray.append(index,getView(index));
        }
        return mMenuArray;
    }

}

package com.horizontalscrollview.view;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;

import com.horizontalscrollview.R;
import com.horizontalscrollview.util.DensityUtil;
import com.horizontalscrollview.view.adapter.BaseMenuAdapter;

/**
 * 水平滾動的選單
 * Created by glh on 2016-08-11.
 */
public class HorizontalScrollMenuView extends RelativeLayout{

    private Context mContext;

    private View mRootView;
    private LinearLayout ll_menu;//選單容器
    private ObservableHorizontalScrollView mObservableHorizontalScrollView;//滾動容器
    private int mMenuIndex;
    private int mScroll;
    private int interval;//選單最左邊和最右邊的距離
    private int mMiddle;//選單間隔距離
    private int mViewWidth;//選單寬度
    private MyHandler mMyHandler;
    private BaseMenuAdapter mBaseMenuAdapter;

    public HorizontalScrollMenuView(Context context) {
        this(context, null);

    }

    public HorizontalScrollMenuView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public HorizontalScrollMenuView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext=context;
        mMyHandler=new MyHandler();
        interval=(DensityUtil.getWindowWidth(mContext) - DensityUtil.dip2px(250)) / 2;
        mMiddle=DensityUtil.dip2px(25);
        mViewWidth=DensityUtil.dip2px(250);
        initView();
        initEvent();
    }

    private void initView(){
        mRootView= LayoutInflater.from(mContext).inflate(R.layout.horizontal_scroll_layout,this,true);
        ll_menu= (LinearLayout) mRootView.findViewById(R.id.ll_menu);
        mObservableHorizontalScrollView= (ObservableHorizontalScrollView) mRootView.findViewById(R.id.obh_view);
    }

    /**
     * 新增選單
     */
    private void addMenu(){
        ll_menu.removeAllViews();
        SparseArray<View> viewSparseArray=mBaseMenuAdapter.getView();
        View intervalView;
        for(int index=0,length=viewSparseArray.size();index<length;index++){
            if (index == 0) {
                /**
                 * <p>
                 *     在最左邊增加一個(屏寬-選單寬)/2的寬度的View,
                 *     目的在於使第一個選單居中顯示。
                 * </>
                 */
                intervalView = new View(mContext);
                intervalView.setLayoutParams(new LayoutParams(interval, 1));
                ll_menu.addView(intervalView);
            }
            ll_menu.addView(viewSparseArray.get(index));
            if (index == length-1) {
                /**
                 * <p>
                 *     在最右邊增加一個(屏寬-選單寬)/2的寬度的View,
                 *     目的在於使最後一個選單居中顯示。
                 * </>
                 */
                intervalView = new View(mContext);
                intervalView.setLayoutParams(new LayoutParams(interval, 1));
                ll_menu.addView(intervalView);
            }else{
                /**
                 * 兩個選單之間留一點空隙
                 */
                intervalView = new View(mContext);
                intervalView.setLayoutParams(new LayoutParams(mMiddle, 1));
                ll_menu.addView(intervalView);
            }
        }
    }

    private void initEvent(){
        mObservableHorizontalScrollView.setHorizontalScrollViewListener(new ObservableHorizontalScrollView.HorizontalScrollViewListener() {
            @Override
            public void onScrollChanged(ObservableHorizontalScrollView scrollView,
                                        int x, int y, int oldx, int oldy) {
                mMenuIndex = x / mViewWidth;//計算當前位置
                mScroll = x % mViewWidth;
                if (mScroll >= 0.5) {
                    mMenuIndex++;
                }
                if (oldx - x > 0) {
                    /**
                     * 選單往右滑動
                     */
                    mMenuIndex--;
                }

            }
        });

        mObservableHorizontalScrollView.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_UP:
                        mMyHandler.sendEmptyMessage(0);
                        break;
                    default:
                        break;
                }
                return false;
            }
        });
    }


    /**
     * 設定View
     * @param adapter
     */
    public void setAdapter(BaseMenuAdapter adapter){
        this.mBaseMenuAdapter=adapter;
        this.interval =(DensityUtil.getWindowWidth(mContext) - DensityUtil.dip2px(mBaseMenuAdapter.getViewWidth())) / 2;
        this.mViewWidth=DensityUtil.dip2px(mBaseMenuAdapter.getViewWidth());
    }

    /**
     * 重新整理
     */
    public void notifyDataSetChanged(){
        addMenu();
    }

    /**
     * 設定選單間隔
     * @param middle
     */
    public void setMiddle(int middle){
        mMiddle=DensityUtil.dip2px(middle);
    }

    class MyHandler extends Handler {
        public MyHandler() {
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 0:
                    mObservableHorizontalScrollView.smoothScrollTo(mMenuIndex * (mViewWidth + mMiddle), 0);
                    break;
            }
        }
    }

}

##專案地址(豪華套餐)

以下是完整的github專案地址
github專案原始碼地址:點選【專案原始碼】