移动电商APP搭建(一) 架构设计

正在学习搭建一个完整的APP,由于工作量较大,时间跨度较长,这里分为几个阶段,不定时更新

主要有五个阶段

架构设计
开发首页和会员模块
开发商品展示模块
开发购物车和移动支付模块
适配与发布

架构设计

架构设计主要是搭建框架

初始化项目

先把必要的依赖导进来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])

implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'androidx.recyclerview:recyclerview:1.2.0-alpha02'
implementation 'com.nostra13.universalimageloader:universal-image-loader:1.9.5' //URL
implementation 'org.greenrobot:greendao:3.1.1'
implementation 'org.greenrobot:greendao-generator:3.2.2'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.squareup.okhttp3:okhttp:3.14.2'
implementation 'com.squareup.okio:okio:1.17.4'
implementation 'com.squareup.okhttp3:logging-interceptor:3.2.0'
implementation 'com.squareup.retrofit2:retrofit:2.0.2'
implementation 'com.squareup.retrofit2:converter-gson:2.0.2'
implementation 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'io.reactivex:rxjava:1.1.6'
}

还有AndroidManifest.xml中的必要的一些,还有将引导页设置为开启页

架构设计
true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.huatec.edu.mobileshop">

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

<application
android:name=".common.MyApplication"
android:allowBackup="true"
android:icon="@drawable/mall"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:usesCleartextTraffic="true">
<activity android:name=".activity.AdActivity"></activity>
<activity android:name=".activity.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".activity.BaseActivity" />
<activity android:name=".activity.MainActivity"></activity>
</application>

</manifest>

合理化设计包结构,添加资源文件夹

package
explain
add
res

搭建主页框架

主页结构分析

采用Activity+Fragment相结合
layout

主界面实现

activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<FrameLayout
android:id="@+id/main_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
</FrameLayout>
</RelativeLayout>

MainActivity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
package com.huatec.edu.mobileshop.activity;

import android.content.Intent;
import android.os.Bundle;

import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;

import com.huatec.edu.mobileshop.R;
import com.huatec.edu.mobileshop.fragment.NavigationFragment;

public class MainActivity extends AppCompatActivity {
private NavigationFragment navigationFragment;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

//1.实例化自定义fragment
NavigationFragment navigationFragment = new NavigationFragment();
//2.获取FragmentManager
FragmentManager fragmentManager = getSupportFragmentManager();
//3.获取FragmentTransaction去动态加载
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.add(R.id.main_frame,navigationFragment);
transaction.commit();
}


/**
* 切换下方的tab标签
*
* @param index
*/
public void changeTab(int index) {
switch (index) {
case 1:
this.navigationFragment.setTabSelection(R.id.tab_item_home);
break;
case 2:
this.navigationFragment.setTabSelection(R.id.tab_item_category);
break;
case 3:
this.navigationFragment.setTabSelection(R.id.tab_item_cart);
break;
case 4:
this.navigationFragment.setTabSelection(R.id.tab_item_personal);
break;
}
}

@Override
protected void onNewIntent(Intent intent) {
String action = intent.getStringExtra("action");
if ("toIndex".equals(action)) {
changeTab(1);
}
}

/**
* 点击返回按键监听
*/
@Override
public void onBackPressed() {
if (navigationFragment.currentId != R.id.tab_item_home) {
changeTab(1);
return;
}
super.onBackPressed();
}

}

fragment_navigation.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<FrameLayout
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1">
</FrameLayout>

<RelativeLayout
android:id="@+id/main_tab_bottom"
android:layout_width="match_parent"
android:layout_height="48dip"
android:layout_alignParentBottom="true"
android:background="#333333">
<include layout="@layout/tab" />
</RelativeLayout>

</LinearLayout>

NavigationFragment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package com.huatec.edu.mobileshop.fragment;


import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.LinearLayout;

import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;

import com.huatec.edu.mobileshop.R;


public class NavigationFragment extends BaseFragment implements View.OnClickListener{

private LinearLayout tabItemHome;
private LinearLayout tabItemCategory;
private LinearLayout tabItemCart;
private LinearLayout tabItemPersonal;

private ImageButton tabItemHomeBtn;
private ImageButton tabItemCategoryBtn;
private ImageButton tabItemCartBtn;
private ImageButton tabItemPersonalBtn;


private HomeFragment homeFragment;
private CategoryFragment categoryFragment;
private CartFragment cartFragment;
private PersonFragment personFragment;

private FragmentManager fragmentManager;

public int currentId;

public NavigationFragment() {
}


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_navigation, container, false);
initViews(view);
setTabSelection(R.id.tab_item_home);
return view;
}

//初始化视图对象
private void initViews(View view) {
tabItemHome = (LinearLayout) view.findViewById(R.id.tab_item_home);
tabItemHome.setOnClickListener(this);
tabItemCategory = (LinearLayout) view.findViewById(R.id.tab_item_category);
tabItemCategory.setOnClickListener(this);
tabItemCart = (LinearLayout) view.findViewById(R.id.tab_item_cart);
tabItemCart.setOnClickListener(this);
tabItemPersonal = (LinearLayout) view.findViewById(R.id.tab_item_personal);
tabItemPersonal.setOnClickListener(this);

tabItemHomeBtn = (ImageButton) view.findViewById(R.id.tab_item_home_btn);
tabItemCategoryBtn = (ImageButton) view.findViewById(R.id.tab_item_category_btn);
tabItemCartBtn = (ImageButton) view.findViewById(R.id.tab_item_cart_btn);
tabItemPersonalBtn = (ImageButton) view.findViewById(R.id.tab_item_personal_btn);


fragmentManager = getFragmentManager();
}

@Override
public void onClick(View v) {
setTabSelection(v.getId());
}

public void setTabSelection(int id){
//重置所有tabItem状态
tabItemHomeBtn.setImageResource(R.drawable.tab_item_home_focus);
tabItemCategoryBtn.setImageResource(R.drawable.tab_item_category_focus);
tabItemCartBtn.setImageResource(R.drawable.tab_item_cart_focus);
tabItemPersonalBtn.setImageResource(R.drawable.tab_item_personal_focus);


FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
//隐藏所有Fragment
if(homeFragment != null) {
fragmentTransaction.hide(homeFragment);
}
if(categoryFragment != null) {
fragmentTransaction.hide(categoryFragment);
}
if(cartFragment != null) {
fragmentTransaction.hide(cartFragment);
}
if(personFragment != null) {
fragmentTransaction.hide(personFragment);
}

//根据tabItem的id来执行不同的操作
switch(id){
case R.id.tab_item_home:
tabItemHomeBtn.setImageResource(R.drawable.tab_item_home_normal);
if(homeFragment == null){
homeFragment = new HomeFragment();
fragmentTransaction.add(R.id.content, homeFragment);
}else{
fragmentTransaction.show(homeFragment);
}
break;
case R.id.tab_item_category:
tabItemCategoryBtn.setImageResource(R.drawable.tab_item_category_normal);
if(categoryFragment == null){
categoryFragment = new CategoryFragment();
fragmentTransaction.add(R.id.content, categoryFragment);
}else{
fragmentTransaction.show(categoryFragment);
}
break;
case R.id.tab_item_cart:
tabItemCartBtn.setImageResource(R.drawable.tab_item_cart_normal);
if(cartFragment == null){
cartFragment = new CartFragment();
fragmentTransaction.add(R.id.content, cartFragment);
}else{
fragmentTransaction.show(cartFragment);
}
break;
case R.id.tab_item_personal:
tabItemPersonalBtn.setImageResource(R.drawable.tab_item_personal_normal);
if(personFragment == null){
personFragment = new PersonFragment();
fragmentTransaction.add(R.id.content, personFragment);
}else{
fragmentTransaction.show(personFragment);
}
break;
}
fragmentTransaction.commit();
currentId = id;
}
}
四个页面框架

home 首页 fragment_home.xml

首页

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="首页"
android:textSize="20sp"/>

</LinearLayout>

category 分类 fragment_category.xml

分类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<TextView
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="分类"
android:textSize="20sp"/>

</LinearLayout>

cart 购物车 fragment_cart.xml

购物车

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">

<TextView
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="购物车"
android:textSize="20sp"/>

</RelativeLayout>

person 我的 fragment_person.xml

我的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">

<TextView
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="我的"
android:textSize="20sp"/>

</RelativeLayout>

设计引导页和广告页

在设计引导页和广告页之前,先构建三个通用类 Constants ImageLoaderManager MyApplication

  • Constants

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    package com.huatec.edu.mobileshop.common;

    /**
    * Created by Administrator on 2016/9/26.
    */

    public class Constants {
    /**
    * 广告显示时长 ,单位:ms
    */
    public static int AD_TIME_SECOND = 3000;
    /**
    * Base url
    */
    public static String BASE_URL = "http://192.168.31.238:8080/MobileShop/";
    /**
    * 广告url
    */
    // public static String AD_URL = BASE_URL + "";
    public static String AD_URL = "http://e.hiphotos.baidu.com/image/pic/item/a1ec08fa513d2697e542494057fbb2fb4316d81e.jpg"+"";
    public static String API_KEY_FOR_MOB_SMS = "182489edf1060";
    public static String API_SECRET_FOR_MOB_SMS = "5955939eb23eb90c2baa227f87de43a0";

    /**
    * 列表页面右侧列表的列数
    */
    public static int SPAN_COUNT = 3;
    }
  • ImageLoaderManager

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    package com.huatec.edu.mobileshop.common;

    import android.content.Context;
    import android.graphics.Bitmap;
    import android.os.Handler;

    import com.huatec.edu.mobileshop.R;
    import com.nostra13.universalimageloader.cache.disc.naming.HashCodeFileNameGenerator;
    import com.nostra13.universalimageloader.core.DisplayImageOptions;
    import com.nostra13.universalimageloader.core.ImageLoader;
    import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
    import com.nostra13.universalimageloader.core.assist.ImageScaleType;
    import com.nostra13.universalimageloader.core.display.SimpleBitmapDisplayer;
    import com.nostra13.universalimageloader.core.download.BaseImageDownloader;
    import com.nostra13.universalimageloader.utils.StorageUtils;

    import java.io.File;

    /**
    * Created by Administrator on 2016/8/31.
    */
    public class ImageLoaderManager {
    private static ImageLoaderManager mInstance;
    public static ImageLoaderManager getInstance() {
    if (mInstance == null) {
    synchronized (ImageLoaderManager.class) {
    if (mInstance == null) {
    mInstance = new ImageLoaderManager();
    }
    }
    }
    return mInstance;
    }
    public ImageLoaderManager() {
    if (mInstance == null) {
    //采用自定义配置
    ImageLoader.getInstance().init(customImageLoaderConfig(MyApplication.getContext()));

    //采用默认配置
    ImageLoader.getInstance().init(defaultImageLoaderConfig());
    }
    }
    //Image-loader框架默认配置
    private ImageLoaderConfiguration defaultImageLoaderConfig() {
    return ImageLoaderConfiguration.createDefault(MyApplication.getContext());
    }

    //Image-loader框架自定义配置
    private ImageLoaderConfiguration customImageLoaderConfig(Context context) {
    File cacheDir = StorageUtils.getCacheDirectory(context); //缓存文件夹路径
    ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
    .memoryCacheExtraOptions(480, 800) // default = device screen dimensions 内存缓存文件的最大长宽
    //.memoryCache(new LruMemoryCache(2 * 1024 * 1024)) //可以通过自己的内存缓存实现
    //.memoryCache(new WeakMemoryCache())
    .memoryCacheSize(2 * 1024 * 1024) // 内存缓存的最大值
    .memoryCacheSizePercentage(13) // default

    .diskCacheSize(50 * 1024 * 1024) // 50 Mb sd卡(本地)缓存的最大值
    .diskCacheFileCount(100) // 可以缓存的文件数量
    // default为使用HASHCODE对UIL进行加密命名, 还可以用MD5(new Md5FileNameGenerator())加密
    .diskCacheFileNameGenerator(new HashCodeFileNameGenerator())
    //.diskCacheExtraOptions(480, 800, null) // 本地缓存的详细信息(缓存的最大长宽),最好不要设置这个

    .threadPoolSize(3) // default 线程池内加载的数量
    .threadPriority(Thread.NORM_PRIORITY - 2) // default 设置当前线程的优先级
    .denyCacheImageMultipleSizesInMemory()
    .imageDownloader(new BaseImageDownloader(context)) // default
    .defaultDisplayImageOptions(DisplayImageOptions.createSimple()) // default
    .writeDebugLogs() // 打印debug log
    .build(); //开始构建
    return config;
    }

    //Image-loader框架显示图片的配置参数
    public static DisplayImageOptions product_options = new DisplayImageOptions.Builder()
    .showImageOnLoading(R.drawable.image_loading) // 设置图片下载期间显示的图片
    .showImageForEmptyUri(R.drawable.image_empty) // 设置图片Uri为空或是错误的时候显示的图片
    .showImageOnFail(R.drawable.image_error) // 设置图片加载或解码过程中发生错误显示的图片
    .resetViewBeforeLoading(false) // default 设置图片在加载前是否重置、复位
    .delayBeforeLoading(1000) // 下载前的延迟时间
    .cacheInMemory(false) // default 设置下载的图片是否缓存在内存中
    .cacheOnDisk(false) // default 设置下载的图片是否缓存在SD卡中
    .considerExifParams(false) // default
    .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default 设置图片以如何的编码方式显示
    .bitmapConfig(Bitmap.Config.ARGB_8888) // default 设置图片的解码类型
    .displayer(new SimpleBitmapDisplayer()) // default 还可以设置圆角图片new RoundedBitmapDisplayer(20)
    .handler(new Handler()) // default
    .build();
    public static DisplayImageOptions user_options = new DisplayImageOptions.Builder()
    .showImageOnLoading(R.drawable.image_loading) // 设置图片下载期间显示的图片
    .showImageForEmptyUri(R.drawable.face_default) // 设置图片Uri为空或是错误的时候显示的图片
    .showImageOnFail(R.drawable.face_default) // 设置图片加载或解码过程中发生错误显示的图片
    .resetViewBeforeLoading(false) // default 设置图片在加载前是否重置、复位
    .delayBeforeLoading(1000) // 下载前的延迟时间
    .cacheInMemory(false) // default 设置下载的图片是否缓存在内存中
    .cacheOnDisk(false) // default 设置下载的图片是否缓存在SD卡中
    .considerExifParams(false) // default
    .imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) // default 设置图片以如何的编码方式显示
    .bitmapConfig(Bitmap.Config.ARGB_8888) // default 设置图片的解码类型
    .displayer(new SimpleBitmapDisplayer()) // default 还可以设置圆角图片new RoundedBitmapDisplayer(20)
    .handler(new Handler()) // default
    .build();

    /**
    * 缩放类型mageScaleType:
    EXACTLY :图像将完全按比例缩小的目标大小
    EXACTLY_STRETCHED:图片会缩放到目标大小完全
    IN_SAMPLE_INT:图像将被二次采样的整数倍
    IN_SAMPLE_POWER_OF_2:图片将降低2倍,直到下一减少步骤,使图像更小的目标大小
    NONE:图片不会调整
    */
    /**
    * 显示方式displayer:
    RoundedBitmapDisplayer(int roundPixels)设置圆角图片
    FakeBitmapDisplayer()这个类什么都没做
    FadeInBitmapDisplayer(int durationMillis)设置图片渐显的时间
    SimpleBitmapDisplayer()正常显示一张图片
    */
    }
  • MyApplication

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    package com.huatec.edu.mobileshop.common;

    import android.app.Application;
    import android.content.Context;

    //import com.huatec.edu.mobileshop.db.GreenDaoManager;
    //import com.huatec.edu.mobileshop.http.HttpMethods;

    /**
    * Created by Administrator on 2016/8/15.
    */
    public class MyApplication extends Application {
    private static Context mContext;

    @Override
    public void onCreate() {
    super.onCreate();
    mContext = getApplicationContext();
    //greenDao全局配置
    // GreenDaoManager.getInstance();

    //全局配置image-loader
    ImageLoaderManager.getInstance();

    //全局配置Retrofit
    // HttpMethods.getInstance();
    }

    public static Context getContext() {
    return mContext;
    }
    }

引导页

引导页这里设计一个进度条动画,从左到右,动画结束跳转广告页

splash

  • 引导页布局 activity_splash.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".activity.SplashActivity"
    android:background="@drawable/splash_bg">


    <ImageView
    android:id="@+id/splash_logo"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentStart="true"
    android:layout_alignParentTop="true"
    android:layout_alignParentEnd="true"
    android:layout_marginStart="72.5dp"
    android:layout_marginTop="512dp"
    android:layout_marginEnd="72.5dp"
    app:srcCompat="@drawable/splash_logo" />

    <RelativeLayout
    android:id="@+id/relativeLayout1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@id/splash_logo"
    android:layout_centerHorizontal="true"
    android:layout_marginTop="50dp" >

    <ImageView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:src="@drawable/splash_loading_bg" />

    <ImageView
    android:id="@+id/splash_loading_item"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentLeft="true"
    android:src="@drawable/splash_loading_item" />
    </RelativeLayout>

    </RelativeLayout>
  • 进度条动画 splash_loading.xml

    1
    2
    3
    4
    5
    6
    7
    <?xml version="1.0" encoding="utf-8"?>
    <translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromXDelta="0.0"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:toXDelta="60%p"
    android:fillAfter="true" />
  • 进度条从左到右动画 push_left_in.xml、push_left_out.xml

    1
    2
    3
    4
    5
    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate android:fromXDelta="100%" android:toXDelta="0"
    android:duration="600" />
    </set>
1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromXDelta="0" android:toXDelta="-100%"
android:duration="600" />
</set>
  • SplashActivity
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    package com.huatec.edu.mobileshop.activity;

    import androidx.appcompat.app.AppCompatActivity;

    import android.content.Intent;
    import android.os.Bundle;
    import android.os.Handler;
    import android.view.animation.Animation;
    import android.view.animation.AnimationUtils;
    import android.widget.ImageView;

    import com.huatec.edu.mobileshop.R;

    public class SplashActivity extends AppCompatActivity {
    private ImageView mSplashItem_iv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_splash);
    //去掉顶部标题
    getSupportActionBar().hide();
    initView();
    }
    private void initView() {
    mSplashItem_iv = findViewById(R.id.splash_loading_item);
    Animation translate = AnimationUtils.loadAnimation(this, R.anim.splash_loading);

    translate.setAnimationListener(new Animation.AnimationListener() {
    @Override
    public void onAnimationStart(Animation animation) {
    }

    @Override
    public void onAnimationEnd(Animation animation) {
    startActivity(new Intent(SplashActivity.this, AdActivity.class));
    overridePendingTransition(R.anim.push_left_in, R.anim.push_left_out);
    finish();
    }

    @Override
    public void onAnimationRepeat(Animation animation) {
    }
    });
    mSplashItem_iv.setAnimation(translate);
    }
    }

广告页

广告页这里设计从网络加载图片,三秒跳转主页,点击跳过直接跳转主页

广告页

  • activity_ad.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".activity.AdActivity"
    android:orientation="vertical">

    <ImageView
    android:id="@+id/ad_image"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:src="@drawable/ad"
    android:layout_gravity="center" />

    <Button
    android:id="@+id/skip_button"
    android:layout_width="50dip"
    android:layout_height="30dp"
    android:layout_gravity="right"
    android:layout_marginBottom="5dip"
    android:layout_marginRight="5dip"
    android:layout_marginTop="5dip"
    android:background="#FFFFFF"
    android:gravity="center"
    android:paddingLeft="5dip"
    android:paddingRight="5dip"
    android:text="跳过"
    android:textSize="12.0sp"/>

    </FrameLayout>
  • AdActivity

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    package com.huatec.edu.mobileshop.activity;

    import androidx.appcompat.app.AppCompatActivity;

    import android.content.Intent;
    import android.graphics.Bitmap;
    import android.os.Bundle;
    import android.os.Handler;
    import android.view.View;
    import android.widget.Button;
    import android.widget.ImageView;

    import com.huatec.edu.mobileshop.R;
    import com.huatec.edu.mobileshop.common.Constants;
    import com.huatec.edu.mobileshop.common.ImageLoaderManager;
    import com.nostra13.universalimageloader.core.ImageLoader;
    import com.nostra13.universalimageloader.core.assist.FailReason;
    import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;

    public class AdActivity extends AppCompatActivity {
    private ImageView adImage;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_ad);
    //去掉顶部标题
    getSupportActionBar().hide();

    adImage = findViewById(R.id.ad_image);
    //加载广告图
    loadAd(Constants.AD_URL);

    }

    private void loadAd(String url) {
    ImageLoader.getInstance().displayImage(url, adImage,
    ImageLoaderManager.product_options, new ImageLoadingListener() {
    @Override
    public void onLoadingStarted(String imageUri, View view) {

    }

    @Override
    public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
    //直接跳转
    skip();
    }

    @Override
    public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
    adImage.setImageBitmap(loadedImage);
    //倒数3秒跳转
    timer();
    }

    @Override
    public void onLoadingCancelled(String imageUri, View view) {

    }
    });
    }

    //过3秒后跳转
    private void timer() {
    final Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
    super.handleMessage(msg);
    if (msg.what == -1)
    skip();
    }
    };

    new Thread() {
    @Override
    public void run() {
    try {
    Thread.sleep(Constants.AD_TIME_SECOND);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    handler.sendEmptyMessage(-1);
    }
    }.start();
    }

    /**
    * 跳过
    */
    private void skip() {
    startActivity(new Intent(AdActivity.this, MainActivity.class));
    }
    }