自定義view——仿酷狗的側滑選單
直接貼原始碼:註解內容裡面都有
public class SlidingMenu extends HorizontalScrollView {
private final int mMenuWidth;
private View mMenuView;
private View mContentView;
//GestureDetector處理快速滑動
private GestureDetector mGestureDetector;
// 7.手指快速滑動 - 選單是否開啟
private boolean mMenuIsOpen = false;
private boolean mIsIntercept = false;
public SlidingMenu(Context context) {
this(context, null);
}
public SlidingMenu(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SlidingMenu(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.SlidingMenu);
float rightMarign = ta.getDimension(R.styleable.SlidingMenu_menuRightMargin, dip2px(context, 50));
//選單的寬度是螢幕的寬度-右邊的一部分距離(自定義屬性)
mMenuWidth = (int) (getScreenWidth(context) - rightMarign);
ta.recycle();
mGestureDetector = new GestureDetector(context, mGestureListener);
}
private GestureDetector.OnGestureListener mGestureListener = new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
//快速滑動
Log.e("TAG", "velocityX—>" + velocityX);//向右滑動大於0,向左滑動小於0
// Bug 判斷左右還是上下 只有左右快速滑動才切換
if(Math.abs(velocityY)>Math.abs(velocityX)){
return super.onFling(e1, e2, velocityX, velocityY);//預設返回的是false
}
if (mMenuIsOpen) {//選單是開啟的,且當向左滑動的時候關閉選單
if (velocityX < 0) {
closeMenu();
return true;
}
} else {//選單是關閉的,且當向右滑動的時候開啟選單
if (velocityX > 0) {
openMenu();
return true;
}
}
return super.onFling(e1, e2, velocityX, velocityY);//預設返回的是false
}
};
//1.寬度不對,指定寬高
@Override
protected void onFinishInflate() {
//這個方法是佈局解析完畢
super.onFinishInflate();
//指定寬高
ViewGroup container = (ViewGroup) getChildAt(0);//LinearLayout
//1.內容的寬度是螢幕的寬度
int childCount = container.getChildCount();
if (childCount != 2) {
throw new RuntimeException("只能放置兩個子View!");
}
mContentView = container.getChildAt(1);
ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();
layoutParams.width = getScreenWidth(getContext());
mContentView.setLayoutParams(layoutParams);
//2.選單的寬度是螢幕的寬度-右邊的一部分距離(自定義屬性)
mMenuView = container.getChildAt(0);
ViewGroup.LayoutParams menuParams = mMenuView.getLayoutParams();
menuParams.width = mMenuWidth;
mMenuView.setLayoutParams(menuParams);
}
//4.處理右邊的縮放,左邊的縮放和透明度,需要獲取當前不斷變化的位置
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
//Log.e("TAG", "l -> " + l);// 變化是 mMenuWidth - 0
float scale = 1f * l / mMenuWidth;//變化是1->0
//右邊的縮放 最小0.7f,最大1f
float rightScale = 0.7f + 0.3f * scale;
//設定右邊的縮放,預設是中心點(ViewCompat相容)
//設定中心點
ViewCompat.setPivotX(mContentView, 0);
ViewCompat.setPivotY(mContentView, mContentView.getMeasuredHeight() / 2);
ViewCompat.setScaleX(mContentView, rightScale);
ViewCompat.setScaleY(mContentView, rightScale);
//左邊縮放和透明度變化
//縮放是從0.7到1完全展開
float leftScale = 0.7f + (1 - scale) * 0.3f;
ViewCompat.setScaleX(mMenuView, leftScale);
ViewCompat.setScaleY(mMenuView, leftScale);
//透明度,半透明到完全透明
float leftAlpha = 0.5f + (1 - scale) * 0.5f;
ViewCompat.setAlpha(mMenuView, leftAlpha);
// 最後一個效果 退出這個按鈕剛開始是在右邊,安裝我們目前的方式永遠都是在左邊
// 設定平移,先看一個抽屜效果
// ViewCompat.setTranslationX(mMenuView,l);
// 平移 l*0.25f
ViewCompat.setTranslationX(mMenuView, 0.25f * l);
}
//點選右邊內容部分關閉選單
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
mIsIntercept = false;
if (mMenuIsOpen) {
float currentX = ev.getX();
if (currentX > mMenuWidth) {
//關閉選單
closeMenu();
//消費當前事件,攔截子view的事件,但是此時會呼叫自己的onTouchEvent事件
mIsIntercept = true;
return true;
}
}
return super.onInterceptTouchEvent(ev);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
//2.預設應該是關閉
scrollTo(mMenuWidth, 0);
}
//3.當抬起的時候二選一,要麼關閉要麼開啟
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (mIsIntercept) {//當是攔截事件,消費當前事件
return true;
}
if (mGestureDetector.onTouchEvent(ev)) {//當點選了快速滑動,則消費當前事件
return true;
}
// 1. 獲取手指滑動的速率,當期大於一定值就認為是快速滑動 , GestureDetector(系統提供好的類)
// 2. 處理事件攔截 + ViewGroup 事件分發的原始碼實踐
// 當選單開啟的時候,手指觸控右邊內容部分需要關閉選單,還需要攔截事件(開啟情況下點選內容頁不會響應點選事件)
if (ev.getAction() == MotionEvent.ACTION_UP) {
int currentScrollX = getScrollX();
if (currentScrollX > mMenuWidth / 2) {
//關閉
closeMenu();
} else {
//開啟
openMenu();
}
//確保不會呼叫super.onTouchEvent(ev),否則會不起作用
return true;
}
return super.onTouchEvent(ev);
}
/**
* 開啟選單
*/
private void openMenu() {
//smoothScrollTo有動畫
smoothScrollTo(0, 0);
mMenuIsOpen = true;
}
/**
* 關閉選單
*/
private void closeMenu() {
//smoothScrollTo有動畫
smoothScrollTo(mMenuWidth, 0);
mMenuIsOpen = false;
}
/**
* Dip into pixels
*/
private int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* 獲得螢幕寬度
*/
private int getScreenWidth(Context context) {
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
return outMetrics.widthPixels;
}
}
在上面的基礎上實現QQ6.0側滑效果
首先去掉縮放,其次新增陰影,縮放把之前程式碼直接註解掉就可以了
給內容佈局新增陰影:首先將內容佈局摳出來,然後套一個Relayout佈局新增內容和陰影,然後再設定回去
//1.內容的寬度是螢幕的寬度
int childCount = container.getChildCount();
if (childCount != 2) {
throw new RuntimeException("只能放置兩個子View!");
}
mContentView = container.getChildAt(1);
ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();
//內容佈區域性分新增陰影
//把內容佈局提取出來
container.removeView(mContentView);
//在外面新增一層陰影
RelativeLayout contentContainer = new RelativeLayout(getContext());
contentContainer.addView(mContentView);
mShadowView = new View(getContext());
mShadowView.setBackgroundColor(Color.parseColor("#55000000"));
contentContainer.addView(mShadowView);
//最後把容器放回原來的位置
layoutParams.width = getScreenWidth(getContext());
contentContainer.setLayoutParams(layoutParams);
container.addView(contentContainer);
mShadowView.setAlpha(0);
onScrollChanged方法中動態設定透明度
float scale = 1f * l / mMenuWidth;//變化是1->0
float alpha=1-scale;
mShadowView.setAlpha(alpha);
ViewCompat.setTranslationX(mMenuView, 0.6f * l);
相關文章
- 自定義View:側滑選單實現View
- 自定義View:側滑選單動畫實現View動畫
- Swift - 仿寫QQ側滑選單Swift
- Android自定義View(四)側滑佈局AndroidView
- (有圖)仿QQ側滑選單:RecyclerView側滑選單,長按拖拽,滑動刪除View
- 自定義ViewGroup,實現Android的側滑選單ViewAndroid
- Flutter | 超簡單仿微信QQ側滑選單元件Flutter元件
- 自定義View:實現炫酷的點贊特效(仿即刻)View特效
- 仿QQ側拉選單
- Flutter 自定義View——仿同花順自選股列表FlutterView
- layui自定義ajax左側三級選單UI
- 自定義RecyclerView實現側滑刪除View
- 【朝花夕拾】Android自定義View篇之(十一)View的滑動,彈性滑動與自定義PagerViewAndroidView
- 一個炫酷的仿雷達掃描和擴散效果——自定義View就是這麼簡單View
- 自定義控制元件?試試300行程式碼實現QQ側滑選單控制元件行程
- Flutter:手把手教你實現一個仿QQ側滑選單的功能Flutter
- 自定義View——仿騰訊TIM下拉重新整理ViewView
- 史上最簡單,一步整合側滑(刪除)選單,高仿QQ、IOS。iOS
- Android自定義View之高仿QQ健康AndroidView
- Android側滑選單DrawerLayout使用Android
- Android 自定義View 滑動解鎖AndroidView
- 『自定義View實戰』—— 仿ios圖示下載viewViewiOS
- android的左右側滑選單實現Android
- android 滑動刪除的listview(自定義view)AndroidView
- [提問交流]後臺新增自定義選單左側不顯示子選單的進
- Flutter自定義View——仿高德三級聯動DrawerFlutterView
- Android自定義View–仿QQ音樂歌詞AndroidView
- 原生Android 側滑選單實踐(部分)Android
- Flutter 仿iOS側滑返回案例實現FlutteriOS
- Android自定義View之實現簡單炫酷的球體進度球AndroidView
- MirrorSwipeLayout:自定義Layout,仿MIUI滑動返回(已開源)UI
- Android開發自定義View之滑動按鈕與自定義屬性AndroidView
- Android自定義View--仿QQ音樂歌詞AndroidView
- 自定義View高仿懂球帝我是教練效果View
- css3實現側邊滑動選單CSSS3
- 【只發精品】匠心打造Vue側滑選單元件Vue元件
- 自定義VIEWView
- 帶有視覺滾動差的選單側滑欄視覺