Android應用開發-------------仿蘋果右滑退出頁面效果

博客爲 有時個哥 原創,如需轉載請標明出處:http://blog.csdn.net/ls703/article/details/41312921

前一段時間一個朋友說他們做應用,跟着蘋果的效果做,蘋果上有一個右滑退出頁面的效果,滑到一般不想退出可以滑回來的那種。他說他和自己的項目經理寫了一個,效果都不理想,我忙完自己的工作,有時間自己寫了寫,效果還算可以。一般這種頁面是需要自定義的。如果在一個activity裏面實現這種效果,是不算難的。但是我們不可能把所有的頁面都放在一個activity裏面,所以我就單獨寫了一個有這個效果的activity,假如我們想要用這種效果的,我們只要繼承這個activity即可,這個activity除了有右滑功能,其他的和正常的activity使用一樣。所以不會影響正常開發。下面就開始說一下具體思路。由於自己按自己的想法寫的,所以有不足之處還請大家指教。

首先,要實現這個效果需要自定義頁面,所以,我們首先先自定義一個佈局頁面,先曬代碼:

package com.example.slidingactivity.ui.weiget;

import com.example.slidingactivity.R;

import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.widget.RelativeLayout;
import android.widget.Scroller;


public class BaseRelativeLayout extends RelativeLayout {
	private Activity activity;
	int currentScreen  = LEFT_SCREEN;
	private static final int LEFT_SCREEN = 0;
	private static final int RIGHT_SCREEN = 1;
	private Scroller mScroller;		// 專門用模擬數據.
	
	public BaseRelativeLayout(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, R.style.Transparent);
	}

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

	public BaseRelativeLayout(Context context) {
		super(context);
		this.activity = (Activity)context;
		mScroller = new Scroller(context);
		//獲得觸發滑動事件的最短距離
		scaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
	}
	
	int oldX;
	@Override
	public boolean onTouchEvent(MotionEvent event) {
//		System.out.println("width:"+	getWidth()+"height:"+getHeight());
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			oldX = (int)event.getX();
			break;
		case MotionEvent.ACTION_UP:
			if(getScrollX()<0&&getScrollX()>-getMeasuredWidth()/2){
				currentScreen = LEFT_SCREEN;
			}
			if(getScrollX()<=-getMeasuredWidth()/2&&getScrollX()>=-getMeasuredWidth()){
				currentScreen = RIGHT_SCREEN;
			}
			scrollScreen();
			break;
		case MotionEvent.ACTION_MOVE:
			//移動後的座標
			int moveX = (int)event.getX();
			//偏移量
			int deltaX  = (oldX-moveX);
			//滑動距離加上偏移量
			int newScrollX = getScrollX() + deltaX;// 獲得當前屏幕x軸的偏移量
			if(newScrollX>0){
				scrollTo(0, 0);
			}else if(newScrollX<=-getMeasuredWidth()){
				scrollTo(-getMeasuredWidth(), 0);
				activity.finish();
			}else{
				scrollBy(deltaX, 0);
			}
			oldX = moveX;
			break;
		default:
			break;
		}
		return true;
	}

	/**
	 * 根據currentScreen變量來切換屏幕的顯示
	 */
	private void scrollScreen() {
		int scrollX = getScrollX();
		int dx = 0;
		if(currentScreen == LEFT_SCREEN) {
			// 向左滑動
			dx = 0 - scrollX;
		} else if(currentScreen == RIGHT_SCREEN) {
			// 向右滑動
			dx = -getChildAt(0).getMeasuredWidth() - scrollX;
		}
		// 開始模擬數據了.
		mScroller.startScroll(scrollX, 0, dx, 0, Math.abs(dx) * 2);
		// 刷新當前控件, 會引起當前控件的重繪.
		invalidate(); // -> drawChild -> child.draw -> computeScroll()
	}

	/**
	 * 更新當前屏幕的x軸的值
	 * 如果mScroller類一直正在模擬數據. 想讓computeScroll方法一直被調用, mScroller停止模擬時停止調用此方法
	 */
	@Override
	public void computeScroll() {
		if(mScroller.computeScrollOffset()) { // true 代表當前正在模擬數據. false 已經停止模擬數據了
			scrollTo(mScroller.getCurrX(), 0);
			invalidate();	// 遞歸, 自己掉自己.
			if(getScrollX()<=-getMeasuredWidth()){
				activity.finish();
			}
		}
	}
	
	/**
	 * 在此攔截事件,左右滑動自身消費點事件
	 */
	
	private int scaledTouchSlop;
	@Override
	public boolean onInterceptTouchEvent(MotionEvent ev) {
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			oldX =  (int)ev.getX();
			break;
		case MotionEvent.ACTION_MOVE:
			int moveX = (int) ev.getX();
			int diff = Math.abs(moveX - oldX);
			if(diff > scaledTouchSlop) {
				return true;
			}
			break;
		default:
			break;
		}
		return super.onInterceptTouchEvent(ev);
	}
}

既然要實現滑動,那麼就需要重新寫ontouch方法,利用觸屏監聽的不同效果,先實現頁面能移動。然後根據位移量來實現移動佈局。上面代碼光劍地方也已做了註釋,上面就是自定義的一個可滑動的自定義佈局。實現自定義佈局後,那然後我們就開始想怎樣讓他添加在一個activity鍾,而不影響activity的正常使用。我們要的效果就是讓他和平常的activity用法一樣。直接繼承使用即可。所以我寫了一個基類BaseActivity一下是他的代碼。

package com.example.slidingactivity.base;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.View;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.TextView;

import com.example.slidingactivity.R;
import com.example.slidingactivity.ui.weiget.BaseRelativeLayout;

public class BaseActivity extends Activity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  // setTheme(R.style.Transparent);
 }

 public void setContentView(View view) {
  super.setContentView(getBaseView(view));
  // setTheme(R.style.Transparent);
 }

 public void setContentView(int layoutResId) {
 // setTheme(R.style.Transparent);
  View view = View.inflate(this, layoutResId, null);
  TextView tv = new TextView(this);
  tv.setText("nihao");
  super.setContentView(getBaseView(view));
 }

 private RelativeLayout getBaseView(View view) {
  BaseRelativeLayout baseView = new BaseRelativeLayout(this);
  view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
    LayoutParams.MATCH_PARENT));
  baseView.addView(view);
  return baseView;
 }
}


這就是整個類的代碼,看着代碼不多。既然要做到和普通的activity一樣,那麼佈局就是使用這給的,所以我這裏選擇,BaseActivity沒有自己靜態佈局的佈局,使用代碼動態添加使用繼承者提供的佈局。

爲了和普通的activity一樣,所以這裏我重寫了setContentView方法,這樣方法是我們熟悉的名字,就直接使用即可,通過重寫這個方法,來得到子類傳入的佈局,得到子類傳入的佈局,我們下一步就是讓子類的佈局和我們自定義的滑動佈局結合。其實思路是這樣的,把子類佈局嵌入自定義的華東佈局中。而滑動佈局就是BaseActivity的佈局。

這樣大體的完成了一大半了。沒錯就是這麼簡單。還有一個比較重要的一步。那就是給Activity設置透明風格。因爲是不同的Activity,在滑動的頁面的時候我們需要看到下面的Activity,所以要把Activity設置成透明的。這裏我也遇到一個問題。我沒有找到在代碼裏把整個Activity設置成透明的辦法。網上一些資料總是在工程裏實現不了那種效果。所以我是在xml設置style,在清單文件裏給Activity設置成透明的風格。

    <style name="Transparent"  parent="AppTheme">
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:windowBackground">@color/transparent</item>
        <item name="android:windowIsTranslucent">true</item>
        <item name="android:windowAnimationStyle">@+android:style/Animation.Translucent</item>
    </style>


在清單文件裏,  

 <activity android:name="com.example.slidingactivity.ContentActivity"
           android:theme="@style/Transparent"
           ></activity>

如果想整個應用使用這種效果,那可以吧整個應用設置成透明的風格。

這樣就萬事大吉了。讓後我們寫幾個子類,繼承BaseActivity,

package com.example.slidingactivity;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

import com.example.slidingactivity.base.BaseActivity;

public class ContentActivity extends BaseActivity {
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_content);
  Button content = (Button)findViewById(R.id.content);
  content.setOnClickListener(new OnClickListener() {
   
   @Override
   public void onClick(View v) {
//    Toast.makeText(ContentActivity.this, "點擊了", 0).show();
    Intent intent = new Intent(ContentActivity.this,ContentActivity1.class);
    startActivity(intent);
   }
  });
 }
  }
}


MainActivity的代碼

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button tvClick = (Button) findViewById(R.id.tvClick);
        tvClick.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				Intent intent = new Intent(MainActivity.this,ContentActivity.class);
				startActivity(intent);
			}
		});
    }

    
}


下面是源碼:

http://download.csdn.net/detail/ls703/8179981

大家有什麼好的方法,或實現效果,可以一塊交流。

在最後,我也在這裏求大家指教,BaseActivity中把Activity變成透明的方法,也就是滑動的時候能看見下面的Activity。是求在代碼中實現。如果在代碼中能實現那種效果,那樣就不用麻煩在清單文件裏配置了。使用起來就會更加方便。

 

題外話:寫完之後聽朋友說,有這方面的架包,大家也可以去下載,在githup上面。具體地址我忘了,嘿嘿,大家可以自己找找。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章