Android自定义View 仿QQ侧滑菜单的实现代码

时间:2021-05-20

先看看QQ的侧滑效果

分析一下

先上原理图(不知道能否表达的清楚 ==)

-首先这里使用了 Android 的HorizontalScrollView 水平滑动布局作为容器,当然我们需要继承它自定义一个侧滑视图

- 这个容器里面有一个父布局(一般用LinerLayout,本demo用的是),这个父布局里面有且只有两个子控件(布局),初始状态菜单页的位置在Y轴上存在偏移这样可以就可以形成主页叠在菜单页的上方的视觉效果;然后在滑动的过程程中 逐渐修正偏移,最后菜单页和主页并排排列。原理搞清了实现起来就不是事儿了……

具体实现

布局代码

<fierce_luk.com.sideslipviewdemo2.SideslipView android:id="@+id/my_veiw" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="none" luk:leftPanding="200dp"> <!--如果菜单在左边直接用 LinearLayout--> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal"> <TextView android:id="@+id/image2" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@mipmap/homepage" android:gravity="center" android:tag="0" android:text="菜单" android:textColor="@color/colorAccent" android:textSize="60sp" /> <TextView android:id="@+id/image1" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/color1" android:gravity="center" android:tag="1" android:text="主页面" android:textColor="@color/colorAccent" android:textSize="60sp" /> </FrameLayout> <!--<fragment--> <!--android:name="com.luk.bluetoothapp.fragment.MyBluetoothDevice"--> <!--android:layout_width="match_parent"--> <!--android:layout_height="match_parent"--> <!--android:tag="1" />--> <!--<fragment--> <!--android:name="com.luk.bluetoothapp.fragment.HomeFragment"--> <!--android:layout_width="match_parent"--> <!--android:layout_height="match_parent"--> <!--android:tag="0" />--> </fierce_luk.com.sideslipviewdemo2.SideslipView>

自定义的侧滑视图

最核心的部分

public class SideslipView extends HorizontalScrollView { private int mScreenWidth;//屏幕宽度 private int mMenuLeftPadding; private int mBluetoothWidth;//菜单的宽度 private int mHalfMenuWidth; View home; View bluetooth; protected boolean isOpen; protected boolean isFirst = true; public SideslipView(Context context) { // super 改 this this(context, null); } public SideslipView(Context context, AttributeSet attrs) { // super 改 this this(context, attrs, 0); } public SideslipView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); //测量屏幕宽度 WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics metrics = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(metrics); mScreenWidth = metrics.widthPixels; // mScreenWidth = context.getResources().getDisplayMetrics().widthPixels; Log.e("TAG", "MyScrollView: mScreenWidth" + mScreenWidth); //获取 自定义的属性值 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MyScrollView); int n = a.length(); for (int i = 0; i < n; i++) { int arrt = a.getIndex(i); switch (arrt) { case R.styleable.MyScrollView_leftPanding: mMenuLeftPadding = (int) a.getDimension(R.styleable.MyScrollView_leftPanding, 0); break; default: break; } } Log.e("TAG", "MyScrollView: mMenuLeftPadding" + mMenuLeftPadding); a.recycle(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (isFirst) { //获取子布局 并设置宽度 //如果菜单在左边 用LinearLayout就行// LinearLayout layout = (LinearLayout) this.getChildAt(0); /**此处因为 把侧边拉出页面设置在了右边 所有用 FrameLayout * 不然在设置偏移量时 隐藏的侧边菜单会跑到主页面的上面*/ FrameLayout layout = (FrameLayout) this.getChildAt(0); home = layout.getChildAt(1); bluetooth = layout.getChildAt(0); LayoutParams params = new LayoutParams(mBluetoothWidth, getResources().getDisplayMetrics().heightPixels); params.setMargins(mScreenWidth, 0, 0, 0); bluetooth.setLayoutParams(params); mBluetoothWidth = mScreenWidth - mMenuLeftPadding; home.getLayoutParams().width = mScreenWidth; bluetooth.getLayoutParams().width = mBluetoothWidth; mHalfMenuWidth = mBluetoothWidth / 2; isFirst = false; } 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); //首先隐藏 Bluetooth if (changed) this.scrollTo(0, mBluetoothWidth); } Animation anim; @Override public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_UP: int scrollX = getScrollX(); if (scrollX >= mHalfMenuWidth) { Log.e("TAG", "===="); this.smoothScrollTo(mBluetoothWidth, 0); isOpen = true; } else { this.smoothScrollTo(0, 0); isOpen = false; } //必须消耗事件 return true; } return super.onTouchEvent(ev); //return true; } /** * 打开菜单栏 */ protected void openMenu() { if (isOpen) return; this.smoothScrollTo(mBluetoothWidth, 0); isOpen = true; } /** * 关闭菜单栏 */ protected void closeMenu() { if (!isOpen) return; this.smoothScrollTo(0, 0); isOpen = false; } /** * 按钮切换菜单 */ public void toggleMenu() { if (isOpen) closeMenu(); else openMenu(); } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt);//此处 l 起始值为零(没有偏移) Log.e("TAG", "l=" + l + " t=" + t); Log.e("TAG", "oldl=" + oldl + " oldt=" + oldt); // scale 在 1 到 0 之间 float scale = l * 1.0f / mBluetoothWidth; /** * 抽屉式侧滑 * scaleLeft 从默认偏移量到偏移量 为零 *实现 * */ float scaleLeft = 0.4f - 0.4f * scale; /**设置 X 轴方向的偏移量**/ ViewHelper.setTranslationX(bluetooth, -(mBluetoothWidth * scaleLeft)); Log.e("TAG", "mBluetoothWidth+" + mBluetoothWidth); Log.e("TAG", "=============" + mBluetoothWidth * scale + "scale" + scale);/**设置缩放时的 轴心点**//**设置 XY轴方向的 缩放动画(从 1 到 0.9)**//* float pivoXY = 1 - 0.4f * scale; ViewHelper.setScaleX(home, pivoXY); ViewHelper.setScaleY(home, pivoXY);*//**设置透明度**//* //从 1 到 0.6; float alpha = 1 - 0.4f * scale; ViewHelper.setAlpha(home, alpha);*/ }}

扩展

添加之定义属性 让用户配置菜单距离右边的边距的值;
首先在values文件夹下新建一个attr.xml,写入以下内容:

<resources> <declare-styleable name="MyScrollView"> <attr name="rightPanding" format="dimension" /> <attr name="leftPanding" format="dimension" /> </declare-styleable></resources>

在布局里设置边距

<fierce_luk.com.sideslipviewdemo2.SideslipView android:id="@+id/my_veiw" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="none" luk:leftPanding="200dp">

其他的就不赘述了,看看效果

- 源码下载Demo源码点击下载

总结

以上所述是小编给大家介绍的Android自定义View 仿QQ侧滑菜单的实现代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!

声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。

相关文章