1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > Android中侧滑菜单效果实现(主界面和菜单界面实现平移 缩放 滚动动画)

Android中侧滑菜单效果实现(主界面和菜单界面实现平移 缩放 滚动动画)

时间:2024-08-31 06:19:36

相关推荐

Android中侧滑菜单效果实现(主界面和菜单界面实现平移 缩放 滚动动画)

阅读数:999

编写不易,如有转载,请声明出处: 梦回河口:/zxc514257857/article/details/72602778

技术要点

自定义侧滑控件SlideMenu主界面和菜单界面实现伴随移动根据拖拽的百分比实现平移、缩放、滚动等动画效果ListView的基本使用Butterknife 的使用

Demo展示图片

布局代码

//(layout)activity_main<com.test.slidemenu.view.SlideMenu xmlns:android="/apk/res/android"android:id="@+id/slideMenu"android:background="@mipmap/bg"android:layout_width="match_parent"android:layout_height="match_parent"><!--两个子View--><!--引入菜单布局 通过getChildAt(0)获取--><include layout="@layout/layout_menu"/><!--引入主界面布局 通过getChildAt(1)获取--><include layout="@layout/layout_main"/></com.test.slidemenu.view.SlideMenu>-------------------------------------------------------------------//(layout)layout_main<LinearLayout xmlns:android="/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:background="#fff"android:id="@+id/main_linearlayout"android:layout_height="match_parent"><FrameLayout android:background="#18B4ED"android:layout_width="match_parent"android:layout_height="60dp"><ImageView android:layout_marginStart="20dp"android:layout_width="50dp"android:id="@+id/iv_headMainPic"android:layout_gravity="center_vertical"android:src="@mipmap/headpic"android:layout_height="50dp"/></FrameLayout><ListView android:overScrollMode="never"android:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/main_listview"/></LinearLayout>-------------------------------------------------------------------//(layout)layout_menu<LinearLayout xmlns:android="/apk/res/android"android:id="@+id/menu_linearlayout"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ><ImageView android:id="@+id/iv_headMenuPic"android:layout_width="90dp"android:layout_height="90dp"android:background="@mipmap/headpic"android:layout_marginTop="50dp"android:layout_marginLeft="10dp"/><ListView android:layout_width="match_parent"android:layout_marginTop="5dp"android:layout_height="match_parent"android:id="@+id/menu_listview"/></LinearLayout>-------------------------------------------------------------------//(layout)mainitem<LinearLayout xmlns:android="/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="match_parent"><RelativeLayout android:layout_width="match_parent"android:layout_height="60dp"><ImageView android:id="@+id/iv_pic"android:src="@mipmap/pic"android:layout_width="50dp"android:layout_height="wrap_content"android:layout_marginLeft="20dp"android:layout_marginRight="15dp"/><TextView android:id="@+id/tv_contact"android:textSize="18sp"android:textColor="#FF3E96"android:layout_centerVertical="true"android:layout_toRightOf="@+id/iv_pic"android:layout_width="wrap_content"android:layout_height="wrap_content"/></RelativeLayout></LinearLayout>

123456789101112131415161718192223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495

自定义侧滑控件代码

//(view)SlideMenuimport android.animation.ArgbEvaluator;import android.animation.FloatEvaluator;import android.content.Context;import android.graphics.Color;import android.graphics.PorterDuff;import android.support.v4.view.ViewCompat;import android.support.v4.widget.ViewDragHelper;import android.util.AttributeSet;import android.util.Log;import android.view.MotionEvent;import android.view.View;import android.widget.FrameLayout;/*** 自定义SlideMenu控件 实现侧滑效果* 为了避免自己去实现onMeasure和onLayout方法 我们继承FrameLayout,系统已经实现好了宽高的测量和位置的摆放* 为什么不使用LinearLayout和RelativeLayout,因为FrameLayout代码简洁*/public class SlideMenu extends FrameLayout {private static final String TAG = "SlideMenu";// 通过它来进行View拖拽的实现private ViewDragHelper mViewDragHelper;private View mMenuView;private View mMainView;// mainView的拖拽范围private int dragRange;private int mMainWidth;private int mMenuWidth;private FloatEvaluator mFloatEvaluator;private ArgbEvaluator mArgbEvaluator;private OnSlideListener mOnSlideListener;// 表示当前状态: 关闭private DragState mDragState = DragState.Close;public enum DragState{Open ,Close}public SlideMenu(Context context) {this(context , null);}public SlideMenu(Context context, AttributeSet attrs) {this(context, attrs , 0);}public SlideMenu(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initData();}private void initData(){// 父View、滑动敏感度、回调方法mViewDragHelper = ViewDragHelper.create(this , callback);// 浮点运算器mFloatEvaluator = new FloatEvaluator();// 颜色运算器mArgbEvaluator = new ArgbEvaluator();}/*** 该方法在ViewGroup将子View全部添加进来之后执行,但在onMeasure之前执行* 一般用来初始化子View的引用,但是还不能获取到子View的宽高*/@Overrideprotected void onFinishInflate() {mMenuView = getChildAt(0);mMainView = getChildAt(1);super.onFinishInflate();}/*** 当onMeasure方法执行完之后执行,在该方法中可以获取所有控件的宽高*/@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {dragRange = (int) (getMeasuredWidth()*0.6f);mMainWidth = mMainView.getMeasuredWidth();mMenuWidth = mMenuView.getMeasuredWidth();super.onSizeChanged(w, h, oldw, oldh);}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {// 让ViewDragHelper帮助我们判断是否应该拦截boolean result = mViewDragHelper.shouldInterceptTouchEvent(ev);return result;}@Overridepublic boolean onTouchEvent(MotionEvent event) {// 让ViewDragHelper帮助我们处理触摸事件mViewDragHelper.processTouchEvent(event);return true;}ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {/*** 判断是否需要捕获View的触摸事件* 这里的child都是当前触摸的View*/@Overridepublic boolean tryCaptureView(View child, int pointerId) {// 捕获mainView和menuView的触摸事件if(child == mMainView || child == mMenuView){return true;}return false;}/*** 当一个View被捕获触摸事件调用*/@Overridepublic void onViewCaptured(View capturedChild, int activePointerId) {Log.i(TAG , "onViewCaptured:" + activePointerId);super.onViewCaptured(capturedChild, activePointerId);}/*** 通过返回值判断滑动方向 只要大于0就可以正常水平垂直滑动*/@Overridepublic int getViewHorizontalDragRange(View child) {return 1;}/*** 用于捕获子View在水平方向上的移动* @param left:是ViewDragHelper帮我们计算好的View最新的left的值* left = child.getLeft() + dx* @return 真正想要View的Left变成的值*/@Overridepublic int clampViewPositionHorizontal(View child, int left, int dx) {// 限制主界面移动if(child == mMainView){left = clampLeft(left);}return left;}// /**// * 用于捕获子View在垂直方向上的移动// */// @Override// public int clampViewPositionVertical(View child, int top, int dy) {// return top;// }/*** 当View移动的时候调用,可以获取到手指移动的距离*/@Overridepublic void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {// 当手指在menuView移动的时候,让mainView进行一个伴随的移动,但是menuView不动Log.i(TAG , "left: " + left + "dx: " + dx);// menuView固定住mMenuView.layout(0 ,0 , mMenuWidth , mMenuView.getBottom());if(changedView == mMenuView){int newLeft = mMainView.getLeft() + dx;// 限制newLeft否则,在menuView上滑动mainView无限制newLeft = clampLeft(newLeft);// 移动mainViewmMainView.layout(newLeft ,0 , newLeft + mMainWidth , mMainView.getBottom());}// 增加伴随动画float fraction = mMainView.getLeft() * 1.0f / dragRange;// 得到百分比Log.i(TAG , "fraction" + fraction);// 执行动画效果execAnim(fraction);// 回调监听器的方法if(fraction == 0f && mDragState !=DragState.Close){mDragState =DragState.Close;// 说明关闭了if(mOnSlideListener != null){mOnSlideListener.onClose();}// 说明打开了}else if(fraction == 1f && mDragState !=DragState.Open){mDragState =DragState.Open;if(mOnSlideListener != null){mOnSlideListener.onOpen();}}// 说明在拖拽中if(mOnSlideListener != null){mOnSlideListener.onDraging(fraction);}super.onViewPositionChanged(changedView, left, top, dx, dy);}/*** 当手指从View上抬起的时候执行*/@Overridepublic void onViewReleased(View releasedChild, float xvel, float yvel) {// 判断mainView的left是否是大于dragRange的一半if(mMainView.getLeft() > dragRange / 2){// mainView平滑滚动到右边mViewDragHelper.smoothSlideViewTo(mMainView , dragRange , 0 );}else{// mainView平滑滚动到左边mViewDragHelper.smoothSlideViewTo(mMainView , 0 , 0 );}// 刷新操作ViewCompat.postInvalidateOnAnimation(SlideMenu.this);super.onViewReleased(releasedChild, xvel, yvel);}};/*** 根据拖拽的百分比来进行伴随动画效果*/private void execAnim(float fraction) {// mainView的缩放mMainView.setScaleX(mFloatEvaluator.evaluate(fraction , 1.0f , 0.8f));mMainView.setScaleY(mFloatEvaluator.evaluate(fraction , 1.0f , 0.8f));// menuView的缩放mMenuView.setScaleX(mFloatEvaluator.evaluate(fraction , 0.4f , 1f));mMenuView.setScaleY(mFloatEvaluator.evaluate(fraction , 0.4f , 1f));// menuView 水平方向的平移mMenuView.setTranslationX(mFloatEvaluator.evaluate(fraction ,-mMenuWidth /2, 0));// 设置SlideMenu的颜色遮罩getBackground();if(getBackground() != null){// 由黑色变为透明的遮罩效果int color = (int) mArgbEvaluator.evaluate(fraction, Color.BLACK, Color.TRANSPARENT);getBackground().setColorFilter(color, PorterDuff.Mode.DARKEN);}}@Overridepublic void computeScroll() {// 判断动画有没有结束,如果为true表示没有结束if(mViewDragHelper.continueSettling(true)){// 刷新操作ViewCompat.postInvalidateOnAnimation(SlideMenu.this);}puteScroll();}/*** 修正左边距*/private int clampLeft(int left) {if(left > dragRange){left = dragRange;}else if(left < 0){left = 0;}return left;}public interface OnSlideListener{void onOpen();void onClose();void onDraging(float fraction);}public void setOnSlideListener(OnSlideListener mOnSlideListener){this.mOnSlideListener = mOnSlideListener;}}

12345678910111213141516171819222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119111221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992000220320420520620720820921021121221321421521621721821921222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276

常量类代码

//conf(Constant)public class Constant {public static final String[] SETTINGS = {"激活会员" , "QQ钱包" , "个性装扮" , "我的收藏" , "我的相册" , "我的文件"};public static final String[] CONSTACTS = {"宋江", "卢俊义","吴用","公孙胜","关胜","林冲","秦明","呼延灼","花荣","柴进","李应","朱仝","鲁智深","武松","董平","张清","扬志","徐宁","索超","戴宗","刘唐","李逵","史进","穆弘","雷横","李俊","阮小二","张横","阮小五","张顺","阮小七","杨雄","石秀","解珍","解宝","燕青","朱武","黄信","孙立","宣赞","赦思文","韩滔","彭玑","单廷","魏定国","萧让","裴宣","欧鹏","邓飞","燕顺","杨林","凌振","蒋敬","吕方","郭盛","安道全","皇浦端","王英","扈三娘","鲍旭","樊瑞","孔明","孔亮","项充","李衮","金大坚","马麟","童威","童猛","孟康","候建","陈达","杨春","郑天寿","陶宗旺","宋清","乐和","龚旺","丁得孙","穆春","曹正","宋万","杜迁","薛永","施恩","李忠","周通","汤隆","杜兴","邹渊","邹润","朱贵","朱富","蔡福","蔡庆","李立","李云","焦挺","石勇","孙新","顾大嫂","张青","孙二娘","王定六","郁保四","白胜","时迁","段景住"};}

123456789101112131415

activity代码

//(activity)MainActivityimport android.animation.FloatEvaluator;import android.graphics.Color;import android.os.Bundle;import android.support.annotation.NonNull;import android.support.v7.app.AppCompatActivity;import android.util.Log;import android.view.View;import android.view.ViewGroup;import android.widget.AdapterView;import android.widget.ArrayAdapter;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.ListView;import android.widget.SimpleAdapter;import android.widget.TextView;import android.widget.Toast;import com.test.slidemenu.R;import com.test.slidemenu.view.SlideMenu;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import butterknife.Bind;import butterknife.ButterKnife;import static com.test.slidemenu.conf.Constant.CONSTACTS;import static com.test.slidemenu.conf.Constant.SETTINGS;public class MainActivity extends AppCompatActivity {private static final String TAG = "MainActivity";private FloatEvaluator mFloatEvaluator;@Bind(R.id.iv_headMenuPic)ImageView mIvHeadMenuPic;@Bind(R.id.menu_listview)ListView mMenuListview;@Bind(R.id.menu_linearlayout)LinearLayout mMenuLinearlayout;@Bind(R.id.iv_headMainPic)ImageView mIvHeadMainPic;@Bind(R.id.main_listview)ListView mMainListview;@Bind(R.id.main_linearlayout)LinearLayout mMainLinearlayout;@Bind(R.id.slideMenu)SlideMenu mSlideMenu;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();initData();}private void initView() {ButterKnife.bind(this);mFloatEvaluator = new FloatEvaluator();}private void initData() {mMenuListview.setAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, SETTINGS) {@NonNull@Override// 修改布局属性public View getView(int position, View convertView, ViewGroup parent) {TextView textView = (TextView) super.getView(position, convertView, parent);textView.setTextColor(Color.parseColor("#FF3E96"));textView.setTextSize(18);textView.setSingleLine();return textView;}});mMenuListview.setDivider(null);mMenuListview.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {Toast.makeText(MainActivity.this, SETTINGS[i], Toast.LENGTH_SHORT).show();}});List<Map<String, Object>> data = new ArrayList<>();String[] from = {"pic", "contact" };int[] to = {R.id.iv_pic, R.id.tv_contact};mMainListview.setAdapter(new SimpleAdapter(MainActivity.this, data, R.layout.mainitem, from, to));for (int i = 0; i < CONSTACTS.length; i++) {Map<String, Object> map = new HashMap<>();map.put("pic", R.mipmap.pic);map.put("contact", CONSTACTS[i]);data.add(map);}mMainListview.setOnItemClickListener(new AdapterView.OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {Toast.makeText(MainActivity.this, CONSTACTS[i], Toast.LENGTH_SHORT).show();}});mSlideMenu.setOnSlideListener(new SlideMenu.OnSlideListener() {@Overridepublic void onOpen() {Toast.makeText(MainActivity.this, "onOpen", Toast.LENGTH_SHORT).show();}@Overridepublic void onClose() {Toast.makeText(MainActivity.this, "onClose", Toast.LENGTH_SHORT).show();}@Overridepublic void onDraging(float fraction) {Log.i(TAG, "fraction:" + fraction);// 沿着y轴旋转mIvHeadMainPic.setRotationY(mFloatEvaluator.evaluate(fraction, 0, 720));}});mIvHeadMenuPic.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Toast.makeText(MainActivity.this, "我是menuView头像", Toast.LENGTH_SHORT).show();}});mIvHeadMainPic.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Toast.makeText(MainActivity.this, "我是mainView头像", Toast.LENGTH_SHORT).show();}});}}

1234567891011121314151617181922232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811911122123124125126127128129130131132133134135136

使用Butterknife 需在Module的build.gradle中的dependencies节点下面添加:

compile 'com.jakewharton:butterknife:7.0.1'

1

目前最新版本为8.6.0。Butterknife配合ButterKnife Zelezny插件使用更佳

如果对Butterknife和ButterKnife Zelezny插件使用不太清楚可移步:Android中ButterKnife的使用(库和插件)/zxc514257857/article/details/59195960

Demo下载请移步:/detail/zxc514257857/9848331

———-因本人才疏学浅,如博客或Demo中有错误的地方请大家随意指出,与大家一起讨论,共同进步,谢谢!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。