Android自定义转盘菜单效果

最近由于公司项目需要,需要开发一款转盘菜单,费了好大功夫搞出来了,下面分享下

样图

具体功能如下:

import android.graphics.Color;

import android.os.Bundle;

import android.support.v4.app.Fragment;

import android.support.v4.app.FragmentPagerAdapter;

import android.support.v7.app.AppCompatActivity;

import android.widget.Toast;

import com.hitomi.smlibrary.OnSpinMenuStateChangeListener;

import com.hitomi.smlibrary.TurnTableMenu;

import java.util.ArrayList;

import java.util.List;

public class MainActivity extends AppCompatActivity {

private TurnTableMenu turnTableMenu;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

turnTableMenu = (TurnTableMenu) findViewById(R.id.spin_menu);

// 设置页面标题

List<String> hintStrList = new ArrayList<>();

hintStrList.add("热门信息");

hintStrList.add("实时新闻");

hintStrList.add("我的论坛");

hintStrList.add("我的信息");

hintStrList.add("环游世界");

hintStrList.add("阅读空间");

hintStrList.add("欢乐空间");

hintStrList.add("系统设置");

turnTableMenu.setHintTextStrList(hintStrList);

turnTableMenu.setHintTextColor(Color.parseColor("#FFFFFF"));

turnTableMenu.setHintTextSize(14);

// 设置页面适配器

final List<Fragment> fragmentList = new ArrayList<>();

fragmentList.add(Fragment1.newInstance());

fragmentList.add(Fragment2.newInstance());

fragmentList.add(Fragment3.newInstance());

fragmentList.add(Fragment4.newInstance());

fragmentList.add(Fragment5.newInstance());

fragmentList.add(Fragment6.newInstance());

fragmentList.add(Fragment7.newInstance());

fragmentList.add(Fragment8.newInstance());

FragmentPagerAdapter fragmentPagerAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) {

@Override

public Fragment getItem(int position) {

return fragmentList.get(position);

}

@Override

public int getCount() {

return fragmentList.size();

}

};

turnTableMenu.setFragmentAdapter(fragmentPagerAdapter);

// 设置菜单状态改变时的监听器

turnTableMenu.setOnSpinMenuStateChangeListener(new OnSpinMenuStateChangeListener() {

@Override

public void onMenuOpened() {

Toast.makeText(MainActivity.this, "SpinMenu opened", Toast.LENGTH_SHORT).show();

}

@Override

public void onMenuClosed() {

Toast.makeText(MainActivity.this, "SpinMenu closed", Toast.LENGTH_SHORT).show();

}

});

}

}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>

<com.hitomi.smlibrary.TurnTableMenu xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:app="http://schemas.android.com/apk/res-auto"

xmlns:tools="http://schemas.android.com/tools"

android:id="@+id/spin_menu"

android:layout_width="match_parent"

android:layout_height="match_parent"

app:hint_text_color="#FFFFFF"

app:hint_text_size="14sp"

app:scale_ratio="0.36"

tools:context="com.hitomi.spinmenu.MainActivity">

<FrameLayout

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="#333a4a"></FrameLayout>

</com.hitomi.smlibrary.TurnTableMenu>

3.自定义View TurnTableMenu

import android.content.Context;

import android.content.res.TypedArray;

import android.graphics.Color;

import android.os.Build;

import android.support.annotation.IdRes;

import android.support.v4.view.GestureDetectorCompat;

import android.support.v4.view.PagerAdapter;

import android.util.AttributeSet;

import android.util.Log;

import android.view.GestureDetector;

import android.view.Gravity;

import android.view.MotionEvent;

import android.view.ViewConfiguration;

import android.view.ViewGroup;

import android.widget.FrameLayout;

import android.widget.LinearLayout;

import android.widget.TextView;

import java.util.ArrayList;

import java.util.List;

import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;

import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;

public class TurnTableMenu extends FrameLayout {

static final String TAG = "SpinMenu";

static final String TAG_ITEM_CONTAINER = "tag_item_container";

static final String TAG_ITEM_PAGER = "tag_item_pager";

static final String TAG_ITEM_HINT = "tag_item_hint";

static final int MENU_STATE_CLOSE = -2;

static final int MENU_STATE_CLOSED = -1;

static final int MENU_STATE_OPEN = 1;

static final int MENU_STATE_OPENED = 2;

/**

* 左右菜单 Item 移动动画的距离

*/

static final float TRAN_SKNEW_VALUE = 160;

/**

* Hint 相对 页面的上外边距

*/

static final int HINT_TOP_MARGIN = 15;

/**

* 可旋转、转动布局

*/

private TurnTableMenuLayout turnTableMenuLayout;

/**

* 菜单打开关闭动画帮助类

*/

private TurnTableMenuAnimator turnTableMenuAnimator;

/**

* 页面适配器

*/

private PagerAdapter pagerAdapter;

/**

* 手势识别器

*/

private GestureDetectorCompat menuDetector;

/**

* 菜单状态改变监听器

*/

private OnSpinMenuStateChangeListener onSpinMenuStateChangeListener;

/**

* 缓存 Fragment 的集合,供 {@link #pagerAdapter} 回收使用

*/

private List pagerObjects;

/**

* 菜单项集合

*/

private List<SMItemLayout> smItemLayoutList;

/**

* 页面标题字符集合

*/

private List<String> hintStrList;

/**

* 页面标题字符尺寸

*/

private int hintTextSize = 14;

/**

* 页面标题字符颜色

*/

private int hintTextColor = Color.parseColor("#666666");

/**

* 默认打开菜单时页面缩小的比率

*/

private float scaleRatio = .36f;

/**

* 控件是否初始化的标记变量

*/

private boolean init = true;

/**

* 是否启用手势识别

*/

private boolean enableGesture;

/**

* 当前菜单状态,默认为打开

*/

private int menuState = MENU_STATE_CLOSED;

/**

* 滑动与触摸之间的阀值

*/

private int touchSlop = 8;

private OnSpinSelectedListener onSpinSelectedListener = new OnSpinSelectedListener() {

@Override

public void onSpinSelected(int position) {

log("SpinMenu position:" + position);

}

};

private OnMenuSelectedListener onMenuSelectedListener = new OnMenuSelectedListener() {

@Override

public void onMenuSelected(SMItemLayout smItemLayout) {

closeMenu(smItemLayout);

}

};

private GestureDetector.SimpleOnGestureListener menuGestureListener = new GestureDetector.SimpleOnGestureListener() {

@Override

public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {

if (Math.abs(distanceX) < touchSlop && distanceY < -touchSlop * 3) {

openMenu();

}

return true;

}

};

public TurnTableMenu(Context context) {

this(context, null);

}

public TurnTableMenu(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public TurnTableMenu(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TurnTableMenu);

scaleRatio = typedArray.getFloat(R.styleable.TurnTableMenu_scale_ratio, scaleRatio);

hintTextSize = typedArray.getDimensionPixelSize(R.styleable.TurnTableMenu_hint_text_size, hintTextSize);

hintTextSize = px2Sp(hintTextColor);

hintTextColor = typedArray.getColor(R.styleable.TurnTableMenu_hint_text_color, hintTextColor);

typedArray.recycle();

pagerObjects = new ArrayList();

smItemLayoutList = new ArrayList<>();

menuDetector = new GestureDetectorCompat(context, menuGestureListener);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.DONUT) {

ViewConfiguration conf = ViewConfiguration.get(getContext());

touchSlop = conf.getScaledTouchSlop();

}

}

@Override

protected void onFinishInflate() {

super.onFinishInflate();

@IdRes final int smLayoutId = 0x6F060505;

ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT);

turnTableMenuLayout = new TurnTableMenuLayout(getContext());

turnTableMenuLayout.setId(smLayoutId);

turnTableMenuLayout.setLayoutParams(layoutParams);

turnTableMenuLayout.setOnSpinSelectedListener(onSpinSelectedListener);

turnTableMenuLayout.setOnMenuSelectedListener(onMenuSelectedListener);

addView(turnTableMenuLayout);

}

@Override

protected void onLayout(boolean changed, int left, int top, int right, int bottom) {

super.onLayout(changed, left, top, right, bottom);

if (init && smItemLayoutList.size() > 0) {

// 根据 scaleRatio 去调整菜单中 item 视图的整体大小

int pagerWidth = (int) (getMeasuredWidth() * scaleRatio);

int pagerHeight = (int) (getMeasuredHeight() * scaleRatio);

SMItemLayout.LayoutParams containerLayoutParams = new SMItemLayout.LayoutParams(pagerWidth, pagerHeight);

SMItemLayout smItemLayout;

FrameLayout frameContainer;

TextView tvHint;

for (int i = 0; i < smItemLayoutList.size(); i++) {

smItemLayout = smItemLayoutList.get(i);

frameContainer = (FrameLayout) smItemLayout.findViewWithTag(TAG_ITEM_CONTAINER);

frameContainer.setLayoutParams(containerLayoutParams);

if (i == 0) { // 初始菜单的时候,默认显示第一个 Fragment

FrameLayout pagerLayout = (FrameLayout) smItemLayout.findViewWithTag(TAG_ITEM_PAGER);

// 先移除第一个包含 Fragment 的布局

frameContainer.removeView(pagerLayout);

// 创建一个用来占位的 FrameLayout

FrameLayout holderLayout = new FrameLayout(getContext());

LinearLayout.LayoutParams pagerLinLayParams = new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT);

holderLayout.setLayoutParams(pagerLinLayParams);

// 将占位的 FrameLayout 添加到布局中的 frameContainer 中

frameContainer.addView(holderLayout, 0);

// 添加 第一个包含 Fragment 的布局添加到 SpinMenu 中

FrameLayout.LayoutParams pagerFrameParams = new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT);

pagerLayout.setLayoutParams(pagerFrameParams);

addView(pagerLayout);

}

// 显示标题

if (hintStrList != null && !hintStrList.isEmpty() && i < hintStrList.size()) {

tvHint = (TextView) smItemLayout.findViewWithTag(TAG_ITEM_HINT);

tvHint.setText(hintStrList.get(i));

tvHint.setTextSize(hintTextSize);

tvHint.setTextColor(hintTextColor);

}

// 位于菜单中当前显示 Fragment 两边的 SMItemlayout 左右移动 TRAN_SKNEW_VALUE 个距离

if (turnTableMenuLayout.getSelectedPosition() + 1 == i

|| (turnTableMenuLayout.isCyclic()

&& turnTableMenuLayout.getMenuItemCount() - i == turnTableMenuLayout.getSelectedPosition() + 1)) { // 右侧 ItemMenu

smItemLayout.setTranslationX(TRAN_SKNEW_VALUE);

} else if (turnTableMenuLayout.getSelectedPosition() - 1 == i

|| (turnTableMenuLayout.isCyclic()

&& turnTableMenuLayout.getMenuItemCount() - i == 1)) { // 左侧 ItemMenu

smItemLayout.setTranslationX(-TRAN_SKNEW_VALUE);

} else {

smItemLayout.setTranslationX(0);

}

}

turnTableMenuAnimator = new TurnTableMenuAnimator(this, turnTableMenuLayout, onSpinMenuStateChangeListener);

init = false;

openMenu();

}

}

@Override

public boolean dispatchTouchEvent(MotionEvent ev) {

if (enableGesture) menuDetector.onTouchEvent(ev);

return super.dispatchTouchEvent(ev);

}

@Override

public boolean onTouchEvent(MotionEvent event) {

if (enableGesture) {

menuDetector.onTouchEvent(event);

return true;

} else {

return super.onTouchEvent(event);

}

}

/**

* 根据手机的分辨率从 px(像素) 的单位转成为 sp

* @param pxValue

* @return

*/

private int px2Sp(float pxValue) {

final float fontScale = getContext().getResources().getDisplayMetrics().scaledDensity;

return (int) (pxValue / fontScale + 0.5f);

}

private void log(String log) {

Log.d(TAG, log);

}

public void setFragmentAdapter(PagerAdapter adapter) {

if (pagerAdapter != null) {

pagerAdapter.startUpdate(turnTableMenuLayout);

for (int i = 0; i < adapter.getCount(); i++) {

ViewGroup pager = (ViewGroup) turnTableMenuLayout.getChildAt(i).findViewWithTag(TAG_ITEM_PAGER);

pagerAdapter.destroyItem(pager, i, pagerObjects.get(i));

}

pagerAdapter.finishUpdate(turnTableMenuLayout);

}

int pagerCount = adapter.getCount();

if (pagerCount > turnTableMenuLayout.getMaxMenuItemCount())

throw new RuntimeException(String.format("Fragment number can't be more than %d", turnTableMenuLayout.getMaxMenuItemCount()));

pagerAdapter = adapter;

SMItemLayout.LayoutParams itemLinLayParams = new SMItemLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);

LinearLayout.LayoutParams containerLinlayParams = new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT);

FrameLayout.LayoutParams pagerFrameParams = new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT);

LinearLayout.LayoutParams hintLinLayParams = new LinearLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);

hintLinLayParams.topMargin = HINT_TOP_MARGIN;

pagerAdapter.startUpdate(turnTableMenuLayout);

for (int i = 0; i < pagerCount; i++) {

// 创建菜单父容器布局

SMItemLayout smItemLayout = new SMItemLayout(getContext());

smItemLayout.setId(i + 1);

smItemLayout.setGravity(Gravity.CENTER);

smItemLayout.setLayoutParams(itemLinLayParams);

// 创建包裹FrameLayout

FrameLayout frameContainer = new FrameLayout(getContext());

frameContainer.setId(pagerCount + i + 1);

frameContainer.setTag(TAG_ITEM_CONTAINER);

frameContainer.setLayoutParams(containerLinlayParams);

// 创建 Fragment 容器

FrameLayout framePager = new FrameLayout(getContext());

framePager.setId(pagerCount * 2 + i + 1);

framePager.setTag(TAG_ITEM_PAGER);

framePager.setLayoutParams(pagerFrameParams);

Object object = pagerAdapter.instantiateItem(framePager, i);

// 创建菜单标题 TextView

TextView tvHint = new TextView(getContext());

tvHint.setId(pagerCount * 3 + i + 1);

tvHint.setTag(TAG_ITEM_HINT);

tvHint.setLayoutParams(hintLinLayParams);

frameContainer.addView(framePager);

smItemLayout.addView(frameContainer);

smItemLayout.addView(tvHint);

turnTableMenuLayout.addView(smItemLayout);

pagerObjects.add(object);

smItemLayoutList.add(smItemLayout);

}

pagerAdapter.finishUpdate(turnTableMenuLayout);

}

public void openMenu() {

if (menuState == MENU_STATE_CLOSED) {

turnTableMenuAnimator.openMenuAnimator();

}

}

public void closeMenu(SMItemLayout chooseItemLayout) {

if (menuState == MENU_STATE_OPENED) {

turnTableMenuAnimator.closeMenuAnimator(chooseItemLayout);

}

}

public int getMenuState() {

return menuState;

}

public void updateMenuState(int state) {

menuState = state;

}

public void setEnableGesture(boolean enable) {

enableGesture = enable;

}

public void setMenuItemScaleValue(float scaleValue) {

scaleRatio = scaleValue;

}

public void setHintTextSize(int textSize) {

hintTextSize = textSize;

}

public void setHintTextColor(int textColor) {

hintTextColor = textColor;

}

public void setHintTextStrList(List<String> hintTextList) {

hintStrList = hintTextList;

}

public void setOnSpinMenuStateChangeListener(OnSpinMenuStateChangeListener listener) {

onSpinMenuStateChangeListener = listener;

}

public float getScaleRatio() {

return scaleRatio;

}

}

Github:SlidMenu

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

以上是 Android自定义转盘菜单效果 的全部内容, 来源链接: utcz.com/p/242904.html

回到顶部