Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android仿QQ6.0主頁面側滑效果

Android仿QQ6.0主頁面側滑效果

編輯:關於Android編程

1.概述

  最近一直都在帶實習生做項目,發現自己好久沒有寫博客了,這幾天更新會比較頻繁,今天玩QQ的時候發現QQ主頁菜單滑動效果早就變了,實在忍不住晚上就來實現一下了!

2.實現 

  2.1. 實現的方式多種多樣
  2.1.1 自定義ViewGroup ,處理其onTouch事件
  2.1.2 FrameLayout + 手勢處理類GestureDetector
  2.2.3 使用Google自帶的DrawerLayout 對其進行修改
  2.2.4 繼承自水平滾動HorizontalScrollView
大家可以看一下這個http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2016/0909/6612.html,這種方式繼承自ViewGroup,個人覺得還行但是還是比較繁瑣要處理的東西也比較多,那麼我就用最後一種2.2.4的方式實現,有人說直接去網上下載一個源代碼就可以了,這我就只能GG了。

  2.3. 自定義SlidingMenu extends HorizontalScrollView 然後寫好布局文件這個和ScrollView的用法一樣,只不過是橫向滾動的

/**
 * description:
 * 仿QQ5.0主頁面側滑的自定View
 * Created by 曾輝 on 2016/11/1.
 * QQ:240336124
 * Email: [email protected]
 * Version:1.0
 */
public class SlidingMenu extends HorizontalScrollView {
 public SlidingMenu(Context context) {
 super(context);
 }

 public SlidingMenu(Context context, AttributeSet attrs) {
 super(context, attrs);
 }

 public SlidingMenu(Context context, AttributeSet attrs, int defStyleAttr) {
 super(context, attrs, defStyleAttr);
 }
}

2.4. 運行起來之後發現布局不對,完全亂了明明都是match_parent可是就是不行那麼我們就需要用代碼指定菜單和內容的寬度:

菜單的寬度 = 屏幕的寬度 - 自定義的右邊留出的寬度
內容的寬度 = 屏幕的寬度

/**
 * description:
 * 仿QQ5.0主頁面側滑的自定View
 * Created by 曾輝 on 2016/11/1.
 * QQ:240336124
 * Email: [email protected]
 * Version:1.0
 */
public class SlidingMenu extends HorizontalScrollView {
 private View mMenuView;
 private View mContentView;
 private int mMenuWidth;

 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 array = context.obtainStyledAttributes(attrs,R.styleable.SlidingMenu);
 float rightPadding = array.getDimension(
  R.styleable.SlidingMenu_rightPadding,dip2px(50));
 // 計算菜單的寬度 = 屏幕的寬度 - 自定義右邊留出的寬度
 mMenuWidth = (int) (getScreenWidth() - rightPadding);
 array.recycle();
 }

 /**
 * 把dip 轉成像素
 */
 private float dip2px(int dip) {
 return TypedValue.applyDimension(
  TypedValue.COMPLEX_UNIT_DIP,dip,getResources().getDisplayMetrics());
 }


 @Override
 protected void onFinishInflate() {
 super.onFinishInflate();

 // 1.獲取根View也就是外層的LinearLayout
 ViewGroup container = (ViewGroup) this.getChildAt(0);

 int containerChildCount = container.getChildCount();
 if(containerChildCount>2){
  // 裡面只允許放置兩個布局 一個是Menu(菜單布局) 一個是Content(主頁內容布局)
  throw new IllegalStateException("SlidingMenu 根布局LinearLayout下面只允許兩個布局,菜單布局和主頁內容布局");
 }

 // 2.獲取菜單和內容布局
 mMenuView = container.getChildAt(0);
 mContentView = container.getChildAt(1);

 // 3.指定內容和菜單布局的寬度
 // 3.1 菜單的寬度 = 屏幕的寬度 - 自定義的右邊留出的寬度
 mMenuView.getLayoutParams().width = mMenuWidth;
 // 3.2 內容的寬度 = 屏幕的寬度
 mContentView.getLayoutParams().width = getScreenWidth();
 }

 /**
 * 獲取屏幕的寬度
 */
 public int getScreenWidth() {
 Resources resources = this.getResources();
 DisplayMetrics dm = resources.getDisplayMetrics();
 return dm.widthPixels;
 }
}

目前的效果就是可以滑動,並且菜單和主頁面內容的布局寬度正常

  2.5 接下來一開始就讓菜單滑動到關閉狀態,手指滑動抬起判斷菜單打開和關閉並做相應的處理 onLayout() onTouch() smoothScrollTo(),當手指快速的時候切換菜單的狀態利用GestureDetector 手勢處理類:

 /**
 * description:
 * 仿QQ5.0主頁面側滑的自定View
 * Created by 曾輝 on 2016/11/1.
 * QQ:240336124
 * Email: [email protected]
 * Version:1.0
 */
public class SlidingMenu extends HorizontalScrollView {
 private View mMenuView;
 private View mContentView;
 private int mMenuWidth;
 // 手勢處理類 主要用來處理手勢快速滑動
 private GestureDetector mGestureDetector;

 // 菜單是否打開
 private boolean mMenuIsOpen = 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 array = context.obtainStyledAttributes(attrs, R.styleable.SlidingMenu);
 float rightPadding = array.getDimension(
  R.styleable.SlidingMenu_rightPadding, dip2px(50));
 // 計算菜單的寬度 = 屏幕的寬度 - 自定義右邊留出的寬度
 mMenuWidth = (int) (getScreenWidth() - rightPadding);
 array.recycle();

 // 實例化手勢處理類
 mGestureDetector = new GestureDetector(context,new GestureListener());
 }

 /**
 * 把dip 轉成像素
 */
 private float dip2px(int dip) {
 return TypedValue.applyDimension(
  TypedValue.COMPLEX_UNIT_DIP, dip, getResources().getDisplayMetrics());
 }


 @Override
 protected void onFinishInflate() {
 super.onFinishInflate();

 // 1.獲取根View也就是外層的LinearLayout
 ViewGroup container = (ViewGroup) this.getChildAt(0);

 int containerChildCount = container.getChildCount();
 if (containerChildCount > 2) {
  // 裡面只允許放置兩個布局 一個是Menu(菜單布局) 一個是Content(主頁內容布局)
  throw new IllegalStateException("SlidingMenu 根布局LinearLayout下面只允許兩個布局,菜單布局和主頁內容布局");
 }

 // 2.獲取菜單和內容布局
 mMenuView = container.getChildAt(0);
 mContentView = container.getChildAt(1);

 // 3.指定內容和菜單布局的寬度
 // 3.1 菜單的寬度 = 屏幕的寬度 - 自定義的右邊留出的寬度
 mMenuView.getLayoutParams().width = mMenuWidth;
 // 3.2 內容的寬度 = 屏幕的寬度
 mContentView.getLayoutParams().width = getScreenWidth();
 }

 @Override
 public boolean onTouchEvent(MotionEvent ev) {

 // 處理手指快速滑動
 if(mGestureDetector.onTouchEvent(ev)){
  return mGestureDetector.onTouchEvent(ev);
 }

 switch (ev.getAction()) {
  case MotionEvent.ACTION_UP:
  // 手指抬起獲取滾動的位置
  int currentScrollX = getScrollX();
  if (currentScrollX > mMenuWidth / 2) {
   // 關閉菜單
   closeMenu();
  } else {
   // 打開菜單
   openMenu();
  }
  return false;
 }
 return super.onTouchEvent(ev);
 }

 /**
 * 打開菜單
 */
 private void openMenu() {
 smoothScrollTo(0, 0);
 mMenuIsOpen = true;
 }

 /**
 * 關閉菜單
 */
 private void closeMenu() {
 smoothScrollTo(mMenuWidth, 0);
 mMenuIsOpen = false;
 }

 @Override
 protected void onLayout(boolean changed, int l, int t, int r, int b) {
 super.onLayout(changed, l, t, r, b);
 // 布局指定後會從新擺放子布局,當其擺放完畢後,讓菜單滾動到不可見狀態
 if (changed) {
  scrollTo(mMenuWidth, 0);
 }
 }

 /**
 * 獲取屏幕的寬度
 */
 public int getScreenWidth() {
 Resources resources = this.getResources();
 DisplayMetrics dm = resources.getDisplayMetrics();
 return dm.widthPixels;
 }


 private class GestureListener extends GestureDetector.SimpleOnGestureListener{
 @Override
 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
  // 當手指快速滑動時候回調的方法
  Log.e("TAG",velocityX+"");
  // 如果菜單打開 並且是向左快速滑動 切換菜單的狀態
  if(mMenuIsOpen){
  if(velocityX<-500){
   toggleMenu();
   return true;
  }
  }else{
  // 如果菜單關閉 並且是向右快速滑動 切換菜單的狀態
  if(velocityX>500){
   toggleMenu();
   return true;
  }
  }

  return false;
 }
 }

 /**
 * 切換菜單的狀態
 */
 private void toggleMenu() {
 if(mMenuIsOpen){
  closeMenu();
 }else{
  openMenu();
 }
 }
}

到了這一步之後我們就可以切換菜單了,並且處理了手指快速滑動,迫不及待的看下效果

2.6. 實現菜單左邊抽屜樣式的動畫效果,監聽滾動回調的方法onScrollChanged() 這個就非常簡單了一句話就搞定,效果就不看了一起看終極效果吧

@Override
 protected void onScrollChanged(int l, int t, int oldl, int oldt) {
 super.onScrollChanged(l, t, oldl, oldt);

 // l 是 當前滾動的x距離 在滾動的時候會不斷反復的回調這個方法
 Log.e(TAG,l+"");

 mMenuView.setTranslationX(l*0.8f);
 }

2.7. 實現菜單右邊菜單的陰影透明度效果,這個打算在主頁面內容布局上面加一層陰影,用ImageView即可,那麼我們的內容View就需要換了

/**
 * description:
 * 仿QQ5.0主頁面側滑的自定View
 * Created by 曾輝 on 2016/11/1.
 * QQ:240336124
 * Email: [email protected]
 * Version:1.0
 */
public class SlidingMenu extends HorizontalScrollView {
 private static final String TAG = "HorizontalScrollView";
 private Context mContext;

 // 4.給菜單和內容View指定寬高 - 左邊菜單View
 private View mMenuView;

 // 4.給菜單和內容View指定寬高 - 菜單的寬度
 private int mMenuWidth;
 // 5.3 手勢處理類 主要用來處理手勢快速滑動
 private GestureDetector mGestureDetector;
 // 5.3 菜單是否打開
 private boolean mMenuIsOpen = false;

 // 7(4). 主頁面內容View的布局包括陰影ImageView
 private ViewGroup mContentView;
 // 7.給內容添加陰影效果 - 陰影的ImageView
 private ImageView mShadowIv;

 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);
 //4.1 計算左邊菜單的寬度
 //4.1.1 獲取自定義的右邊留出的寬度
 TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.SlidingMenu);
 float rightPadding = array.getDimension(
  R.styleable.SlidingMenu_rightPadding, dip2px(50));
 // 4.1.2 計算菜單的寬度 = 屏幕的寬度 - 自定義右邊留出的寬度
 mMenuWidth = (int) (getScreenWidth() - rightPadding);
 array.recycle();

 // 5.3 實例化手勢處理類
 mGestureDetector = new GestureDetector(context,new GestureListener());

 this.mContext = context;
 }

 /**
 * 把dip 轉成像素
 */
 private float dip2px(int dip) {
 return TypedValue.applyDimension(
  TypedValue.COMPLEX_UNIT_DIP, dip, getResources().getDisplayMetrics());
 }


 @Override
 protected void onFinishInflate() {
 super.onFinishInflate();
 // 4.2 指定菜單和內容View的寬度
 // 4.2.1.獲取根View也就是外層的LinearLayout
 ViewGroup container = (ViewGroup) this.getChildAt(0);

 int containerChildCount = container.getChildCount();
 if (containerChildCount > 2) {
  // 裡面只允許放置兩個布局 一個是Menu(菜單布局) 一個是Content(主頁內容布局)
  throw new IllegalStateException("SlidingMenu 根布局LinearLayout下面只允許兩個布局,菜單布局和主頁內容布局");
 }

 // 4.2.2.獲取菜單和內容布局
 mMenuView = container.getChildAt(0);

 // 7.給內容添加陰影效果
 // 7.1 先new一個主內容布局用來放 陰影和LinearLayout原來的內容布局
 mContentView = new FrameLayout(mContext);
 ViewGroup.LayoutParams contentParams = new ViewGroup.LayoutParams(
  ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT);

 // 7.2 獲取原來的內容布局,並把原來的內容布局從LinearLayout中異常
 View oldContentView = container.getChildAt(1);
 container.removeView(oldContentView);

 // 7.3 把原來的內容View 和 陰影加到我們新創建的內容布局中
 mContentView.addView(oldContentView);
 // 7.3.1 創建陰影ImageView
 mShadowIv = new ImageView(mContext);
 mShadowIv.setBackgroundColor(Color.parseColor("#99000000"));
 mContentView.addView(mShadowIv);

 // 7.4 把包含陰影的新的內容View 添加到 LinearLayout中
 container.addView(mContentView);

 // 4.2.3.指定內容和菜單布局的寬度
 // 4.2.3.1 菜單的寬度 = 屏幕的寬度 - 自定義的右邊留出的寬度
 mMenuView.getLayoutParams().width = mMenuWidth;
 // 4.2.3.2 內容的寬度 = 屏幕的寬度
 mContentView.getLayoutParams().width = getScreenWidth();
 }

 /**
 * 5.處理手指抬起和快速滑動切換菜單
 */
 @Override
 public boolean onTouchEvent(MotionEvent ev) {
 // 5.3 處理手指快速滑動
 if(mGestureDetector.onTouchEvent(ev)){
  return mGestureDetector.onTouchEvent(ev);
 }

 switch (ev.getAction()) {
  case MotionEvent.ACTION_UP:
  // 5.1 手指抬起獲取滾動的位置
  int currentScrollX = getScrollX();
  if (currentScrollX > mMenuWidth / 2) {
   // 5.1.1 關閉菜單
   closeMenu();
  } else {
   // 5.1.2 打開菜單
   openMenu();
  }
  return false;
 }
 return super.onTouchEvent(ev);
 }

 @Override
 protected void onScrollChanged(int l, int t, int oldl, int oldt) {
 super.onScrollChanged(l, t, oldl, oldt);

 // l 是 當前滾動的x距離 在滾動的時候會不斷反復的回調這個方法
 Log.e(TAG,l+"");
 // 6. 實現菜單左邊抽屜樣式的動畫效果
 mMenuView.setTranslationX(l*0.8f);

 // 7.給內容添加陰影效果 - 計算梯度值
 float gradientValue = l * 1f / mMenuWidth;// 這是 1 - 0 變化的值

 // 7.給內容添加陰影效果 - 給陰影的View指定透明度 0 - 1 變化的值
 float shadowAlpha = 1 - gradientValue;
 mShadowIv.setAlpha(shadowAlpha);
 }

 /**
 * 5.1.2 打開菜單
 */
 private void openMenu() {
 smoothScrollTo(0, 0);
 mMenuIsOpen = true;
 }

 /**
 * 5.1.1 關閉菜單
 */
 private void closeMenu() {
 smoothScrollTo(mMenuWidth, 0);
 mMenuIsOpen = false;
 }

 @Override
 protected void onLayout(boolean changed, int l, int t, int r, int b) {
 super.onLayout(changed, l, t, r, b);
 // 布局指定後會從新擺放子布局,當其擺放完畢後,讓菜單滾動到不可見狀態
 if (changed) {
  scrollTo(mMenuWidth, 0);
 }
 }

 /**
 * 獲取屏幕的寬度
 */
 public int getScreenWidth() {
 Resources resources = this.getResources();
 DisplayMetrics dm = resources.getDisplayMetrics();
 return dm.widthPixels;
 }


 /**
 * 5.3 處理手指快速滑動
 */
 private class GestureListener extends GestureDetector.SimpleOnGestureListener{
 @Override
 public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
  // 當手指快速滑動時候回調的方法
  Log.e(TAG,velocityX+"");
  // 5.3.1 如果菜單打開 並且是向左快速滑動 切換菜單的狀態
  if(mMenuIsOpen){
  if(velocityX<0){
   toggleMenu();
   return true;
  }
  }else{
  // 5.3.2 如果菜單關閉 並且是向右快速滑動 切換菜單的狀態
  if(velocityX>0){
   toggleMenu();
   return true;
  }
  }
  return false;
 }
 }

 /**
 * 切換菜單的狀態
 */
 private void toggleMenu() {
 if(mMenuIsOpen){
  closeMenu();
 }else{
  openMenu();
 }
 }
}

我們來看一下最後的效果吧,最終代碼量不是很多啦,需要的請下載源碼,如果是實現QQ5.0或是酷狗的側滑效果可以自己改改。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved