最近用HorizontalScrollView弄了个和slidingmenu差不多的效果的侧边菜单,顺便在里面嵌套viewpager,效果类似天天动听ios版和仿QQ侧边菜单栏,界面略戳,看图
1. 结构
最外层是一个HorizontalScrollView ,重写了它里面的一些方法从而实现划出和收起菜单的效果
里面是viewpager,能左右滑动和点击上面的文字切换。2.主要代码
</pre><pre name="code" class="html">主页布局xml和代码
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.have.ingeniousmusicplayer.business.workmain.view.SlidingMenu
android:id="@+id/sm_workmain_slidingmenu"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@drawable/workmain_background" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/white"
android:orientation="vertical" >
<include layout="@layout/item_workmain_head" />
<com.have.ingeniousmusicplayer.business.workmain.view.ViewPager
android:id="@+id/vp_workmain_container"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" >
</com.have.ingeniousmusicplayer.business.workmain.view.ViewPager>
</LinearLayout>
<include layout="@layout/layout_workmain_menu" />
</LinearLayout>
</com.have.ingeniousmusicplayer.business.workmain.view.SlidingMenu>
</LinearLayout>
<strong>
</strong>
package com.have.ingeniousmusicplayer.business.workmain;
import java.util.ArrayList;
import java.util.List;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.have.baselib.client.common.base.BaseFragmentActivity;
import com.have.ingeniousmusicplayer.MyApplication;
import com.have.ingeniousmusicplayer.R;
import com.have.ingeniousmusicplayer.business.workmain.frag.EqualizerFrag;
import com.have.ingeniousmusicplayer.business.workmain.frag.MyMusicFrag;
import com.have.ingeniousmusicplayer.business.workmain.frag.SearchFrag;
import com.have.ingeniousmusicplayer.business.workmain.frag.TransportFrag;
import com.have.ingeniousmusicplayer.business.workmain.view.SlidingMenu;
import com.have.ingeniousmusicplayer.service.QuickMenuFlowService;
/**
* 主页
*
* @author hongdameng
* @version: [版本号, 2014-12-31]
*
*/
public class WorkMainActivity extends BaseFragmentActivity implements OnClickListener {
private ViewPager vp_workmain_container;
private FragmentPagerAdapter fragmentPagerAdapter;
private List<Fragment> fragments = new ArrayList<Fragment>();
private MyMusicFrag myMusicFrag;
private EqualizerFrag equalizerFrag;
private SearchFrag searchFrag ;
private TransportFrag transportFrag;
private SlidingMenu slidingMenu;
/**四个tab的容器 */
private LinearLayout llTabContainer;
private TextView tvMymusic;
private TextView tvEq;
private TextView tvSearch;
private TextView tvTransport;
private LinearLayout llMyMusic;
private LinearLayout llEq;
private LinearLayout llSearch;
private LinearLayout llTransport;
private ImageView ivMenu;
private int currentIndex;
private boolean isClickTab;
private int tabContainerWidth;
private View ivTabLine;
private float screenWidth;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_workmain);
initView();
initTabLine();
initData();
initService();
}
private void initView() {
llTabContainer = (LinearLayout) findViewById(R.id.ll_workmain_tab_container);
vp_workmain_container = (ViewPager) findViewById(R.id.vp_workmain_container);
tvMymusic = (TextView) findViewById(R.id.tv_workmain_head_tab_mymusic);
tvEq = (TextView) findViewById(R.id.tv_workmain_head_tab_eq);
tvSearch = (TextView) findViewById(R.id.tv_workmain_head_tab_search);
tvTransport = (TextView) findViewById(R.id.tv_workmain_head_tab_transport);
llMyMusic = (LinearLayout) findViewById(R.id.ll_workmain_head_tab_mymusic);
llEq = (LinearLayout) findViewById(R.id.ll_workmain_head_tab_eq);
llSearch = (LinearLayout) findViewById(R.id.ll_workmain_head_tab_search);
llTransport = (LinearLayout) findViewById(R.id.ll_workmain_head_tab_transport);
ivMenu = (ImageView) findViewById(R.id.iv_workmain_menu);
ivMenu.setOnClickListener(this);
llMyMusic.setOnClickListener(this);
llEq.setOnClickListener(this);
llSearch.setOnClickListener(this);
llTransport.setOnClickListener(this);
slidingMenu = (SlidingMenu) findViewById(R.id.sm_workmain_slidingmenu);
}
private void initData() {
myMusicFrag = new MyMusicFrag();
equalizerFrag = new EqualizerFrag();
searchFrag = new SearchFrag();
transportFrag = new TransportFrag();
fragments.add(myMusicFrag);
fragments.add(equalizerFrag);
fragments.add(searchFrag);
fragments.add(transportFrag);
fragmentPagerAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) {
@Override
public int getCount() {
return fragments.size();
}
@Override
public Fragment getItem(int arg0) {
return fragments.get(arg0);
}
};
vp_workmain_container.setAdapter(fragmentPagerAdapter);
vp_workmain_container.setOnPageChangeListener(new MyOnPageChangeListener());
}
private void initService() {
// Intent intent = new Intent(getApplicationContext(), QuickMenuFlowService.class);
// startService(intent);
}
private class MyOnPageChangeListener implements OnPageChangeListener{
@Override
public void onPageSelected(int position) {
resetTextColor();
switch (position) {
case 0:
tvMymusic.setTextColor(getResources().getColor(
R.color.blue_price));
MyApplication.workmainCurrentPage = 0;
MyApplication.isCanControlMenu = false;
break;
case 1:
tvEq.setTextColor(getResources().getColor(
R.color.blue_price));
MyApplication.workmainCurrentPage = 1;
MyApplication.isCanControlMenu = false;
break;
case 2:
tvSearch.setTextColor(getResources().getColor(
R.color.blue_price));
MyApplication.workmainCurrentPage = 2;
MyApplication.isCanControlMenu = false;
break;
case 3:
tvTransport.setTextColor(getResources().getColor(
R.color.blue_price));
MyApplication.workmainCurrentPage = 3;
break;
}
currentIndex = position;
}
@Override
public void onPageScrolled(int position, float positionOffset,
int positionOffsetPixels) {
if (isClickTab) {
isClickTab = false;
return;
}
float trueOffset = positionOffset * (tabContainerWidth/screenWidth);
LinearLayout.LayoutParams layoutParams = (android.widget.LinearLayout.LayoutParams) ivTabLine
.getLayoutParams();
if (currentIndex == 0 && position == 0) {
layoutParams.leftMargin = (int) (trueOffset * (tabContainerWidth * 1.0 / 4) + currentIndex * (tabContainerWidth / 4)) + tabContainerWidth / 16;
ivTabLine.setLayoutParams(layoutParams);
} else if (currentIndex == 1 && position == 0) { // 从位置1平移到位置0
layoutParams.leftMargin = (int) (-(1 - trueOffset) * (tabContainerWidth * 1.0 / 4) + currentIndex * (tabContainerWidth / 4)) + tabContainerWidth / 16;
ivTabLine.setLayoutParams(layoutParams);
} else if(currentIndex == 1 && position == 1){
layoutParams.leftMargin = (int) (trueOffset * (tabContainerWidth * 1.0 / 4) + currentIndex * (tabContainerWidth / 4)) + tabContainerWidth / 16;
ivTabLine.setLayoutParams(layoutParams);
} else if(currentIndex == 2 && position == 1){
layoutParams.leftMargin = (int) (-(1 - trueOffset) * (tabContainerWidth * 1.0 / 4) + currentIndex * (tabContainerWidth / 4)) + tabContainerWidth / 16;
ivTabLine.setLayoutParams(layoutParams);
} else if(currentIndex == 2 && position == 2){
layoutParams.leftMargin = (int) (trueOffset * (tabContainerWidth * 1.0 / 4) + currentIndex * (tabContainerWidth / 4)) + tabContainerWidth / 16;
ivTabLine.setLayoutParams(layoutParams);
} else if(currentIndex == 2 && position == 3){
layoutParams.leftMargin = (int) (trueOffset * (tabContainerWidth * 1.0 / 4) + currentIndex * (tabContainerWidth / 4)) + tabContainerWidth / 16;
ivTabLine.setLayoutParams(layoutParams);
} else if(currentIndex == 3 && position == 2){
layoutParams.leftMargin = (int)(-(1 - trueOffset) * (tabContainerWidth * 1.0 / 4) + currentIndex * (tabContainerWidth / 4)) + tabContainerWidth / 16;
ivTabLine.setLayoutParams(layoutParams);
} else if(currentIndex == 3 && position == 3){
layoutParams.leftMargin = (int) (trueOffset * (tabContainerWidth * 1.0 / 4) + currentIndex * (tabContainerWidth / 4)) + tabContainerWidth / 16;
ivTabLine.setLayoutParams(layoutParams);
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
}
private void initTabLine() {
int w = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);
int h = View.MeasureSpec.makeMeasureSpec(0,View.MeasureSpec.UNSPECIFIED);
ivMenu.measure(w, h);
int menuWidth =ivMenu.getMeasuredWidth();
ivTabLine = (ImageView) findViewById(R.id.iv_workmain_tabline);
DisplayMetrics outMetrics = new DisplayMetrics();
getWindow().getWindowManager().getDefaultDisplay()
.getMetrics(outMetrics);
screenWidth = outMetrics.widthPixels;
tabContainerWidth = (int) (screenWidth - menuWidth);
LinearLayout.LayoutParams lp = (android.widget.LinearLayout.LayoutParams) ivTabLine
.getLayoutParams();
lp.width = tabContainerWidth / 8;
ivTabLine.setLayoutParams(lp);
}
/**
* 重置颜色
*/
protected void resetTextColor() {
tvMymusic.setTextColor(getResources().getColor(R.color.gray_cccccc));
tvEq.setTextColor(getResources().getColor(R.color.gray_cccccc));
tvSearch.setTextColor(getResources().getColor(R.color.gray_cccccc));
tvTransport.setTextColor(getResources().getColor(R.color.gray_cccccc));
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.iv_workmain_menu:
slidingMenu.toggle();
break;
case R.id.ll_workmain_head_tab_mymusic:
vp_workmain_container.setCurrentItem(0);
break;
case R.id.ll_workmain_head_tab_eq:
vp_workmain_container.setCurrentItem(1);
break;
case R.id.ll_workmain_head_tab_search:
vp_workmain_container.setCurrentItem(2);
break;
case R.id.ll_workmain_head_tab_transport:
vp_workmain_container.setCurrentItem(3);
break;
default:
break;
}
}
@Override
protected void onDestroy() {
MyApplication.isCanControlMenu = false;
super.onDestroy();
}
}
重写HorizontalScrollView代码
package com.have.ingeniousmusicplayer.business.workmain.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import com.have.ingeniousmusicplayer.MyApplication;
import com.have.ingeniousmusicplayer.common.utils.ScreenUtils;
import com.nineoldandroids.view.ViewHelper;
/**
* <菜单侧边栏>
*
* @author hongdameng
* @version: [版本号, 2015-1-4]
*
*/
public class SlidingMenu extends HorizontalScrollView {
/**
* 屏幕宽度
*/
private int mScreenWidth;
/**
* dp
*/
private int mMenuRightPadding;
/**
* 菜单的宽度
*/
private int mMenuWidth;
private int mHalfMenuWidth;
private boolean isOpen;
private boolean once;
private ViewGroup mMenu;
private ViewGroup mContent;
public SlidingMenu(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SlidingMenu(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mScreenWidth = ScreenUtils.getScreenWidth(context);
mMenuRightPadding = mScreenWidth / 3;
}
public SlidingMenu(Context context) {
this(context, null, 0);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
/**
* 显示的设置一个宽度
*/
if (!once) {
LinearLayout wrapper = (LinearLayout) getChildAt(0);
mContent = (ViewGroup) wrapper.getChildAt(0);
mMenu = (ViewGroup) wrapper.getChildAt(1);
mMenuWidth = mScreenWidth - mMenuRightPadding;
mHalfMenuWidth = mMenuWidth / 2;
mMenu.getLayoutParams().width = mMenuWidth;
mContent.getLayoutParams().width = mScreenWidth;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (changed) {
// 将菜单隐藏
this.scrollTo(0, 0);
once = true;
}
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_UP:
int scrollX = getScrollX();
if (scrollX > mHalfMenuWidth) {
this.smoothScrollTo(mMenuWidth, 0);
isOpen = true;
} else {
this.smoothScrollTo(0, 0);
MyApplication.isOpenByClick = false;
isOpen = false;
}
return true;
}
return super.onTouchEvent(ev);
}
/**
* 打开菜单
*/
public void openMenu() {
MyApplication.isOpenByClick = true;
if (isOpen)
return;
this.smoothScrollTo(mMenuWidth, 0);
isOpen = true;
}
/**
* 关闭菜单
*/
public void closeMenu() {
if (isOpen) {
this.smoothScrollTo(0, 0);
MyApplication.isOpenByClick = false;
isOpen = false;
}
}
/**
* 切换菜单状态
*/
public void toggle() {
if (isOpen) {
closeMenu();
} else {
openMenu();
}
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
float scale = l * 1.0f / mMenuWidth;
float leftScale = 1 - 0.3f * scale;
float rightScale = 0.8f + scale * 0.2f;
ViewHelper.setScaleX(mContent, leftScale);
ViewHelper.setScaleY(mContent, leftScale);
ViewHelper.setTranslationX(mContent, -mContent.getWidth() * scale * 0.01f);
ViewHelper.setAlpha(mMenu, 0.6f + 0.4f * scale);
ViewHelper.setPivotX(mMenu, 0);
ViewHelper.setPivotY(mMenu, mMenu.getHeight() / 2);
ViewHelper.setScaleX(mMenu, rightScale);
ViewHelper.setScaleY(mMenu, rightScale);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
MyApplication.downXPosition = ev.getX();
case MotionEvent.ACTION_MOVE:
if(MyApplication.workmainCurrentPage == 3 && ev.getX() > MyApplication.downXPosition && ! isOpen){
MyApplication.isCanControlMenu = false;
}
}
return super.onInterceptTouchEvent(ev) && (MyApplication.isCanControlMenu || MyApplication.isOpenByClick);
}
}
重写 viewpager 代码
/*
* 文件名: ViewPager.java
* 文件描述: ()
* 修改人: [hongdameng]
* 生成时间: 2015-1-5 下午1:56:59
* 修改记录:
*/
package com.have.ingeniousmusicplayer.business.workmain.view;
import com.have.ingeniousmusicplayer.MyApplication;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
/**
* <首页viewpager>
*
* @author hongdameng
* @version: [版本号, 2015-1-5]
*
*/
public class ViewPager extends android.support.v4.view.ViewPager {
public ViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
MyApplication.downXPosition = ev.getX();
return super.onTouchEvent(ev);
case MotionEvent.ACTION_MOVE:
if (this.getCurrentItem() == 3 && MyApplication.downXPosition > ev.getX()) {
MyApplication.isCanControlMenu = true;
return super.onTouchEvent(ev);
} else {
return super.onTouchEvent(ev);
}
default:
return super.onTouchEvent(ev);
}
}
}
</pre><pre name="code" class="html">
为了在页面切换过程中判断是否要打开菜单,我在application保存了一些状态
public class MyApplication extends BaseApplication {
public static int workmainCurrentPage = 0;
public static boolean isCanControlMenu = false;
public static float downXPosition = 0;
public static boolean isOpenByClick = false;
@Override
public void onCreate() {
super.onCreate();
initService();
}
/**
* 初始化服务
*/
private void initService() {
//TODO
workmainCurrentPage = 0; //可以通过读取 SharedPreferences 设置当前页
}
}
1. 原理
重写HorizontalScrollView ,实现划出和收起菜单和QQ类似的效果,在用户滑动再抬起手的时候判断露出菜单的偏移量来打开或者关闭菜单,在viewpager滑动过程中,如果是滑到最后一页,再向左滑动机打开菜单,里面的状态都是通过application保存着。