編輯:關於Android編程
簡稱PO,這是一個設計模式,其實設計模式就是代碼的架構,一個整體的框架。例如mvc 就是模型-視圖-控制的一個代碼架構,mvp就是-模型-視圖-主持 這樣的一個架構。PageObject翻譯過來就是頁面對象的意思,就是把頁面對象和邏輯操作分開。結合封裝,更加方便使用(不明白? 下面看demo)
做UI自動化時定位特別依賴頁面,一旦頁面發生變更就不得不跟著去修改頁面定位。
,假設你想對一個元素定位操作,你可能會編寫下面的代碼:
driver.findElement(By.id("comit")).click();
於是問題就出來了,這樣代碼冗余就高了。都寫一塊了,後期難維護。你有10個地方對這個元素做了這個操作,哪天這個控件的元素變了,你就不得不去修改10個地方。
那麼po的好處就出來了,方便維護、減少代碼冗余、逼格高

每層一個父類,driver使用靜態,每個用例可以連續執行。封裝類裡面用到的Builder和Assertion在之前的文章已經貼出來了,這裡就不再次貼了。
用例基類 InitAppium.java,每個用例繼承這個類,直接加注解@Test,調用operate 層的方法即可
package com.example.base;
import org.apache.http.util.TextUtils;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.testng.annotations.AfterClass;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.Listeners;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.AndroidElement;
/**
* 測試用例的父類
* Created by LITP on 2016/9/7.
*/
@Listeners({com.example.base.AssertionListener.class})
public class InitAppium {
//調試設備名字
public static String deviceName = "minote";
//調試設備系統版本
public static String platformVersion = "4.4.2";
//app路徑
public static String appPath = System.getProperty("user.dir") + "/src/main/java/apps/shouhu2.2.3.apk";
//包名
public static String appPackage = "com.minstone.mdoctor";
//是否需要重新安裝
public static String noReset = "True";
//是否不重新簽名
public static String noSign = "True";
//是否使用unicode輸入法,真是支持中文
public static String unicodeKeyboard = "True";
//是否禍福默認呢輸入法
public static String resetKeyboard = "True";
//要啟動的Activity
//public static String appActivity = appPackage + ".activity.login.WelcomeActivity";
public static String appActivity = "";
public static AndroidDriver driver = null;
//構造方法
public InitAppium() {
this(new Builder());
}
public InitAppium(Builder builder) {
appActivity = builder.appActivity;
appPackage = builder.appPackage;
appPath = builder.appPath;
deviceName = builder.deviceName;
noReset = builder.noReset;
noSign = builder.noSign;
unicodeKeyboard = builder.unicodeKeyboard;
resetKeyboard = builder.resetKeyboard;
}
/**
* appium啟動參數
*
* @throws MalformedURLException
*/
@BeforeSuite
public void beforeSuite() throws MalformedURLException {
DesiredCapabilities capabilities = new DesiredCapabilities();
capabilities.setCapability("deviceName", deviceName);
capabilities.setCapability("platformVersion", platformVersion);
capabilities.setCapability("app", new File(appPath).getAbsolutePath());
capabilities.setCapability("appPackage", appPackage);
//支持中文
capabilities.setCapability("unicodeKeyboard", unicodeKeyboard);
//運行完畢之後,變回系統的輸入法
capabilities.setCapability("resetKeyboard", resetKeyboard);
//不重復安裝
capabilities.setCapability("noReset", noReset);
//不重新簽名
capabilities.setCapability("noSign", noSign);
//打開的activity
if(!TextUtils.isEmpty(appActivity)){
capabilities.setCapability("appActivity", appActivity);
}
//啟動Driver
driver = new AndroidDriver<>(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
}
@AfterTest
public void afterTest() {
driver.quit();
}
@AfterClass
public void afterClass(){
//每一個用例完畢結束這次測試
//driver.quit();
}
/**
* 打印字符
*
* @param str 要打印的字符
*/
public void print(T str) {
if (!TextUtils.isEmpty(String.valueOf(str))) {
System.out.println(str);
} else {
System.out.println("輸出了空字符");
}
}
}
邏輯操作基類OperateAppium.java:,邏輯功能類繼承這個類,在這裡獲取頁面控件使用page層的對象
package com.example.base;
import org.apache.http.util.TextUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.TimeoutException;
import java.util.List;
import java.util.concurrent.TimeUnit;
import io.appium.java_client.MultiTouchAction;
import io.appium.java_client.TouchAction;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.AndroidElement;
import static com.example.base.InitAppium.appPackage;
import static io.appium.java_client.android.AndroidKeyCode.BACKSPACE;
import static io.appium.java_client.android.AndroidKeyCode.KEYCODE_MOVE_END;
/**
* 邏輯處理父類
* Created by LITP on 2016/9/22.
*/
public class OperateAppium {
AndroidDriver driver;
//單個觸摸操作類
TouchAction touchAction;
//多個觸摸操作時間
MultiTouchAction multiTouchAction;
private static int WAIT_TIME = 10; //默認的等待控件時間
private final int SWIPE_DEFAULT_PERCENT = 5; //默認滑動百分比
public final String SWIP_UP = "UP",
SWIP_DOWN = "DOWN",
SWIP_LEFT = "LEFT",
SWIP_RIGHT = "RIGHT";
public OperateAppium(AndroidDriver androidDriver) {
this.driver = androidDriver;
}
/**
* 打印字符
*
* @param str 要打印的字符
*/
public void print(T str) {
if (!TextUtils.isEmpty(String.valueOf(str))) {
System.out.println(str);
} else {
System.out.println("輸出了空字符");
}
}
/**
* Click點擊空格鍵
*
* @param ae 要點擊的控件
* @return 返回是否點擊
*/
public boolean clickView(AndroidElement ae) {
return clickView(ae, "");
}
/**
* Click點擊控件
*
* @param ae 控件
* @param str 控件的文字描述,供錯誤時候輸出
* @return 返回是否存在控件
*/
public boolean clickView(AndroidElement ae, String str) {
if (ae != null) {
ae.click();
return true;
} else {
print(str + "為空,點擊錯誤");
}
return false;
}
/**
* 線程休眠秒數,單位秒
*
* @param s 要休眠的秒數
*/
public void sleep(long s) {
try {
Thread.sleep(s);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 獲取當前的activity,返回文件名
*
* @return
*/
public String getCurrActivity() {
String str = driver.currentActivity();
return str.substring(str.lastIndexOf(".") + 1);
}
/**
* 獲取觸摸實例
*
* @return
*/
public TouchAction getTouch() {
if (driver == null) {
print("單點觸摸時候driver為空");
return null;
} else {
if (touchAction == null) {
return new TouchAction(driver);
} else {
return touchAction;
}
}
}
/**
* 獲取多點觸摸實例
*
* @return
*/
public MultiTouchAction getMultiTouch() {
if (driver == null) {
print("多點觸摸時候driver為空");
return null;
} else {
if (multiTouchAction == null) {
return new MultiTouchAction(driver);
} else {
return multiTouchAction;
}
}
}
/**
* 往控件輸入字符串
*
* @param ae 要輸入的控件
* @param str 要輸入的字符串
*/
public void input(AndroidElement ae, String str) {
if (ae == null) {
print("控件為空,輸入內容失敗:" + str);
} else {
ae.sendKeys(str);
}
}
public void swipeToUp(int during) {
swipeToUp(during, SWIPE_DEFAULT_PERCENT);
}
/**
* 向上滑動,
*
* @param during
*/
public void swipeToUp(int during, int percent) {
int width = getScreenWidth();
int height = getScreenHeight();
driver.swipe(width / 2, height * (percent - 1) / percent, width / 2, height / percent, during);
}
public void swipeToDown(int during) {
swipeToDown(during, SWIPE_DEFAULT_PERCENT);
}
/**
* 向下滑動,
*
* @param during 滑動時間
*/
public void swipeToDown(int during, int percent) {
int width = getScreenWidth();
int height = getScreenHeight();
driver.swipe(width / 2, height / percent, width / 2, height * (percent - 1) / percent, during);
}
public void swipeToLeft(int during) {
swipeToLeft(during, SWIPE_DEFAULT_PERCENT);
}
/**
* 向左滑動,
*
* @param during 滑動時間
* @param percent 位置的百分比,2-10, 例如3就是 從2/3滑到1/3
*/
public void swipeToLeft(int during, int percent) {
int width = getScreenWidth();
int height = getScreenHeight();
driver.swipe(width * (percent - 1) / percent, height / 2, width / percent, height / 2, during);
}
public void swipeToRight(int during) {
swipeToRight(during, SWIPE_DEFAULT_PERCENT);
}
/**
* 向右滑動,
*
* @param during 滑動時間
* @param percent 位置的百分比,2-10, 例如3就是 從1/3滑到2/3
*/
public void swipeToRight(int during, int percent) {
int width = getScreenWidth();
int height = getScreenHeight();
driver.swipe(width / percent, height / 2, width * (percent - 1) / percent, height / 2, during);
}
/**
* 顯示等待,等待Id對應的控件出現time秒,一出現馬上返回,time秒不出現也返回
*/
public AndroidElement waitAuto(By by, int time) {
try {
return new AndroidDriverWait(driver, time)
.until(new ExpectedCondition() {
@Override
public AndroidElement apply(AndroidDriver androidDriver) {
return (AndroidElement) androidDriver.findElement(by);
}
});
} catch (TimeoutException e) {
print("查找元素超時!! " + time + " 秒之後還沒找到元素 [" + by.toString() + "]");
return null;
}
}
public AndroidElement waitAutoById(String id) {
return waitAutoById(id, WAIT_TIME);
}
public AndroidElement waitAutoById(String id, int time) {
return waitAuto(By.id(id), time);
}
public AndroidElement waitAutoByName(String name) {
return waitAutoByName(name, WAIT_TIME);
}
public AndroidElement waitAutoByName(String name, int time) {
return waitAuto(By.name(name), time);
}
public AndroidElement waitAutoByXp(String xPath) {
return waitAutoByXp(xPath, WAIT_TIME);
}
public AndroidElement waitAutoByXp(String xPath, int time) {
return waitAuto(By.xpath(xPath), time);
}
public void waitAuto() {
waitAuto(WAIT_TIME);
}
/**
* ,隱式等待,如果在指定時間內還是找不到下個元素則會報錯停止腳本
* 全局設定的,find控件找不到就會按照這個事件來等待
*
* @param time 要等待的時間
*/
public void waitAuto(int time) {
driver.manage().timeouts().implicitlyWait(time, TimeUnit.SECONDS);
}
/**
* 打開Activity
*
* @param activityName activity的名字
*/
public void startActivity(String activityName) {
driver.startActivity(appPackage, activityName);
}
/**
* 獲取當前界面的所有EditText,並依次輸入內容
*
* @param str 要輸入的數組
*/
public void inputManyText(String... str) {
List textFieldsList = driver.findElementsByClassName("android.widget.EditText");
for (int i = 0; i < str.length; i++) {
textFieldsList.get(i).click();
clearText(textFieldsList.get(i)); //清除內容
textFieldsList.get(i).sendKeys(str[i]);
}
}
/**
* 點擊屏幕中間
*/
public void press() {
press(getScreenWidth() / 2, getScreenHeight() / 2);
}
/**
* 點擊某個控件
*
* @param ae 要點擊的控件
*/
public void press(AndroidElement ae) {
try {
getTouch().tap(ae).perform();
} catch (Exception e) {
print("tab點擊元素錯誤" + e.getMessage());
e.printStackTrace();
}
}
/**
* 點擊某個坐標
*
* @param x
* @param y
*/
public void press(int x, int y) {
try {
driver.tap(1, x, y, 500);
//getTouch().tap(x, y).perform();
print("tab點擊位置(" + x + "," + y + ")");
} catch (Exception e) {
print("tab點擊元素位置異常" + e.getMessage());
e.printStackTrace();
}
}
/**
* 長按某個控件
*
* @param ae 要點擊的控件
*/
public void longPress(AndroidElement ae) {
try {
getTouch().longPress(ae).release().perform();
} catch (Exception e) {
print("長按點擊元素錯誤" + e.getMessage());
e.printStackTrace();
}
}
/**
* 長按某個坐標
*
* @param x
* @param y
*/
public void longPress(int x, int y) {
try {
getTouch().longPress(x, y).release().perform();
} catch (Exception e) {
print("長按點擊元素錯誤" + e.getMessage());
e.printStackTrace();
}
}
/**
* 在控件上滑動
*
* @param element 要滑動的控件
* @param direction 方向,事件不設置默認1秒
*/
public void swipOnElement(AndroidElement element, String direction) {
swipOnElement(element, direction, 1000); //不設置時間就為2秒
}
/**
* 在某一個控件上滑動
*
* @param element 在那個元素上滑動
* @param direction 方向,UP DOWN LEFT RIGHT
*/
public void swipOnElement(AndroidElement element, String direction, int duration) {
//獲取元素的起初xy,在左上角
int x = element.getLocation().getX();
int y = element.getLocation().getY();
//獲取元素的寬高
int width = element.getSize().getWidth();
int height = element.getSize().getHeight();
switch (direction) {
case SWIP_UP:
int startX = x + width / 2;
//在4/5的底部的中間向上滑動
driver.swipe(startX, y + height * 4 / 5, startX, y + height / 5, duration);
break;
case SWIP_DOWN:
startX = x + width / 2;
//在4/5的底部的中間向上滑動
driver.swipe(startX, y + height / 5, startX, y + height * 4 / 5, duration);
break;
case SWIP_LEFT:
int startY = y + width / 2;
driver.swipe(x + width * 4 / 5, startY, x + width / 5, startY, duration);
break;
case SWIP_RIGHT:
startY = y + width / 2;
driver.swipe(x + width / 5, startY, x + width * 4 / 5, startY, duration);
break;
}
}
/**
* 在某個方向上滑動
*
* @param direction 方向,UP DOWN LEFT RIGHT
* @param duration 持續時間
*/
public void swip(String direction, int duration) {
switch (direction) {
case "UP":
swipeToUp(duration);
break;
case "DOWN":
swipeToDown(duration);
break;
case "LEFT":
swipeToLeft(duration);
break;
case "RIGHT":
swipeToRight(duration);
break;
}
}
/**
* 在指定次數的條件下,某個方向滑動,直到這個元素出現
*
* @param by 控件
* @param direction 方向,UP DOWN LEFT RIGHT
* @param duration 滑動一次持續時間
* @param maxSwipNum 最大滑動次數
*/
public void swipUtilElementAppear(By by, String direction, int duration, int maxSwipNum) {
int i = maxSwipNum;
Boolean flag = true;
while (flag) {
try {
if (i <= 0) {
flag = false;
}
driver.findElement(by);
flag = false;
} catch (Exception e) {
i--;
swip(direction, duration);
}
}
}
/**
* 在某個方向滑動直到這個元素出現
*
* @param by 控件
* @param direction 方向,UP DOWN LEFT RIGHT
* @param duration 滑動一次持續時間
*/
public void swipUtilElementAppear(By by, String direction, int duration) {
Boolean flag = true;
while (flag) {
try {
driver.findElement(by);
flag = false;
} catch (Exception e) {
swip(direction, duration);
}
}
}
/**
* 獲取屏幕的寬高
*
* @return 返回寬高的數組
*/
public int[] getScreen() {
int width = driver.manage().window().getSize().getWidth();
int height = driver.manage().window().getSize().getHeight();
return new int[]{width, height};
}
/**
* 獲取屏幕寬度
*
* @return
*/
public int getScreenWidth() {
return driver.manage().window().getSize().getWidth();
}
/**
* 獲取屏幕高度
*
* @return
*/
public int getScreenHeight() {
return driver.manage().window().getSize().getHeight();
}
/**
* 逐字刪除編輯框中的文字
*
* @param element 文本框架控件
*/
public void clearText(AndroidElement element) {
String text = element.getText();
//跳到最後
driver.pressKeyCode(KEYCODE_MOVE_END);
for (int i = 0; i < text.length(); i++) {
//循環後退刪除
driver.pressKeyCode(BACKSPACE);
}
}
}
頁面元素基類PageAppium.java:, 界面元素的存放獲取類繼承這個類,
package com.example.base;
import org.apache.http.util.TextUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.NoSuchElementException;
import org.openqa.selenium.TimeoutException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import io.appium.java_client.android.AndroidDriver;
import io.appium.java_client.android.AndroidElement;
import static com.example.base.InitAppium.appPackage;
/**
* 頁面UI獲取定位父類,供給Page層使用
* Created by LITP on 2016/9/23.
*/
public class PageAppium {
AndroidDriver driver;
private static int WAIT_TIME = 3; //默認的等待控件時間
public PageAppium(AndroidDriver androidDriver) {
this.driver = androidDriver;
waitAuto(WAIT_TIME);
}
public boolean isIdElementExist(String id) {
return isIdElementExist(id, 0);
}
public boolean isIdElementExist(String id,int timeOut) {
return isIdElementExist(id,timeOut ,false);
}
/**
* 根據id判斷當前界面是否存在並顯示這個控件
*
* @param id 要查找的id
* @param isShow 是否判斷控件顯示
* @return 返回對應的控件
*/
public boolean isIdElementExist(String id,int timeOut, boolean isShow) {
return isElementExist(By.id(appPackage + ":id/" +id),timeOut,isShow);
}
/**
* 選擇當前界面的有這個文字的控件
*
* @param name
* @return
*/
public boolean isNameElementExist(String name) {
return isNameElementExist(name, 0);
}
public boolean isNameElementExist(String name, int timeOut) {
return isNameElementExist(name, timeOut,false);
}
public boolean isNameElementExist(String name, int timeOut, boolean isShow) {
return isElementExist(By.name(name),timeOut, isShow);
}
/**
* 判斷當前界面有沒有這個字符串存在
*
* @param text 要判斷的字符串
* @return 存在返回真
*/
public boolean isTextExist(String text) {
String str = driver.getPageSource();
print(str);
return str.contains(text);
}
/**
* 判斷當前界面有沒有這個Xpath控件存在
*
* @param text 要判斷的字符串
* @return 存在返回真
*/
public boolean isXpathExist(String text) {
return isXpathExist(text,0);
}
public boolean isXpathExist(String text,int timeOut) {
return isXpathExist(text,timeOut, false);
}
public boolean isXpathExist(String text,int timeOut,boolean isShow) {
////android.widget.TextView[@text='"+text+"']
return isElementExist(By.xpath(text), timeOut,isShow);
}
/**
* 判斷控件時候存在
*
* @param by By
* @param timeout 等待的事件
* @return
*/
public boolean isElementExist(By by, int timeout,boolean isShow) {
try {
AndroidElement element = waitAuto(by, timeout);
if(element == null){
return false;
}else{
if(isShow){
return element.isDisplayed();
}
}
return true;
} catch (Exception e) {
return false;
}
}
/**
* 獲取當前的activity,返回文件名
*
* @return
*/
public String getCurrActivity() {
String str = driver.currentActivity();
return str.substring(str.lastIndexOf(".") + 1);
}
/**
* 根據id獲取當前界面的一個控件
*
* @param id 要查找的id
* @return 返回對應的控件
*/
public AndroidElement findById(String id,String desc) {
return findElementBy(By.id(id),desc);
}
public AndroidElement findById(String id) {
return findElementBy(By.id(id),"");
}
public AndroidElement findByFullId(String id) {
try {
if (driver != null) {
return (AndroidElement) driver.findElement(By.id(id));
} else {
print("driver為空");
}
} catch (NoSuchElementException e) {
print("找不到控件:" +" 異常信息:"+ e.getMessage());
}
return null;
}
/**
* 選擇當前界面的有這個文字的控件
*
* @param name 內容
* @return 找到的控件
*/
public AndroidElement findByName(String name,String desc) {
return findElementBy(By.name(name),desc);
}
public AndroidElement findByName(String name) {
return findByName(name,"");
}
/**
* 根據id獲取當前界面的一個控件
*
* @param name 要查找的控件的類名
* @return 返回對應的控件
*/
public AndroidElement findByClassName(String name,String desc) {
return findElementBy(By.className(name),desc);
}
public AndroidElement findByClassName(String name) {
return findByClassName(name,"");
}
public AndroidElement findByXpath(String str) {
return findByXpath(str,"");
}
public AndroidElement findByXpath(String str,String desc) {
return findElementBy(By.xpath(str),desc);
}
public AndroidElement findElementBy(By by){
return findElementBy(by,"");
}
/**
* 獲取控件
* @param by by
* @param str 報錯提示信息
* @return
*/
public AndroidElement findElementBy(By by,String str){
try {
if (driver != null) {
return (AndroidElement) driver.findElement(by);
} else {
print("driver為空");
}
} catch (NoSuchElementException e) {
print("找不到控件:" +str+" 異常信息:"+ e.getMessage());
}
return null;
}
/**
* 打印字符
*
* @param str 要打印的字符
*/
public void print(T str) {
if (!TextUtils.isEmpty(String.valueOf(str))) {
System.out.println(str);
} else {
System.out.println("輸出了空字符");
}
}
/**
* 線程休眠秒數,單位秒
*
* @param s 要休眠的秒數
*/
public void sleep(long s) throws InterruptedException {
Thread.sleep(s);
}
/**
* 顯示等待,等待Id對應的控件出現time秒,一出現馬上返回,time秒不出現也返回
*/
public AndroidElement waitAuto(By by, int time) {
try {
return new AndroidDriverWait(driver, time)
.until(new ExpectedCondition() {
@Override
public AndroidElement apply(AndroidDriver androidDriver) {
return (AndroidElement) androidDriver.findElement(by);
}
});
} catch (TimeoutException e) {
return null;
}
}
public AndroidElement waitAutoById(String id) {
return waitAutoById(id, WAIT_TIME);
}
public AndroidElement waitAutoById(String id, int time) {
return waitAuto(By.id(id), time);
}
public AndroidElement waitAutoByName(String name) {
return waitAutoByName(name, WAIT_TIME);
}
public AndroidElement waitAutoByName(String name, int time) {
return waitAuto(By.name(name), time);
}
public AndroidElement waitAutoByXp(String xPath) {
return waitAutoByXp(xPath, WAIT_TIME);
}
public AndroidElement waitAutoByXp(String xPath, int time) {
return waitAuto(By.xpath(xPath), time);
}
public void waitAuto() {
waitAuto(WAIT_TIME);
}
/**
* ,隱式等待,如果在指定時間內還是找不到下個元素則會報錯停止腳本
* 全局設定的,find控件找不到就會按照這個事件來等待
*
* @param time 要等待的時間
*/
public void waitAuto(int time) {
driver.manage().timeouts().implicitlyWait(time, TimeUnit.SECONDS);
}
/**
* 獲取屏幕的寬高
*
* @return 返回寬高的數組
*/
public int[] getScreen() {
int width = driver.manage().window().getSize().getWidth();
int height = driver.manage().window().getSize().getHeight();
return new int[]{width, height};
}
/**
* 獲取屏幕寬度
*
* @return
*/
public int getScreenWidth() {
return driver.manage().window().getSize().getWidth();
}
/**
* 獲取屏幕高度
*
* @return
*/
public int getScreenHeight() {
return driver.manage().window().getSize().getHeight();
}
/**
* 根據ClassName獲取多個控件
*
* @param className 控件的類名字,例如 android.widget.EditText
* @param num 返回的數量
* @return
*/
public List getManyElementByClassName(String className, int num) {
List textFieldsList = driver.findElementsByClassName(className);
List list = new ArrayList<>();
try{
for(int i=0; i getManyElementById(String id, int num) {
if(driver != null){
List textFieldsList = driver.findElementsById(id);
List list = new ArrayList<>();
try{
for(int i=0; i下一篇講解案例
Android 實用工具之emulator介紹
在android-sdk\tools目錄下,有一個名為emulator.exe的可執行程序,望名知義,emulator即為仿真器或模擬器,但很多人可能會發現,通過AVD
Android自定義View實現閃耀字體效果
本文實例為大家分享了閃耀字體效果的具體代碼,供大家參考,具體內容如下import android.content.Context;import android.graph
AndroidStudio生成自定義的混淆jar包
今天我就給大家交給大家studio如何生成帶混淆的jar包,其實和上一篇文章差不多,只不過是多了一些混淆文件。首先我們先新建一個module(我把它新建成了一個libra
ViewPager 從入門到帶你撸個啟動頁之ViewPager基礎入門(一)
一、ViewPager的基本用法1.ViewPager概述??ViewPager是android擴展包v4包中的類,這個類可以讓我們左右切換當前的view。我們先來聊聊V