【自定义ViewGroup】仿知乎右下角FloatingActionMenuGroup (本人小白,纯记录)
来源:互联网 发布:乎是不是多音字 编辑:程序博客网 时间:2024/05/21 14:08
纯粹记录 。自己在做一个自己的小软件 就把知乎的设计拿过来了 。 右下角的那个悬浮菜单感觉不错 ,然后就搜了一下 有一个开源库 !但是他用的不是FloatingActionButton 写的, 我这种有强迫症的就受不了 , 就决定自己写一个。 刚好练练自定义ViewGroup这个自己并不熟悉的东东。
可能后边会有变化 发现现在写的有点变的复杂了。。。
一开始的思路是 :这个控件点开之后,左边是一个button ,右边是一个 FloatingActionButton ,最下方是自己本身的一个FloatingActionButton 。然后button的字从哪里
来呢 。所以先写了一个带text的FloatingActionButton
包含text textsize 和textcolor 三个属性
自定义 attrs.xml中自定义
<declare-styleable name="FloatingActionButtonWithText"> <attr name="ftext" format="string"></attr> <attr name="ftextsize" format="dimension"></attr> <attr name="ftextcolor" format="color"></attr></declare-styleable>
十分简单 代码
/** * 存储text的FloatingActionButton */public class FloatingActionButtonWithText extends FloatingActionButton { private String mText; private int mTextColor; private float mTextSize; public int getmTextColor() { return mTextColor; } public void setmTextColor(int mTextColor) { this.mTextColor = mTextColor; } public float getmTextSize() { return mTextSize; } public void setmTextSize(float mTextSize) { this.mTextSize = mTextSize; } public String getmText() { return mText; } public void setmText(String mText) { this.mText = mText; } public FloatingActionButtonWithText(Context context) { this(context,null); } public FloatingActionButtonWithText(Context context, AttributeSet attrs) { this(context, attrs,0); } public FloatingActionButtonWithText(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray attr = context.obtainStyledAttributes(attrs, R.styleable.FloatingActionButtonWithText, defStyleAttr,defStyleAttr); mText=attr.getString(R.styleable.FloatingActionButtonWithText_ftext); mTextColor=attr.getColor(R.styleable.FloatingActionButtonWithText_ftextcolor,getResources().getColor(R.color.black)); mTextSize=attr.getDimension(R.styleable.FloatingActionButtonWithText_ftextsize,15f); if(TextUtils.isEmpty(mText)){ mText="喵喵喵"; } }}好的 有文字了
接下来进正题 必然是一个ViewGroup 我就按照一开始的想法来吧 首先是一个不管是否打开菜单都存在的FloatingActionButton 还有一个白布 用的textview
attrs.xml 添加自定属性 每个item之间的间隔 和默认的FloatingActionButton 的图片 还有ViewGroup的padding 其实好像没必要这么写 但是都写了先这样了 懒。。。。
<declare-styleable name="FloatingActionMenuGroup"> <attr name="imageSrc" format="reference"></attr> <attr name="layout_bottom" format="dimension"></attr> <attr name="layout_right" format="dimension"></attr> <attr name="itemSpace" format="dimension"></attr></declare-styleable>实例化代码 初始化各种变量
public FloatingActionMenuGroup(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray attr = context.obtainStyledAttributes(attrs, R.styleable.FloatingActionMenuGroup, defStyleAttr,defStyleAttr); int imageID=attr.getResourceId(R.styleable.FloatingActionMenuGroup_imageSrc,R.drawable.yumao); layoutRight= (int) attr.getDimension(R.styleable.FloatingActionMenuGroup_layout_right,60f); layoutBottom= (int) attr.getDimension(R.styleable.FloatingActionMenuGroup_layout_bottom,60f); itemSpce=(int) attr.getDimension(R.styleable.FloatingActionMenuGroup_itemSpace,12f); mIndex=new FloatingActionButton(getContext()); mIndex.setImageResource(imageID); mIndex.setBackgroundTintList(getResources().getColorStateList(R.color.blue)); mIndex.setClickable(true); mIndex.setFocusable(true); mIndex.setBackgroundResource(R.drawable.view_clickbg); addView(mIndex); //添加进ViewGroup isOpen=false; def=DpPxUtils.dip2px(getContext(),56);//获取默认宽高 DisplayMetrics dm = new DisplayMetrics(); //取得窗口属性 ((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(dm); //窗口的宽度 int screenWidth = dm.widthPixels; screenScale=screenWidth/defWith; def= (int) (def*screenScale); subFbWith= (int) (def*0.8f); //子FloatingActionButton的宽 subBtHeight= (int) (subFbWith*0.8f);//item Button的高度 white=new TextView(getContext()); white.setClickable(true); white.setOnClickListener(this); white.setBackgroundColor(0xccffffff); white.setLayoutParams( new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT));}然后onMeasure方法中 开始添加各种View 还有测量子View的宽高
protected void onMeasure(int widthSpec, int heightSpec) { int width = 0; int height = 0; measureChild(mIndex,def,def); //先测量一直存在的Fb int count=getChildCount(); int fbcount=0; for(int i=0;i<count;i++){ final View view=getChildAt(i); if(view instanceof FloatingActionButtonWithText){ mFlbtList.add((FloatingActionButtonWithText) view); fbcount++; mButtonTexts.add(((FloatingActionButtonWithText) view).getmText()); if(subBtTextColor==-1){ subBtTextColor=((FloatingActionButtonWithText) view).getmTextColor(); subBtTextSize=((FloatingActionButtonWithText) view).getmTextSize(); } measureChild(view,subFbWith,subFbWith); } } for(String s:mButtonTexts){ if(mButtonList.size()<mButtonTexts.size()){ Button button=new Button(getContext()); button.setText(s); button.setTextColor(subBtTextColor); button.setTextSize(subBtTextSize); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { button.setBackgroundTintList(getResources().getColorStateList(R.color.white)); } button.setPadding(0,0,0,0); addView(button); mButtonList.add(button); button.measure(MeasureSpec.EXACTLY+(int)(150*screenScale),MeasureSpec.EXACTLY+subBtHeight);//默认为150根据屏幕比例放大缩小 subBtWith=button.getMeasuredWidth(); } } if(mButtonTexts.size()>0){ itemWith= (int) (def+subBtWith-(def*0.1));//宽度大概是button+mIndex的宽度 去掉0.1的mIndex宽度 }else{ itemWith=def; } width=itemWith; height= (int) (def+subFbWith*fbcount+fbcount*itemSpce); width+=2*layoutRight+itemSpce/3; //中间在加一些空隙 是button和fb之间的空隙 height+=2*layoutBottom; //上下的空隙 setMeasuredDimension(width,height); for(int i=0;i<count;i++){ getChildAt(i).setOnClickListener(this);//添加单击监听 }}然后就是onLayout方法 确定各个位置的布局@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) { int count=getChildCount(); if(isOpen){ subFbY=0; subBtY=0; for(int i=0;i<count;i++){ final View view=getChildAt(i); if(view instanceof FloatingActionButtonWithText){ int fabSomeWith= (int) (def*0.9f); view.layout(getWidth()-fabSomeWith-layoutRight,subFbY+layoutRight,getWidth()-fabSomeWith+subFbWith-layoutRight,subFbY+subFbWith+layoutRight); subFbY+=subFbWith+itemSpce; }else if(view instanceof Button){ int subSomeHeight= (int) (subFbWith*0.1f); view.layout(0+layoutRight,subBtY+subSomeHeight+layoutRight,subBtWith+layoutRight,subBtY+subBtHeight+subSomeHeight+layoutRight); subBtY+=subFbWith+itemSpce; }else{ mIndex.layout(getWidth()-def-layoutRight,getHeight()-def-layoutBottom,getWidth()-layoutRight,getHeight()-layoutBottom); } } }else{ mIndex.layout(getWidth()-def-layoutRight,getHeight()-def-layoutBottom,getWidth()-layoutRight,getHeight()-layoutBottom); }}到这里基本就完成啦 然后还差点击动画效果 还有展开! 以及传递点击效果出去的接口@Override public void onClick( View v) { CoordinatorLayout coordinatorLayout=((CoordinatorLayout)getParent()); if(v==mIndex){ if(isOpen){ isOpen=false; coordinatorLayout .removeView(white); }else{ isOpen=true; coordinatorLayout.addView(white,coordinatorLayout.getChildCount()-1); } openOrClose(); requestLayout(); }else if(v==white){ isOpen=false; coordinatorLayout .removeView(white); openOrClose(); requestLayout(); }else{ if(v instanceof Button){ if(isClick){ isClick=false; return; } for(Button button:mButtonList){ if(v==button){ for(FloatingActionButtonWithText f:mFlbtList){ if(button.getText().equals(f.getmText())){ MotionEvent evenDownt = MotionEvent.obtain(System.currentTimeMillis(), System.currentTimeMillis() + 100, MotionEvent.ACTION_DOWN, f.getX(), f.getY(), 0); isClick=true; dispatchTouchEvent(evenDownt); MotionEvent eventUp = MotionEvent.obtain(System.currentTimeMillis(), System.currentTimeMillis() + 100, MotionEvent.ACTION_UP, f.getX(), f.getY(), 0); dispatchTouchEvent(eventUp); evenDownt.recycle(); eventUp.recycle(); } } } } }else{ if(isClick){ isClick=false; if(onFloatingActionClickListener!=null){ onFloatingActionClickListener.onItemClick(((FloatingActionButtonWithText)v).getmText(),v); } return; } for(Button b:mButtonList){ //模拟点击一边 另外一边也有点击效果 if(((FloatingActionButtonWithText)v).getmText().equals(b.getText())){ MotionEvent evenDownt = MotionEvent.obtain(System.currentTimeMillis(), System.currentTimeMillis() + 100, MotionEvent.ACTION_DOWN, b.getX(), b.getY(), 0); isClick=true; dispatchTouchEvent(evenDownt); MotionEvent eventUp = MotionEvent.obtain(System.currentTimeMillis(), System.currentTimeMillis() + 100, MotionEvent.ACTION_UP, b.getX(), b.getY(), 0); dispatchTouchEvent(eventUp); evenDownt.recycle(); eventUp.recycle(); } } } } } private void openOrClose(){ for(int i=0;i<getChildCount();i++){ final View view=getChildAt(i); view.setVisibility(VISIBLE); if(view instanceof FloatingActionButtonWithText){ ObjectAnimator anim; if(!isOpen){ anim=ObjectAnimator.ofFloat(view,"subFb",1.0f,0.0f).setDuration(200); }else{ anim=ObjectAnimator.ofFloat(view,"subFb",0.0f,1.5f).setDuration(200); } anim.start(); anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float cVal = (Float) animation.getAnimatedValue(); if(isOpen){ if(cVal<=1.2f){ //弹性动画效果 view.setScaleX(cVal); view.setScaleY(cVal); }else{ view.setScaleX(2.5f-cVal); view.setScaleY(2.5f-cVal); } }else{ view.setScaleX(cVal); view.setScaleY(cVal); if(cVal==0){ view.setVisibility(INVISIBLE); } } } }); }else if(view instanceof Button){ ValueAnimator valueAnimator = new ValueAnimator(); valueAnimator.setDuration(200); if(isOpen){ valueAnimator.setObjectValues(new PointF(layoutRight, 0)); }else{ valueAnimator.setObjectValues(new PointF(layoutRight+subBtWith*0.2f, 0)); } valueAnimator.setInterpolator(new LinearInterpolator()); valueAnimator.setEvaluator(new TypeEvaluator<PointF>() { @Override public PointF evaluate(float fraction, PointF startValue, PointF endValue) { PointF point = new PointF(); if(isOpen){ point.x= layoutRight+subBtWith*0.2f-fraction*subBtWith*0.2f;// System.out.println("f"+fraction); }else{ point.x= layoutRight+fraction*subBtWith*0.2f; } return point; } }); valueAnimator.start(); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { PointF point = (PointF) animation.getAnimatedValue(); view.setX(point.x); if(animation.getAnimatedFraction()==1.0f){ //如果动画已经完成 if(!isOpen){ //关闭动画 view.setVisibility(INVISIBLE); } } } }); }else{ if(isOpen){ mIndex.setImageResource(R.drawable.cha); }else{ mIndex.setImageResource(R.drawable.yumao); } } } }public interface OnFloatingActionClick { void onItemClick(String text,View view);}最后上完整的代码public class FloatingActionMenuGroup extends ViewGroup implements View.OnClickListener { private boolean isOpen; private boolean isClick; private FloatingActionButton mIndex;//未打开时的显示 private OnFloatingActionClick onFloatingActionClickListener; private TextView white; private Set<String> mButtonTexts=new HashSet<>();//保存按钮的文字 private List<Button> mButtonList=new ArrayList<>(); //保存的按钮 private Set<FloatingActionButtonWithText> mFlbtList=new HashSet<>();//保存的字view private int def;//默认宽度 private final float defWith=1080f;//屏幕宽度用来计算比列 private float screenScale;//屏幕比例 private int itemWith;//viewgroup的宽度 private int subFbWith,subFbY;//子fab的宽高和绘制的Y轴位置 private int subBtHeight,subBtY,subBtWith,subBtTextColor=-1;//按钮的高度,按钮绘制的Y轴位置,按钮宽度,按钮字体颜色 private float subBtTextSize; //按钮的字体大小 private int layoutRight,layoutBottom;//预留的边界距离 private int itemSpce; public void setOnFloatingActionClickListener(OnFloatingActionClick onFloatingActionClickListener) { this.onFloatingActionClickListener = onFloatingActionClickListener; } public FloatingActionMenuGroup(Context context) { this(context,null); } public FloatingActionMenuGroup(Context context, AttributeSet attrs) { this(context, attrs,0); } public FloatingActionMenuGroup(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); TypedArray attr = context.obtainStyledAttributes(attrs, R.styleable.FloatingActionMenuGroup, defStyleAttr,defStyleAttr); int imageID=attr.getResourceId(R.styleable.FloatingActionMenuGroup_imageSrc,R.drawable.yumao); layoutRight= (int) attr.getDimension(R.styleable.FloatingActionMenuGroup_layout_right,60f); layoutBottom= (int) attr.getDimension(R.styleable.FloatingActionMenuGroup_layout_bottom,60f); itemSpce=(int) attr.getDimension(R.styleable.FloatingActionMenuGroup_itemSpace,12f); mIndex=new FloatingActionButton(getContext()); mIndex.setImageResource(imageID); mIndex.setBackgroundTintList(getResources().getColorStateList(R.color.blue)); mIndex.setClickable(true); mIndex.setFocusable(true); mIndex.setBackgroundResource(R.drawable.view_clickbg); addView(mIndex); isOpen=false; def=DpPxUtils.dip2px(getContext(),56);//获取默认宽高 DisplayMetrics dm = new DisplayMetrics(); //取得窗口属性 ((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(dm); //窗口的宽度 int screenWidth = dm.widthPixels; screenScale=screenWidth/defWith; def= (int) (def*screenScale); subFbWith= (int) (def*0.8f); subBtHeight= (int) (subFbWith*0.8f); white=new TextView(getContext()); white.setClickable(true); white.setOnClickListener(this); white.setBackgroundColor(0xccffffff); white.setLayoutParams( new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.MATCH_PARENT)); } @Override protected void onMeasure(int widthSpec, int heightSpec) { int width = 0; int height = 0; measureChild(mIndex,def,def); int count=getChildCount(); int fbcount=0; for(int i=0;i<count;i++){ final View view=getChildAt(i); if(view instanceof FloatingActionButtonWithText){ mFlbtList.add((FloatingActionButtonWithText) view); fbcount++; mButtonTexts.add(((FloatingActionButtonWithText) view).getmText()); if(subBtTextColor==-1){ subBtTextColor=((FloatingActionButtonWithText) view).getmTextColor(); subBtTextSize=((FloatingActionButtonWithText) view).getmTextSize(); } measureChild(view,subFbWith,subFbWith); } } for(String s:mButtonTexts){ if(mButtonList.size()<mButtonTexts.size()){ Button button=new Button(getContext()); button.setText(s); button.setTextColor(subBtTextColor); button.setTextSize(subBtTextSize); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { button.setBackgroundTintList(getResources().getColorStateList(R.color.white)); } button.setPadding(0,0,0,0); addView(button); mButtonList.add(button); button.measure(MeasureSpec.EXACTLY+(int)(150*screenScale),MeasureSpec.EXACTLY+subBtHeight); subBtWith=button.getMeasuredWidth(); } } if(mButtonTexts.size()>0){ itemWith= (int) (def+subBtWith-(def*0.1)); }else{ itemWith=def; } width=itemWith; height= (int) (def+subFbWith*fbcount+fbcount*itemSpce); width+=2*layoutRight+itemSpce/3; height+=2*layoutBottom; setMeasuredDimension(width,height); for(int i=0;i<count;i++){ getChildAt(i).setOnClickListener(this); } } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int count=getChildCount(); if(isOpen){ subFbY=0; subBtY=0; for(int i=0;i<count;i++){ final View view=getChildAt(i); if(view instanceof FloatingActionButtonWithText){ int fabSomeWith= (int) (def*0.9f); view.layout(getWidth()-fabSomeWith-layoutRight,subFbY+layoutRight,getWidth()-fabSomeWith+subFbWith-layoutRight,subFbY+subFbWith+layoutRight); subFbY+=subFbWith+itemSpce; }else if(view instanceof Button){ int subSomeHeight= (int) (subFbWith*0.1f); view.layout(0+layoutRight,subBtY+subSomeHeight+layoutRight,subBtWith+layoutRight,subBtY+subBtHeight+subSomeHeight+layoutRight); subBtY+=subFbWith+itemSpce; }else{ mIndex.layout(getWidth()-def-layoutRight,getHeight()-def-layoutBottom,getWidth()-layoutRight,getHeight()-layoutBottom); } } }else{ mIndex.layout(getWidth()-def-layoutRight,getHeight()-def-layoutBottom,getWidth()-layoutRight,getHeight()-layoutBottom); } } @Override public void onClick( View v) { CoordinatorLayout coordinatorLayout=((CoordinatorLayout)getParent()); if(v==mIndex){ if(isOpen){ isOpen=false; coordinatorLayout .removeView(white); }else{ isOpen=true; coordinatorLayout.addView(white,coordinatorLayout.getChildCount()-1); } openOrClose(); requestLayout(); }else if(v==white){ isOpen=false; coordinatorLayout .removeView(white); openOrClose(); requestLayout(); }else{ if(v instanceof Button){ if(isClick){ isClick=false; return; } for(Button button:mButtonList){ if(v==button){ for(FloatingActionButtonWithText f:mFlbtList){ if(button.getText().equals(f.getmText())){ MotionEvent evenDownt = MotionEvent.obtain(System.currentTimeMillis(), System.currentTimeMillis() + 100, MotionEvent.ACTION_DOWN, f.getX(), f.getY(), 0); isClick=true; dispatchTouchEvent(evenDownt); MotionEvent eventUp = MotionEvent.obtain(System.currentTimeMillis(), System.currentTimeMillis() + 100, MotionEvent.ACTION_UP, f.getX(), f.getY(), 0); dispatchTouchEvent(eventUp); evenDownt.recycle(); eventUp.recycle(); } } } } }else{ if(isClick){ isClick=false; if(onFloatingActionClickListener!=null){ onFloatingActionClickListener.onItemClick(((FloatingActionButtonWithText)v).getmText(),v); } return; } for(Button b:mButtonList){ if(((FloatingActionButtonWithText)v).getmText().equals(b.getText())){ MotionEvent evenDownt = MotionEvent.obtain(System.currentTimeMillis(), System.currentTimeMillis() + 100, MotionEvent.ACTION_DOWN, b.getX(), b.getY(), 0); isClick=true; dispatchTouchEvent(evenDownt); MotionEvent eventUp = MotionEvent.obtain(System.currentTimeMillis(), System.currentTimeMillis() + 100, MotionEvent.ACTION_UP, b.getX(), b.getY(), 0); dispatchTouchEvent(eventUp); evenDownt.recycle(); eventUp.recycle(); } } } } } private void openOrClose(){ for(int i=0;i<getChildCount();i++){ final View view=getChildAt(i); view.setVisibility(VISIBLE); if(view instanceof FloatingActionButtonWithText){ ObjectAnimator anim; if(!isOpen){ anim=ObjectAnimator.ofFloat(view,"subFb",1.0f,0.0f).setDuration(200); }else{ anim=ObjectAnimator.ofFloat(view,"subFb",0.0f,1.5f).setDuration(200); } anim.start(); anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float cVal = (Float) animation.getAnimatedValue(); if(isOpen){ if(cVal<=1.2f){ view.setScaleX(cVal); view.setScaleY(cVal); }else{ view.setScaleX(2.5f-cVal); view.setScaleY(2.5f-cVal); } }else{ view.setScaleX(cVal); view.setScaleY(cVal); if(cVal==0){ view.setVisibility(INVISIBLE); } } } }); }else if(view instanceof Button){ ValueAnimator valueAnimator = new ValueAnimator(); valueAnimator.setDuration(200); if(isOpen){ valueAnimator.setObjectValues(new PointF(layoutRight, 0)); }else{ valueAnimator.setObjectValues(new PointF(layoutRight+subBtWith*0.2f, 0)); } valueAnimator.setInterpolator(new LinearInterpolator()); valueAnimator.setEvaluator(new TypeEvaluator<PointF>() { @Override public PointF evaluate(float fraction, PointF startValue, PointF endValue) { PointF point = new PointF(); if(isOpen){ point.x= layoutRight+subBtWith*0.2f-fraction*subBtWith*0.2f;// System.out.println("f"+fraction); }else{ point.x= layoutRight+fraction*subBtWith*0.2f; } return point; } }); valueAnimator.start(); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { PointF point = (PointF) animation.getAnimatedValue(); view.setX(point.x); if(animation.getAnimatedFraction()==1.0f){ //如果动画已经完成 if(!isOpen){ //关闭动画 view.setVisibility(INVISIBLE); } } } }); }else{ if(isOpen){ mIndex.setImageResource(R.drawable.cha); }else{ mIndex.setImageResource(R.drawable.yumao); } } } } public interface OnFloatingActionClick { void onItemClick(String text,View view); }}对了还有布局<?xml version="1.0" encoding="utf-8"?><android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/mainfragment_drawer" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white" android:fitsSystemWindows="true"> <android.support.design.widget.CoordinatorLayout android:id="@+id/mianfragment_coor" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android:id="@+id/added_toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="@color/blue" app:layout_scrollFlags="scroll|enterAlways" app:popupTheme="@style/AppTheme.PopupOverlay"> <ImageView android:id="@+id/added_nag" android:layout_width="30dp" android:layout_height="30dp" android:src="@mipmap/left_menu" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingLeft="10dp" android:text="账号助手" android:textColor="@color/white" /> </android.support.v7.widget.Toolbar> </android.support.design.widget.AppBarLayout> <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/added_swip" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <android.support.v7.widget.RecyclerView android:id="@+id/added_recycler" android:layout_width="match_parent" android:layout_height="match_parent"> </android.support.v7.widget.RecyclerView> </android.support.v4.widget.SwipeRefreshLayout> <com.comic.help.view.FloatingActionMenuGroup android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="end|bottom" app:imageSrc="@drawable/yumao" app:itemSpace="10dp" app:layout_bottom="20dp" app:layout_right="20dp"> <com.comic.help.view.FloatingActionButtonWithText android:id="@+id/fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:clickable="true" android:background="@drawable/view_clickbg" android:src="@mipmap/menu2" app:backgroundTint="@color/white" app:elevation="5dp" app:ftext="初始" app:ftextcolor="@color/black" app:ftextsize="@dimen/dimen_5px" app:pressedTranslationZ="10dp" /> <com.comic.help.view.FloatingActionButtonWithText android:id="@+id/fab2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:clickable="true" android:background="@drawable/view_clickbg" android:src="@mipmap/menu3" app:backgroundTint="@color/white" app:elevation="5dp" app:ftext="恢复" app:ftextcolor="@color/black" app:ftextsize="@dimen/dimen_5px" app:pressedTranslationZ="10dp" /> </com.comic.help.view.FloatingActionMenuGroup> </android.support.design.widget.CoordinatorLayout> <android.support.design.widget.NavigationView android:id="@+id/applist_navigationmenu" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="left" app:headerLayout="@layout/header_just_username" app:menu="@menu/menu_drawer" /></android.support.v4.widget.DrawerLayout>完工 撒花 效果和知乎的还是有点像的 但是代码写的有点复杂 。。。我准备有空重构一下 看着太难受了
0 0
- 【自定义ViewGroup】仿知乎右下角FloatingActionMenuGroup (本人小白,纯记录)
- Android自定义ViewGroup记录
- Android小白进阶(二)--自定义控件之自定义ViewGroup
- Android学习小demo(2)自定义ViewGroup
- 自定义ViewGroup(一)
- 自定义ViewGroup(0)
- 自定义ViewGroup(一)
- 自定义ViewGroup(二)
- 自定义ViewGroup(三)
- 自定义控件之继承ViewGroup(使用纯代码)
- 自定义ViewGroup的一个小例子
- Android 自定义ViewGroup(一)
- 自定义ViewGroup (滚动布局)
- 自定义viewgroup(左右上下)
- 自定义控件(View viewGroup)
- 关于指针的一点理解(本人小白用户)
- 关于新手语言一些想法(本人也是小白)
- kafka基础(一)---本人小白,大牛多指教!
- gradle-wrapper.jar gradle-wrapper.properties 是干什么的
- 怎样实现前端裁剪上传图片功能
- python操作excel文件并输出txt文件
- Redis 和Memcache的区别
- Linux中jdk的安装
- 【自定义ViewGroup】仿知乎右下角FloatingActionMenuGroup (本人小白,纯记录)
- Spring Util常量类调用Service
- 新机器开发环境搭建
- Flink学习记录(一)
- win10系统 微软输入法 于eclipse ctrl+shif+f冲突间接处理办法
- Namespace declaration statement has to be the very first statement in the script--ThinkPHP3.2.3
- android耳机插拔的监听
- PHP实现快速排序
- linux 大并发测试需要的系统修改