您的位置:首页 > 移动开发 > Android开发

[置顶] Android ViewPage+Fragment伸缩实现菜单效果,仿Ifanr

2016-09-22 22:12 549 查看
先上Ifanr效果



实现效果



1.布局xml

设置android:clipChildren=”false” 使子View在ViewPage被缩放时允许超出ViewPage的范围

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/content"
tools:context=".View.Activity.MainActivity">

<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fillViewport="false" />

<android.support.v4.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/tabs">

<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:id="@+id/frag_content"
android:clipChildren="false"
android:foreground="@android:color/transparent">

<include layout="@layout/menuview_background" ></include>

<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/vp_content"
android:clipChildren="false">

<com.gy.ifanr.View.Widget.MyViewPage
android:id="@+id/view_pager"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@android:color/black"
android:clipChildren="false"
android:layout_alignParentBottom="true"/>

</FrameLayout>

<ImageButton
android:id="@+id/btn_scale"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_margin="10dp"
android:background="@drawable/menu"
android:layout_gravity="right|top"
android:clickable="true"
android:focusable="true"/>

<ImageButton
android:id="@+id/btn_menu"
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_margin="10dp"
android:background="@drawable/circle"
android:layout_gravity="left|top"
android:clickable="true"
android:focusable="true"/>

</FrameLayout>

</android.support.v4.widget.SwipeRefreshLayout>

</RelativeLayout>


fragment_first_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="你好"
android:id="@+id/hello"
android:textColor="@android:color/black"/>

<ImageView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/mask"
android:background="@android:color/transparent"/>

</FrameLayout>


背景菜单布局

menuview_background.xml

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

<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/imageView"
android:src="@mipmap/ic_launcher"/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="菜单1"
android:id="@+id/textView" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="菜单2"
android:id="@+id/textView2" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="菜单3"
android:id="@+id/textView3" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="菜单4"
android:id="@+id/textView4" />

</LinearLayout>


2.MainActivity

public class MainActivity extends AppCompatActivity implements Animator.AnimatorListener,View.OnClickListener, OnFragmentClick {

private List<Fragment> fragments;

private MyViewPage viewPager;
private RelativeLayout content;
private TabLayout mTabLayout;
private FrameLayout viewpagecontent;
private FrameLayout vpParent;
private float scale = 0.6f;
private float x,y;
private ImageButton menubt,scalebt;

private boolean scalling = false;
private boolean isScalled = false;

private MenuHelper moremenu;
private View moremenuView;

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

private void findview(){
viewPager = (MyViewPage) findViewById(R.id.view_pager);
content = (RelativeLayout) findViewById(R.id.content);
viewpagecontent = (FrameLayout) findViewById(R.id.frag_content);
mTabLayout = (TabLayout) findViewById(R.id.tabs);
vpParent = (FrameLayout) findViewById(R.id.vp_content);
menubt = (ImageButton) findViewById(R.id.btn_menu);
scalebt = (ImageButton) findViewById(R.id.btn_scale);
moremenuView = View.inflate(this,R.layout.grid_menu_layout,null);
}

private void setView(){
viewPager.setOffscreenPageLimit(3);
viewPager.setPageMargin(6);
menubt.setOnClickListener(this);
scalebt.setOnClickListener(this);
moremenu = new MenuHelper(this,menubt,moremenuView,viewpagecontent);
//将ViewPage父容器的touch事件转发给ViewPage,不然只有中间的item可以触摸,并且需要自定义
//ViewPage
vpParent.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return viewPager.dispatchTouchEvent(event);
}
});
}

private void addFrags(){
List<String> titles = new ArrayList<>();
titles.add("页面1");
titles.add("页面2");
titles.add("页面3");
mTabLayout.addTab(mTabLayout.newTab().setText(titles.get(0)));
mTabLayout.addTab(mTabLayout.newTab().setText(titles.get(1)));
mTabLayout.addTab(mTabLayout.newTab().setText(titles.get(2)));
fragments = new ArrayList<>();
fragments.add(new FirstFragment());
fragments.add(new SecFragment());
fragments.add(new ThrFragment());
FragmentAdapter adapter =
new FragmentAdapter(getSupportFragmentManager(), fragments, titles);
viewPager.setAdapter(adapter);
mTabLayout.setupWithViewPager(viewPager);
mTabLayout.setTabsFromPagerAdapter(adapter);
}

//对ViewPage的父视图进行Y轴缩放,同时对ViewPage进行X轴缩放,保持x/y比例
private void scaleViewPage(){
x = vpParent.getWidth()/2 + vpParent.getX();
y = vpParent.getHeight() + vpParent.getY();
ViewPropertyAnimator.animate(vpParent).setListener(this).scaleY(scale);
ViewPropertyAnimator.animate(viewPager).scaleX(scale);
ViewHelper.setPivotX(viewPager, x);
ViewHelper.setPivotY(viewPager, y);
ViewHelper.setPivotX(vpParent, x);
ViewHelper.setPivotY(vpParent, y);
ViewHelper.setScaleX(viewPager,scale);
ViewHelper.setScaleY(vpParent,scale);
}

//缩放还原
private void restoreViewPage(){
x = vpParent.getWidth()/2 + vpParent.getX();
y = vpParent.getHeight() + vpParent.getY();
ViewPropertyAnimator.animate(vpParent).setListener(this).scaleY(1);
ViewPropertyAnimator.animate(viewPager).scaleX(1);
ViewHelper.setPivotX(viewPager, x);
ViewHelper.setPivotY(viewPager, y);
ViewHelper.setPivotX(vpParent, x);
ViewHelper.setPivotY(vpParent, y);
ViewHelper.setScaleX(viewPager,1);
ViewHelper.setScaleY(vpParent,1);
}

//相关视图元素进行控制
@Override
public void onAnimationStart(Animator animator) {
scalling = true;
if (!isScalled){
mTabLayout.setVisibility(View.INVISIBLE);
menubt.setVisibility(View.GONE);
}
}

@Override
public void onAnimationEnd(Animator animator) {
scalling = false;
isScalled = !isScalled;
if (!isScalled){
mTabLayout.setVisibility(View.VISIBLE);
menubt.setVisibility(View.VISIBLE);
}
}

@Override
public void onAnimationCancel(Animator animator) {

}

@Override
public void onAnimationRepeat(Animator animator) {

}

@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btn_scale:
doScale();
break;
case R.id.btn_menu:
moremenu.showMenu();
break;
}
}

private void doScale() {
if (scalling)
return;
if (isScalled){
restoreViewPage();
}else {
scaleViewPage();
}
}

@Override
public void OnFragClick(int no) {
if (isScalled){
viewPager.setCurrentItem(no);
doScale();
}
}
}


3.BaseFragment

/**
* 基类Fragment,捕获Click事件以收起菜单
* Created by gy939 on 2016/9/21.
*/
public abstract class BaseFragment extends Fragment{

private View view;

private OnFragmentClick fragmentClick;

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_first_layout,container,false);
//这里其实建议使用类似EventBus的消息框架做组件间通讯。
fragmentClick = (OnFragmentClick) getActivity();
view.findViewById(R.id.mask).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.e("gy","点击了"+hashCode());
fragmentClick.OnFragClick(getNo());
}
});
((TextView)view.findViewById(R.id.hello)).setText(getClass().getName());
return view;
}

//获取Fragment编号
protected abstract int getNo();

}


4.自定义ViewPage

需要对触摸事件进行转发拦截等

public class MyViewPage extends ViewPager{

public MyViewPage(Context context) {
super(context);
}

public MyViewPage(Context context, AttributeSet attrs) {
super(context, attrs);
}

/**
* 拦截ViewPage范围以外的Touch事件
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
FragmentAdapter adapter = (FragmentAdapter) getAdapter();
int[] xy = new int[2];
getLocationInWindow(xy);
int x = xy[0];
int y = xy[1];
Log.e("gy","x="+x+"y="+y);
if (ev.getRawY() < y){
Log.e("gy",y+"-"+ev.getRawY());
return true;
}
if (getWidth() - x < ev.getRawX()){
//在右边
Log.e("gy","右边");
return true;
}else if (x > ev.getRawX()){
//在左边
Log.e("gy","左边");
return true;
}else {
//中间在区域内不做拦截
}
return super.onInterceptTouchEvent(ev);
}

/**
* 向ViewPage范围以外的子View分发Touch事件,
* 因为设置了ClipChildren属性以后,子View已经可以超出父View的范围了
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
FragmentAdapter adapter = (FragmentAdapter) getAdapter();
int fragno = adapter.getCurPosition();
int[] xy = new int[2];
getLocationInWindow(xy);
int x = xy[0];
int y = xy[1];
if (getWidth() - x < ev.getRawX()){
//在右边
Log.e("gy","右边");
//在右边将事件分发给当前Page的右边一个Page
if (fragno < adapter.getCount() - 1)
adapter.getItem(fragno + 1).getView().dispatchTouchEvent(ev);
}else if (x > ev.getRawX()){
//在左边
Log.e("gy","左边");
//在左边边将事件分发给当前Page的左边一个Page
if (fragno > 0)
adapter.getItem(fragno - 1).getView().dispatchTouchEvent(ev);
}else {
//中间
}
return super.onTouchEvent(ev);
}

}


最后老规矩上链接GitHub
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: