Android仿QQ6.0主頁面?zhèn)然Ч?/h1>
更新時間:2016年11月02日 10:11:51 作者:z240336124
這篇文章主要為大家詳細介紹了Android仿QQ6.0主頁面?zhèn)然Ч?具有一定的參考價值,感興趣的小伙伴們可以參考一下
1.概述
最近一直都在帶實習(xí)生做項目,發(fā)現(xiàn)自己好久沒有寫博客了,這幾天更新會比較頻繁,今天玩QQ的時候發(fā)現(xiàn)QQ主頁菜單滑動效果早就變了,實在忍不住晚上就來實現(xiàn)一下了!

2.實現(xiàn)
2.1. 實現(xiàn)的方式多種多樣
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的方式實現(xiàn),有人說直接去網(wǎng)上下載一個源代碼就可以了,這我就只能GG了。
2.3. 自定義SlidingMenu extends HorizontalScrollView 然后寫好布局文件這個和ScrollView的用法一樣,只不過是橫向滾動的
/**
* description:
* 仿QQ5.0主頁面?zhèn)然淖远╒iew
* Created by 曾輝 on 2016/11/1.
* QQ:240336124
* Email: 240336124@qq.com
* 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. 運行起來之后發(fā)現(xiàn)布局不對,完全亂了明明都是match_parent可是就是不行那么我們就需要用代碼指定菜單和內(nèi)容的寬度:
菜單的寬度 = 屏幕的寬度 - 自定義的右邊留出的寬度
內(nèi)容的寬度 = 屏幕的寬度
/**
* description:
* 仿QQ5.0主頁面?zhèn)然淖远╒iew
* Created by 曾輝 on 2016/11/1.
* QQ:240336124
* Email: 240336124@qq.com
* 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 轉(zhuǎn)成像素
*/
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(主頁內(nèi)容布局)
throw new IllegalStateException("SlidingMenu 根布局LinearLayout下面只允許兩個布局,菜單布局和主頁內(nèi)容布局");
}
// 2.獲取菜單和內(nèi)容布局
mMenuView = container.getChildAt(0);
mContentView = container.getChildAt(1);
// 3.指定內(nèi)容和菜單布局的寬度
// 3.1 菜單的寬度 = 屏幕的寬度 - 自定義的右邊留出的寬度
mMenuView.getLayoutParams().width = mMenuWidth;
// 3.2 內(nèi)容的寬度 = 屏幕的寬度
mContentView.getLayoutParams().width = getScreenWidth();
}
/**
* 獲取屏幕的寬度
*/
public int getScreenWidth() {
Resources resources = this.getResources();
DisplayMetrics dm = resources.getDisplayMetrics();
return dm.widthPixels;
}
}
目前的效果就是可以滑動,并且菜單和主頁面內(nèi)容的布局寬度正常

2.5 接下來一開始就讓菜單滑動到關(guān)閉狀態(tài),手指滑動抬起判斷菜單打開和關(guān)閉并做相應(yīng)的處理 onLayout() onTouch() smoothScrollTo(),當手指快速的時候切換菜單的狀態(tài)利用GestureDetector 手勢處理類:
/**
* description:
* 仿QQ5.0主頁面?zhèn)然淖远╒iew
* Created by 曾輝 on 2016/11/1.
* QQ:240336124
* Email: 240336124@qq.com
* 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 轉(zhuǎn)成像素
*/
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(主頁內(nèi)容布局)
throw new IllegalStateException("SlidingMenu 根布局LinearLayout下面只允許兩個布局,菜單布局和主頁內(nèi)容布局");
}
// 2.獲取菜單和內(nèi)容布局
mMenuView = container.getChildAt(0);
mContentView = container.getChildAt(1);
// 3.指定內(nèi)容和菜單布局的寬度
// 3.1 菜單的寬度 = 屏幕的寬度 - 自定義的右邊留出的寬度
mMenuView.getLayoutParams().width = mMenuWidth;
// 3.2 內(nèi)容的寬度 = 屏幕的寬度
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) {
// 關(guān)閉菜單
closeMenu();
} else {
// 打開菜單
openMenu();
}
return false;
}
return super.onTouchEvent(ev);
}
/**
* 打開菜單
*/
private void openMenu() {
smoothScrollTo(0, 0);
mMenuIsOpen = true;
}
/**
* 關(guān)閉菜單
*/
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);
// 布局指定后會從新擺放子布局,當其擺放完畢后,讓菜單滾動到不可見狀態(tài)
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) {
// 當手指快速滑動時候回調(diào)的方法
Log.e("TAG",velocityX+"");
// 如果菜單打開 并且是向左快速滑動 切換菜單的狀態(tài)
if(mMenuIsOpen){
if(velocityX<-500){
toggleMenu();
return true;
}
}else{
// 如果菜單關(guān)閉 并且是向右快速滑動 切換菜單的狀態(tài)
if(velocityX>500){
toggleMenu();
return true;
}
}
return false;
}
}
/**
* 切換菜單的狀態(tài)
*/
private void toggleMenu() {
if(mMenuIsOpen){
closeMenu();
}else{
openMenu();
}
}
}
到了這一步之后我們就可以切換菜單了,并且處理了手指快速滑動,迫不及待的看下效果

2.6. 實現(xiàn)菜單左邊抽屜樣式的動畫效果,監(jiān)聽滾動回調(diào)的方法onScrollChanged() 這個就非常簡單了一句話就搞定,效果就不看了一起看終極效果吧
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
// l 是 當前滾動的x距離 在滾動的時候會不斷反復(fù)的回調(diào)這個方法
Log.e(TAG,l+"");
mMenuView.setTranslationX(l*0.8f);
}
2.7. 實現(xiàn)菜單右邊菜單的陰影透明度效果,這個打算在主頁面內(nèi)容布局上面加一層陰影,用ImageView即可,那么我們的內(nèi)容View就需要換了
/**
* description:
* 仿QQ5.0主頁面?zhèn)然淖远╒iew
* Created by 曾輝 on 2016/11/1.
* QQ:240336124
* Email: 240336124@qq.com
* Version:1.0
*/
public class SlidingMenu extends HorizontalScrollView {
private static final String TAG = "HorizontalScrollView";
private Context mContext;
// 4.給菜單和內(nèi)容View指定寬高 - 左邊菜單View
private View mMenuView;
// 4.給菜單和內(nèi)容View指定寬高 - 菜單的寬度
private int mMenuWidth;
// 5.3 手勢處理類 主要用來處理手勢快速滑動
private GestureDetector mGestureDetector;
// 5.3 菜單是否打開
private boolean mMenuIsOpen = false;
// 7(4). 主頁面內(nèi)容View的布局包括陰影ImageView
private ViewGroup mContentView;
// 7.給內(nèi)容添加陰影效果 - 陰影的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 轉(zhuǎn)成像素
*/
private float dip2px(int dip) {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, dip, getResources().getDisplayMetrics());
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
// 4.2 指定菜單和內(nèi)容View的寬度
// 4.2.1.獲取根View也就是外層的LinearLayout
ViewGroup container = (ViewGroup) this.getChildAt(0);
int containerChildCount = container.getChildCount();
if (containerChildCount > 2) {
// 里面只允許放置兩個布局 一個是Menu(菜單布局) 一個是Content(主頁內(nèi)容布局)
throw new IllegalStateException("SlidingMenu 根布局LinearLayout下面只允許兩個布局,菜單布局和主頁內(nèi)容布局");
}
// 4.2.2.獲取菜單和內(nèi)容布局
mMenuView = container.getChildAt(0);
// 7.給內(nèi)容添加陰影效果
// 7.1 先new一個主內(nèi)容布局用來放 陰影和LinearLayout原來的內(nèi)容布局
mContentView = new FrameLayout(mContext);
ViewGroup.LayoutParams contentParams = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT);
// 7.2 獲取原來的內(nèi)容布局,并把原來的內(nèi)容布局從LinearLayout中異常
View oldContentView = container.getChildAt(1);
container.removeView(oldContentView);
// 7.3 把原來的內(nèi)容View 和 陰影加到我們新創(chuàng)建的內(nèi)容布局中
mContentView.addView(oldContentView);
// 7.3.1 創(chuàng)建陰影ImageView
mShadowIv = new ImageView(mContext);
mShadowIv.setBackgroundColor(Color.parseColor("#99000000"));
mContentView.addView(mShadowIv);
// 7.4 把包含陰影的新的內(nèi)容View 添加到 LinearLayout中
container.addView(mContentView);
// 4.2.3.指定內(nèi)容和菜單布局的寬度
// 4.2.3.1 菜單的寬度 = 屏幕的寬度 - 自定義的右邊留出的寬度
mMenuView.getLayoutParams().width = mMenuWidth;
// 4.2.3.2 內(nèi)容的寬度 = 屏幕的寬度
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 關(guān)閉菜單
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距離 在滾動的時候會不斷反復(fù)的回調(diào)這個方法
Log.e(TAG,l+"");
// 6. 實現(xiàn)菜單左邊抽屜樣式的動畫效果
mMenuView.setTranslationX(l*0.8f);
// 7.給內(nèi)容添加陰影效果 - 計算梯度值
float gradientValue = l * 1f / mMenuWidth;// 這是 1 - 0 變化的值
// 7.給內(nèi)容添加陰影效果 - 給陰影的View指定透明度 0 - 1 變化的值
float shadowAlpha = 1 - gradientValue;
mShadowIv.setAlpha(shadowAlpha);
}
/**
* 5.1.2 打開菜單
*/
private void openMenu() {
smoothScrollTo(0, 0);
mMenuIsOpen = true;
}
/**
* 5.1.1 關(guān)閉菜單
*/
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);
// 布局指定后會從新擺放子布局,當其擺放完畢后,讓菜單滾動到不可見狀態(tài)
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) {
// 當手指快速滑動時候回調(diào)的方法
Log.e(TAG,velocityX+"");
// 5.3.1 如果菜單打開 并且是向左快速滑動 切換菜單的狀態(tài)
if(mMenuIsOpen){
if(velocityX<0){
toggleMenu();
return true;
}
}else{
// 5.3.2 如果菜單關(guān)閉 并且是向右快速滑動 切換菜單的狀態(tài)
if(velocityX>0){
toggleMenu();
return true;
}
}
return false;
}
}
/**
* 切換菜單的狀態(tài)
*/
private void toggleMenu() {
if(mMenuIsOpen){
closeMenu();
}else{
openMenu();
}
}
}
我們來看一下最后的效果吧,最終代碼量不是很多啦,需要的請下載源碼,如果是實現(xiàn)QQ5.0或是酷狗的側(cè)滑效果可以自己改改。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
您可能感興趣的文章:- Android高仿QQ6.0側(cè)滑刪除實例代碼
- Android使用ViewDragHelper實現(xiàn)仿QQ6.0側(cè)滑界面(一)
- Android使用ViewDragHelper實現(xiàn)QQ6.X最新版本側(cè)滑界面效果實例代碼
- Android滑動優(yōu)化高仿QQ6.0側(cè)滑菜單(滑動優(yōu)化)
- Android使用DrawerLayout實現(xiàn)仿QQ雙向側(cè)滑菜單
- 基于Android實現(xiàn)仿QQ5.0側(cè)滑
- Android基于ViewDragHelper仿QQ5.0側(cè)滑界面效果
- Android程序開發(fā)之使用Design包實現(xiàn)QQ動畫側(cè)滑效果和滑動菜單導(dǎo)航
- Android自定義view系列之99.99%實現(xiàn)QQ側(cè)滑刪除效果實例代碼詳解
- Android自定義布局實現(xiàn)仿qq側(cè)滑部分代碼
相關(guān)文章
-
sqlite查詢結(jié)果在listview中展示的實現(xiàn)
下面小編就為大家?guī)硪黄猻qlite查詢結(jié)果在listview中展示的實現(xiàn)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧 2017-04-04
-
事件是一種有用來收集用戶與應(yīng)用程序互動數(shù)據(jù)的互動組件,如按鍵或觸摸屏等放置事件,因為每個事件從Android框架維護事件隊列先入先出(FIFO)基礎(chǔ)上的隊列??梢栽诔绦蛑胁东@這些事件,按要求并采取適當?shù)膭幼?/div> 2023-02-02
-
android 修改launcher行數(shù)和列數(shù)的方法
這篇文章主要介紹了android 修改launcher行數(shù)和列數(shù)的方法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下 2018-07-07
-
Android IPC機制利用Messenger實現(xiàn)跨進程通信
這篇文章主要介紹了Android IPC機制中 Messager 實現(xiàn)跨進程通信的知識,對Android學(xué)習(xí)通信知識非常重要,需要的同學(xué)可以參考下 2016-07-07
-
基于Android開發(fā)支持表情的實現(xiàn)詳解
本篇文章是對在Android開發(fā)中支持表情的實現(xiàn)代碼進行了介紹。需要的朋友參考下 2013-05-05
最新評論
1.概述
最近一直都在帶實習(xí)生做項目,發(fā)現(xiàn)自己好久沒有寫博客了,這幾天更新會比較頻繁,今天玩QQ的時候發(fā)現(xiàn)QQ主頁菜單滑動效果早就變了,實在忍不住晚上就來實現(xiàn)一下了!
2.實現(xiàn)
2.1. 實現(xiàn)的方式多種多樣
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的方式實現(xiàn),有人說直接去網(wǎng)上下載一個源代碼就可以了,這我就只能GG了。
2.3. 自定義SlidingMenu extends HorizontalScrollView 然后寫好布局文件這個和ScrollView的用法一樣,只不過是橫向滾動的
/** * description: * 仿QQ5.0主頁面?zhèn)然淖远╒iew * Created by 曾輝 on 2016/11/1. * QQ:240336124 * Email: 240336124@qq.com * 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. 運行起來之后發(fā)現(xiàn)布局不對,完全亂了明明都是match_parent可是就是不行那么我們就需要用代碼指定菜單和內(nèi)容的寬度:
菜單的寬度 = 屏幕的寬度 - 自定義的右邊留出的寬度
內(nèi)容的寬度 = 屏幕的寬度
/** * description: * 仿QQ5.0主頁面?zhèn)然淖远╒iew * Created by 曾輝 on 2016/11/1. * QQ:240336124 * Email: 240336124@qq.com * 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 轉(zhuǎn)成像素 */ 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(主頁內(nèi)容布局) throw new IllegalStateException("SlidingMenu 根布局LinearLayout下面只允許兩個布局,菜單布局和主頁內(nèi)容布局"); } // 2.獲取菜單和內(nèi)容布局 mMenuView = container.getChildAt(0); mContentView = container.getChildAt(1); // 3.指定內(nèi)容和菜單布局的寬度 // 3.1 菜單的寬度 = 屏幕的寬度 - 自定義的右邊留出的寬度 mMenuView.getLayoutParams().width = mMenuWidth; // 3.2 內(nèi)容的寬度 = 屏幕的寬度 mContentView.getLayoutParams().width = getScreenWidth(); } /** * 獲取屏幕的寬度 */ public int getScreenWidth() { Resources resources = this.getResources(); DisplayMetrics dm = resources.getDisplayMetrics(); return dm.widthPixels; } }
目前的效果就是可以滑動,并且菜單和主頁面內(nèi)容的布局寬度正常
2.5 接下來一開始就讓菜單滑動到關(guān)閉狀態(tài),手指滑動抬起判斷菜單打開和關(guān)閉并做相應(yīng)的處理 onLayout() onTouch() smoothScrollTo(),當手指快速的時候切換菜單的狀態(tài)利用GestureDetector 手勢處理類:
/** * description: * 仿QQ5.0主頁面?zhèn)然淖远╒iew * Created by 曾輝 on 2016/11/1. * QQ:240336124 * Email: 240336124@qq.com * 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 轉(zhuǎn)成像素 */ 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(主頁內(nèi)容布局) throw new IllegalStateException("SlidingMenu 根布局LinearLayout下面只允許兩個布局,菜單布局和主頁內(nèi)容布局"); } // 2.獲取菜單和內(nèi)容布局 mMenuView = container.getChildAt(0); mContentView = container.getChildAt(1); // 3.指定內(nèi)容和菜單布局的寬度 // 3.1 菜單的寬度 = 屏幕的寬度 - 自定義的右邊留出的寬度 mMenuView.getLayoutParams().width = mMenuWidth; // 3.2 內(nèi)容的寬度 = 屏幕的寬度 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) { // 關(guān)閉菜單 closeMenu(); } else { // 打開菜單 openMenu(); } return false; } return super.onTouchEvent(ev); } /** * 打開菜單 */ private void openMenu() { smoothScrollTo(0, 0); mMenuIsOpen = true; } /** * 關(guān)閉菜單 */ 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); // 布局指定后會從新擺放子布局,當其擺放完畢后,讓菜單滾動到不可見狀態(tài) 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) { // 當手指快速滑動時候回調(diào)的方法 Log.e("TAG",velocityX+""); // 如果菜單打開 并且是向左快速滑動 切換菜單的狀態(tài) if(mMenuIsOpen){ if(velocityX<-500){ toggleMenu(); return true; } }else{ // 如果菜單關(guān)閉 并且是向右快速滑動 切換菜單的狀態(tài) if(velocityX>500){ toggleMenu(); return true; } } return false; } } /** * 切換菜單的狀態(tài) */ private void toggleMenu() { if(mMenuIsOpen){ closeMenu(); }else{ openMenu(); } } }
到了這一步之后我們就可以切換菜單了,并且處理了手指快速滑動,迫不及待的看下效果
2.6. 實現(xiàn)菜單左邊抽屜樣式的動畫效果,監(jiān)聽滾動回調(diào)的方法onScrollChanged() 這個就非常簡單了一句話就搞定,效果就不看了一起看終極效果吧
@Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); // l 是 當前滾動的x距離 在滾動的時候會不斷反復(fù)的回調(diào)這個方法 Log.e(TAG,l+""); mMenuView.setTranslationX(l*0.8f); }
2.7. 實現(xiàn)菜單右邊菜單的陰影透明度效果,這個打算在主頁面內(nèi)容布局上面加一層陰影,用ImageView即可,那么我們的內(nèi)容View就需要換了
/** * description: * 仿QQ5.0主頁面?zhèn)然淖远╒iew * Created by 曾輝 on 2016/11/1. * QQ:240336124 * Email: 240336124@qq.com * Version:1.0 */ public class SlidingMenu extends HorizontalScrollView { private static final String TAG = "HorizontalScrollView"; private Context mContext; // 4.給菜單和內(nèi)容View指定寬高 - 左邊菜單View private View mMenuView; // 4.給菜單和內(nèi)容View指定寬高 - 菜單的寬度 private int mMenuWidth; // 5.3 手勢處理類 主要用來處理手勢快速滑動 private GestureDetector mGestureDetector; // 5.3 菜單是否打開 private boolean mMenuIsOpen = false; // 7(4). 主頁面內(nèi)容View的布局包括陰影ImageView private ViewGroup mContentView; // 7.給內(nèi)容添加陰影效果 - 陰影的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 轉(zhuǎn)成像素 */ private float dip2px(int dip) { return TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, dip, getResources().getDisplayMetrics()); } @Override protected void onFinishInflate() { super.onFinishInflate(); // 4.2 指定菜單和內(nèi)容View的寬度 // 4.2.1.獲取根View也就是外層的LinearLayout ViewGroup container = (ViewGroup) this.getChildAt(0); int containerChildCount = container.getChildCount(); if (containerChildCount > 2) { // 里面只允許放置兩個布局 一個是Menu(菜單布局) 一個是Content(主頁內(nèi)容布局) throw new IllegalStateException("SlidingMenu 根布局LinearLayout下面只允許兩個布局,菜單布局和主頁內(nèi)容布局"); } // 4.2.2.獲取菜單和內(nèi)容布局 mMenuView = container.getChildAt(0); // 7.給內(nèi)容添加陰影效果 // 7.1 先new一個主內(nèi)容布局用來放 陰影和LinearLayout原來的內(nèi)容布局 mContentView = new FrameLayout(mContext); ViewGroup.LayoutParams contentParams = new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT); // 7.2 獲取原來的內(nèi)容布局,并把原來的內(nèi)容布局從LinearLayout中異常 View oldContentView = container.getChildAt(1); container.removeView(oldContentView); // 7.3 把原來的內(nèi)容View 和 陰影加到我們新創(chuàng)建的內(nèi)容布局中 mContentView.addView(oldContentView); // 7.3.1 創(chuàng)建陰影ImageView mShadowIv = new ImageView(mContext); mShadowIv.setBackgroundColor(Color.parseColor("#99000000")); mContentView.addView(mShadowIv); // 7.4 把包含陰影的新的內(nèi)容View 添加到 LinearLayout中 container.addView(mContentView); // 4.2.3.指定內(nèi)容和菜單布局的寬度 // 4.2.3.1 菜單的寬度 = 屏幕的寬度 - 自定義的右邊留出的寬度 mMenuView.getLayoutParams().width = mMenuWidth; // 4.2.3.2 內(nèi)容的寬度 = 屏幕的寬度 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 關(guān)閉菜單 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距離 在滾動的時候會不斷反復(fù)的回調(diào)這個方法 Log.e(TAG,l+""); // 6. 實現(xiàn)菜單左邊抽屜樣式的動畫效果 mMenuView.setTranslationX(l*0.8f); // 7.給內(nèi)容添加陰影效果 - 計算梯度值 float gradientValue = l * 1f / mMenuWidth;// 這是 1 - 0 變化的值 // 7.給內(nèi)容添加陰影效果 - 給陰影的View指定透明度 0 - 1 變化的值 float shadowAlpha = 1 - gradientValue; mShadowIv.setAlpha(shadowAlpha); } /** * 5.1.2 打開菜單 */ private void openMenu() { smoothScrollTo(0, 0); mMenuIsOpen = true; } /** * 5.1.1 關(guān)閉菜單 */ 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); // 布局指定后會從新擺放子布局,當其擺放完畢后,讓菜單滾動到不可見狀態(tài) 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) { // 當手指快速滑動時候回調(diào)的方法 Log.e(TAG,velocityX+""); // 5.3.1 如果菜單打開 并且是向左快速滑動 切換菜單的狀態(tài) if(mMenuIsOpen){ if(velocityX<0){ toggleMenu(); return true; } }else{ // 5.3.2 如果菜單關(guān)閉 并且是向右快速滑動 切換菜單的狀態(tài) if(velocityX>0){ toggleMenu(); return true; } } return false; } } /** * 切換菜單的狀態(tài) */ private void toggleMenu() { if(mMenuIsOpen){ closeMenu(); }else{ openMenu(); } } }
我們來看一下最后的效果吧,最終代碼量不是很多啦,需要的請下載源碼,如果是實現(xiàn)QQ5.0或是酷狗的側(cè)滑效果可以自己改改。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android高仿QQ6.0側(cè)滑刪除實例代碼
- Android使用ViewDragHelper實現(xiàn)仿QQ6.0側(cè)滑界面(一)
- Android使用ViewDragHelper實現(xiàn)QQ6.X最新版本側(cè)滑界面效果實例代碼
- Android滑動優(yōu)化高仿QQ6.0側(cè)滑菜單(滑動優(yōu)化)
- Android使用DrawerLayout實現(xiàn)仿QQ雙向側(cè)滑菜單
- 基于Android實現(xiàn)仿QQ5.0側(cè)滑
- Android基于ViewDragHelper仿QQ5.0側(cè)滑界面效果
- Android程序開發(fā)之使用Design包實現(xiàn)QQ動畫側(cè)滑效果和滑動菜單導(dǎo)航
- Android自定義view系列之99.99%實現(xiàn)QQ側(cè)滑刪除效果實例代碼詳解
- Android自定義布局實現(xiàn)仿qq側(cè)滑部分代碼
相關(guān)文章
sqlite查詢結(jié)果在listview中展示的實現(xiàn)
下面小編就為大家?guī)硪黄猻qlite查詢結(jié)果在listview中展示的實現(xiàn)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-04-04- 事件是一種有用來收集用戶與應(yīng)用程序互動數(shù)據(jù)的互動組件,如按鍵或觸摸屏等放置事件,因為每個事件從Android框架維護事件隊列先入先出(FIFO)基礎(chǔ)上的隊列??梢栽诔绦蛑胁东@這些事件,按要求并采取適當?shù)膭幼?/div> 2023-02-02
android 修改launcher行數(shù)和列數(shù)的方法
這篇文章主要介紹了android 修改launcher行數(shù)和列數(shù)的方法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2018-07-07Android IPC機制利用Messenger實現(xiàn)跨進程通信
這篇文章主要介紹了Android IPC機制中 Messager 實現(xiàn)跨進程通信的知識,對Android學(xué)習(xí)通信知識非常重要,需要的同學(xué)可以參考下2016-07-07基于Android開發(fā)支持表情的實現(xiàn)詳解
本篇文章是對在Android開發(fā)中支持表情的實現(xiàn)代碼進行了介紹。需要的朋友參考下2013-05-05最新評論