【右滑返回】滑动冲突 Scroller DecorView
生活随笔
收集整理的這篇文章主要介紹了
【右滑返回】滑动冲突 Scroller DecorView
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
基本思想
我們的滑動(dòng)邏輯主要是利用View的scrollBy() 方法, scrollTo()方法和Scroller類來實(shí)現(xiàn)的當(dāng)手指拖動(dòng)視圖的時(shí)候,我們監(jiān)聽手指在屏幕上滑動(dòng)的距離利用View的scrollBy() 方法使得View隨著手指的滑動(dòng)而滑動(dòng)而當(dāng)手指離開屏幕,我們在根據(jù)邏輯使用Scroller類startScroll()方法設(shè)置滑動(dòng)的參數(shù),然后再根據(jù)View的scrollTo進(jìn)行滾動(dòng)。對于View的滑動(dòng),存在一些Touch事件消費(fèi)的處理等問題,最主要的就是Activity里面有一些ListView、 GridView、ScrollView等控件假如我們Activity里面存在ListView、GridView等控件的話,我們對Activity的最外層布局進(jìn)行滾動(dòng)根本就無效果,因?yàn)門ouch事件被ListView、GridView等控件消費(fèi)了,所以Activity的最外層布局根本得不到Touch事件,也就實(shí)現(xiàn)不了Touch邏輯了為了解決此Touch事件問題,我們將OnTouchListener直接設(shè)置到ListView、GridView上面,這樣子就避免了Activity的最外層接受不到Touch事件的問題了
核心:一個(gè)自定義View
public?class?SwipeBackLayout?extends?FrameLayout?{????//常量????/**手指向右滑動(dòng)時(shí)的最小【滑動(dòng)】距離(只有滑動(dòng)超過此距離才滾動(dòng)view)*/????public?static?int?X_MIN_DISTANCE_IF_MOVE?=?8;????/**手指向右滑動(dòng)時(shí)的最大【起始】距離(防止誤操作,只有從左邊緣滑動(dòng)才有效),這個(gè)值最好大于上面的值*/????public?static?int?X_MIN_START_DISTANCE?=?10;????/**手指向右滑動(dòng)時(shí)的最小【滑動(dòng)】距離(防止誤操作,只有滑動(dòng)超過一定距離才關(guān)閉)*/????public?static?int?X_MIN_DISTANCE_FROM_LEFT?=?90;????/**自動(dòng)滾動(dòng)到左側(cè)(回到初始位置)消耗的時(shí)間*/????public?static?final?int?TIME_MOVE_TO_LEFT?=?20;????/**自動(dòng)滾動(dòng)到右側(cè)(關(guān)閉應(yīng)用前)消耗的時(shí)間*/????public?static?final?int?TIME_MOVE_TO_RIGHT?=?200;????//一些可以設(shè)置的成員????/**滑動(dòng)時(shí)左邊緣是否顯示陰影*/????private?boolean?isShowShadow?=?true;????/**當(dāng)touch位置有ViewPager,但是ViewPager不是在item0時(shí),是否攔截【從屏幕邊緣down】的滑動(dòng)事件*/????private?boolean?isInterceptWhenTouchViewPagerIfNotFirst?=?false;????/**滑動(dòng)時(shí)左邊緣添加陰影*/????private?Drawable?mShadowDrawable?=?getResources().getDrawable(R.drawable.shadow_left);
????//臨時(shí)變量????/**是否要finish掉Activity*/????private?boolean?isFinish;????private?Activity?mActivity;????/**記錄按下時(shí)的觸摸點(diǎn)、移動(dòng)時(shí)的觸摸點(diǎn)在屏幕上的X坐標(biāo)*/????private?int?downX,?touchX;????private?Scroller?mScroller?=?new?Scroller(getContext());????private?List<ViewPager>?mViewPagers?=?new?LinkedList<ViewPager>();
????public?SwipeBackLayout(Context?context)?{????????this(context,?null);????}????public?SwipeBackLayout(Context?context,?AttributeSet?attrs)?{????????this(context,?attrs,?0);????}????public?SwipeBackLayout(Context?context,?AttributeSet?attrs,?int?defStyle)?{????????super(context,?attrs,?defStyle);????????DisplayMetrics?metric?=?new?DisplayMetrics();????????((WindowManager)?context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(metric);????????X_MIN_DISTANCE_FROM_LEFT?=?(int)?(metric.widthPixels?*?0.2f);//屏幕寬的1/5????????//滑動(dòng)的時(shí)候,手的移動(dòng)大于這個(gè)距離才開始移動(dòng)控件;如果小于這個(gè)距離就不觸發(fā)移動(dòng)控件。ViewPage就是用這個(gè)距離來判斷用戶是否翻頁的????????X_MIN_DISTANCE_IF_MOVE?=?ViewConfiguration.get(context).getScaledTouchSlop();????????Log.i("bqt",?X_MIN_DISTANCE_FROM_LEFT?+?"---"?+?X_MIN_DISTANCE_IF_MOVE);//144-16????????X_MIN_START_DISTANCE?=?X_MIN_DISTANCE_IF_MOVE?+?2;//這個(gè)值最好大于X_MIN_DISTANCE_IF_MOVE????}????//必須手動(dòng)調(diào)用的方法????public?void?attachToActivityAndAsRootLayout(Activity?activity)?{????????mActivity?=?activity;????????FrameLayout?decorView?=?(FrameLayout)?activity.getWindow().getDecorView();//所有窗口的根View????????ViewGroup?decorChild?=?(ViewGroup)?decorView.getChildAt(0);//封裝內(nèi)容區(qū)域和ActionBar區(qū)域的容器????????decorView.removeView(decorChild);? ? ? ??this.addView(decorChild);????????decorView.addView(this);????}????//******************************************************************************************????@Override????public?boolean?onInterceptTouchEvent(MotionEvent?event)?{????????if?(!isInterceptWhenTouchViewPagerIfNotFirst)?{????????????ViewPager?mViewPager?=?getMyTouchViewPager(mViewPagers,?event);????????????//如果存在ViewPager并且ViewPager不是處在第一個(gè)Item,我們才攔截Touch事件,否則不攔截(Touch事件由ViewPager處理)????????????if?(mViewPager?!=?null?&&?mViewPager.getCurrentItem()?!=?0)?return?super.onInterceptTouchEvent(event);????????}????????switch?(event.getActionMasked())?{????????case?MotionEvent.ACTION_DOWN:????????????downX?=?(int)?event.getRawX();//getRawX獲取的是相對父View(也即整個(gè)屏幕左上角)的位置坐標(biāo)????????????touchX?=?downX;????????????break;????????case?MotionEvent.ACTION_MOVE:????????????if?(downX?<=?X_MIN_START_DISTANCE?//不是從屏幕左邊緣開始的不攔截????????????????????&&?event.getRawX()?-?downX?>?X_MIN_DISTANCE_IF_MOVE)?return?true;//滑動(dòng)距離太小時(shí)暫不攔截????????????break;????????}????????return?super.onInterceptTouchEvent(event);????}????@Override????public?boolean?onTouchEvent(MotionEvent?event)?{????????switch?(event.getActionMasked())?{????????case?MotionEvent.ACTION_MOVE:????????????if?(event.getRawX()?-?downX?>?X_MIN_DISTANCE_IF_MOVE)?scrollBy(touchX?-?(int)?event.getRawX(),?0);//將View中的內(nèi)容滾動(dòng)指定距離????????????touchX?=?(int)?event.getRawX();????????????break;????????case?MotionEvent.ACTION_UP:????????????if?(Math.abs(getScrollX())?>=?X_MIN_DISTANCE_FROM_LEFT)?scrollRightOrLeft(true);//當(dāng)滑動(dòng)的距離大于我們設(shè)定的最小距離時(shí),滑到右側(cè)????????????else?scrollRightOrLeft(false);//當(dāng)滑動(dòng)的距離小于我們設(shè)定的最小距離時(shí),回到起始位置????????????break;????????}????????return?true;????}????@Override????protected?void?onLayout(boolean?changed,?int?l,?int?t,?int?r,?int?b)?{????????super.onLayout(changed,?l,?t,?r,?b);????????if?(changed)?getAlLViewPager(mViewPagers,?this);//【遞歸】遍歷整個(gè)View樹,獲取里面的ViewPager的集合????}????@Override????protected?void?dispatchDraw(Canvas?canvas)?{//調(diào)用View.onDraw為繪制VIew本身,調(diào)用dispatchDraw為繪制自己的孩子????????//Called?by?draw?to?draw?the?child?views.?This?may?be?overridden?by?derived?classes?to?gain?control?just?before?its?children?are?drawn?????????super.dispatchDraw(canvas);????????if?(isShowShadow?&&?mShadowDrawable?!=?null)?{????????????int?left?=?getLeft()?-?mShadowDrawable.getIntrinsicWidth();????????????int?right?=?left?+?mShadowDrawable.getIntrinsicWidth();????????????mShadowDrawable.setBounds(left,?getTop(),?right,?getBottom());????????????mShadowDrawable.draw(canvas);????????}????}????@Override????public?void?computeScroll()?{????????if?(mScroller.computeScrollOffset())?{????????????scrollTo(mScroller.getCurrX(),?mScroller.getCurrY());????????????postInvalidate();????????????if?(mScroller.isFinished()?&&?isFinish)?mActivity.finish();????????}????}????//******************************************************************************************????/**?????*?【遞歸】遍歷整個(gè)View樹,獲取里面的ViewPager的集合?????*/????private?void?getAlLViewPager(List<ViewPager>?mViewPagers,?ViewGroup?parent)?{????????int?childCount?=?parent.getChildCount();????????for?(int?i?=?0;?i?<?childCount;?i++)?{????????????View?child?=?parent.getChildAt(i);????????????if?(child?instanceof?ViewPager)?mViewPagers.add((ViewPager)?child);????????????else?if?(child?instanceof?ViewGroup)?getAlLViewPager(mViewPagers,?(ViewGroup)?child);????????}????}????/**?????*?返回我們touch范圍內(nèi)的那個(gè)ViewPager?????*/????private?ViewPager?getMyTouchViewPager(List<ViewPager>?mViewPagers,?MotionEvent?ev)?{????????if?(mViewPagers?==?null?||?mViewPagers.size()?==?0)?return?null;????????Rect?mRect?=?new?Rect();????????for?(ViewPager?viewPager?:?mViewPagers)?{????????????viewPager.getHitRect(mRect);????????????if?(mRect.contains((int)?ev.getX(),?(int)?ev.getY()))?return?viewPager;????????}????????return?null;????}????/**?????*?滾動(dòng)出界面或滾動(dòng)到起始位置?????*/????private?void?scrollRightOrLeft(boolean?toRight)?{????????isFinish?=?toRight;????????if?(toRight)?mScroller.startScroll(getScrollX(),?0,?-getWidth()?-?getScrollX(),?0,?TIME_MOVE_TO_RIGHT);????????else?mScroller.startScroll(getScrollX(),?0,?-getScrollX(),?0,?TIME_MOVE_TO_LEFT);//int?startX,?int?startY,?int?dx,?int?dy,?int?duration????????postInvalidate();//刷新界面????}????//get和set方法******************************************************************************************????public?boolean?isInterceptWhenTouchViewPagerIfNotFirst()?{????????return?isInterceptWhenTouchViewPagerIfNotFirst;????}????public?void?setInterceptWhenTouchViewPagerIfNotFirst(boolean?isInterceptWhenTouchViewPagerIfNotFirst)?{????????this.isInterceptWhenTouchViewPagerIfNotFirst?=?isInterceptWhenTouchViewPagerIfNotFirst;????}????public?Drawable?getmShadowDrawable()?{????????return?mShadowDrawable;????}????public?void?setmShadowDrawable(Drawable?mShadowDrawable)?{????????this.mShadowDrawable?=?mShadowDrawable;????}????public?boolean?isShowShadow()?{????????return?isShowShadow;????}????public?void?setShowShadow(boolean?isShowShadow)?{????????this.isShowShadow?=?isShowShadow;????}}
Activity基類
/**?*?想要實(shí)現(xiàn)向右滑動(dòng)刪除Activity效果只需要繼承SwipeBackActivity即可?*/public?class?SwipeBackActivity?extends?Activity?{????protected?SwipeBackLayout?rootLayout;????@Override????protected?void?onCreate(Bundle?savedInstanceState)?{????????requestWindowFeature(Window.FEATURE_NO_TITLE);//可以放在super.onCreate之后,但必須放在attachToActivityAndAsRootLayout之前????????super.onCreate(savedInstanceState);????????rootLayout?=?new?SwipeBackLayout(this);????????rootLayout.attachToActivityAndAsRootLayout(this);????}????@Override????public?void?startActivity(Intent?intent)?{????????super.startActivity(intent);????????overridePendingTransition(R.anim.base_slide_right_in,?R.anim.base_slide_remain);????}????@Override????public?void?onBackPressed()?{????????super.onBackPressed();????????overridePendingTransition(0,?R.anim.base_slide_right_out);????}????@Override????public?void?finish()?{????????super.finish();????????overridePendingTransition(0,?R.anim.base_slide_right_out);????}}MainActivity
public?class?MainActivity?extends?ListActivity?{????protected?void?onCreate(Bundle?savedInstanceState)?{????????requestWindowFeature(Window.FEATURE_NO_TITLE);????????super.onCreate(savedInstanceState);????????String[]?array?=?{?"普通的Activity",?//????????????????"普通的Activity:不顯示陰影",//????????????????"普通的Activity:自定義陰影",?//????????????????"普通的Activity:背景透明",//????????????????"普通的Activity:Translucent主題",//????????????????"普通的Activity:Holo_Light主題",//????????????????"有ListView的Activity",?//????????????????"當(dāng)touch位置有ViewPager,但ViewPager不是在item0時(shí),不攔截滑動(dòng)事件",//????????????????"當(dāng)touch位置有ViewPager,即使ViewPager不是在item0時(shí),也攔截【從屏幕邊緣down】的滑動(dòng)事件"?};//我感覺這種方式的用戶體驗(yàn)更好????????setListAdapter(new?ArrayAdapter<String>(this,?android.R.layout.simple_list_item_1,?new?ArrayList<String>(Arrays.asList(array))));????}????@Override????protected?void?onListItemClick(ListView?l,?View?v,?int?position,?long?id)?{????????if?(position?<=?5)?{????????????Intent?intent?=?new?Intent(this,?NormalActivity.class);????????????intent.putExtra("position",?position);????????????startActivity(intent);????????}?else?if?(position?==?6)?startActivity(new?Intent(MainActivity.this,?ListViewActivity.class));????????else?{????????????Intent?intent?=?new?Intent(this,?ViewPagerActivity.class);????????????intent.putExtra("position",?position);????????????startActivity(intent);????????}????????overridePendingTransition(R.anim.base_slide_right_in,?R.anim.base_slide_remain);????}}NormalActivity
public?class?NormalActivity?extends?SwipeBackActivity?{????@Override????protected?void?onCreate(Bundle?savedInstanceState)?{????????//如果子類要requestWindowFeature,必須放在super.onCreate之前,因?yàn)楦割怱wipeBackActivity的onCreate方法已經(jīng)獲取到了DecorView????????//也即子類在調(diào)用super.onCreate后,其窗口裝飾風(fēng)格(即相應(yīng)的根布局文件)已經(jīng)確定好了(默認(rèn)的),如:是否有標(biāo)題、是否有icon等。????????//由于要求窗口裝飾風(fēng)格一經(jīng)確定就不能再修改,否則直接拋異常!而requestWindowFeature的作用就是根據(jù)你的設(shè)置選擇匹配的窗口裝飾風(fēng)格????????//所以requestWindowFeature必須在包括setContentView以及getWindow().getDecorView()等行為之前調(diào)用!????????//注意:以上規(guī)則只適合requestWindowFeature等方法,全屏設(shè)置可以放在【任何】位置,比如在點(diǎn)擊某個(gè)View后調(diào)用也是可以的????????requestWindowFeature(Window.FEATURE_LEFT_ICON);//實(shí)際上這行代碼沒任何意義,因?yàn)闀?huì)被super.onCreate中的設(shè)置覆蓋掉????????super.onCreate(savedInstanceState);????????TextView?tv_info?=?new?TextView(this);????????tv_info.setTextColor(Color.BLACK);????????tv_info.setTextSize(TypedValue.COMPLEX_UNIT_SP,?25);????????tv_info.setBackgroundColor(Color.RED);//必須設(shè)置背景色,否則是透明的????????tv_info.setGravity(Gravity.CENTER);????????switch?(getIntent().getIntExtra("position",?0))?{????????case?0:????????????tv_info.setText("默認(rèn)顯示指定的陰影\n對于普通的Activity,不必一定要在屏幕邊緣開始滑才能退出");????????????break;????????case?1:????????????tv_info.setText("不顯示陰影");????????????rootLayout.setShowShadow(false);????????????break;????????case?2:????????????tv_info.setText("自定義陰影");????????????rootLayout.setmShadowDrawable(getResources().getDrawable(R.drawable.ic_launcher));????????????break;????????case?3:????????????tv_info.setText("背景透明");????????????tv_info.setBackgroundColor(Color.TRANSPARENT);????????????break;????????case?4:????????????tv_info.setText("Translucent主題");????????????new?AlertDialog.Builder(this).setTitle("Translucent主題").create().show();????????????break;????????case?5:????????????tv_info.setText("Holo_Light主題");????????????setTheme(android.R.style.Theme_Holo_Light);????????????new?AlertDialog.Builder(this).setTitle("Holo_Light主題").create().show();????????????break;????????}????????setContentView(tv_info);????}}ListViewActivity
public?class?ListViewActivity?extends?SwipeBackActivity?{????@Override????protected?void?onCreate(Bundle?savedInstanceState)?{????????super.onCreate(savedInstanceState);????????List<String>?list?=?new?ArrayList<String>();????????for?(int?i?=?0;?i?<=?30;?i++)?{????????????list.add("包含ListView時(shí)不會(huì)有手勢沖突");????????}????????ListView?mListView?=?new?ListView(this);????????mListView.setBackgroundColor(Color.GREEN);//設(shè)置背景色????????mListView.setAdapter(new?ArrayAdapter<String>(ListViewActivity.this,?android.R.layout.simple_list_item_1,?list));????????setContentView(mListView);????}}ViewPagerActivity
public?class?ViewPagerActivity?extends?SwipeBackActivity?{????private?List<View>?list?=?new?ArrayList<View>();????@Override????protected?void?onCreate(Bundle?savedInstanceState)?{????????super.onCreate(savedInstanceState);????????ViewPager?viewPager?=?new?ViewPager(this);????????for?(int?i?=?0;?i?<?5;?i++)?{????????????TextView?tv_info?=?new?TextView(this);????????????tv_info.setTextColor(Color.RED);????????????tv_info.setTextSize(TypedValue.COMPLEX_UNIT_SP,?300);????????????tv_info.setBackgroundColor(Color.GREEN);//必須設(shè)置背景色,否則是透明的????????????tv_info.setGravity(Gravity.CENTER);????????????tv_info.setText(""?+?i);????????????list.add(tv_info);????????}????????viewPager.setAdapter(new?Adapter(this,?list));????????setContentView(viewPager);????????if?(getIntent().getIntExtra("position",?0)?==?8)?rootLayout.setInterceptWhenTouchViewPagerIfNotFirst(true);????}????public?class?Adapter?extends?PagerAdapter?{????????private?List<View>?list;????????public?Adapter(Context?context,?List<View>?list)?{????????????this.list?=?list;????????}????????@Override????????public?int?getCount()?{????????????return?list.size();????????}????????@Override????????public?boolean?isViewFromObject(View?arg0,?Object?arg1)?{????????????return?arg0?==?arg1;????????}????????@Override????????public?void?destroyItem(ViewGroup?container,?int?position,?Object?object)?{????????????container.removeView(list.get(position));????????}????????@Override????????public?Object?instantiateItem(ViewGroup?container,?int?position)?{????????????View?v?=?list.get(position);????????????container.addView(v);????????????return?v;????????}????}}清單文件
<?xml?version="1.0"?encoding="utf-8"?><manifest?xmlns:android="http://schemas.android.com/apk/res/android"????package="com.example.slidingfinish"????android:versionCode="1"????android:versionName="1.0"?>????<uses-sdk????????android:minSdkVersion="17"????????android:targetSdkVersion="19"?/>????<application????????android:allowBackup="true"????????android:icon="@drawable/ic_launcher"????????android:label="@string/app_name"????????android:theme="@android:style/Theme.Translucent"?>????????<activity????????????android:name=".MainActivity"????????????android:label="@string/app_name"????????????android:theme="@android:style/Theme.Holo.Light"?>????????????<intent-filter>????????????????<action?android:name="android.intent.action.MAIN"?/>????????????????<category?android:name="android.intent.category.LAUNCHER"?/>????????????</intent-filter>????????</activity>????????<activity?android:name=".ListViewActivity"?/>????????<activity?android:name=".NormalActivity"?/>????????<activity?android:name=".ViewPagerActivity"?/>????</application></manifest>附件列表
?
總結(jié)
以上是生活随笔為你收集整理的【右滑返回】滑动冲突 Scroller DecorView的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Fastreport.Net用户手册:报
- 下一篇: java ftpclient API上传