Android ViewPage+Fragment伸缩实现菜单效果,仿Ifanr

先上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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值