Android 仿淘宝商品详情页

其实差很多,只是简单的模仿里面的一个效果而已。稍微做个笔记。

效果是这个样子的。

上面那几个 ITEM 可以点击,还有下面模块滑动的时候,对应的 ITEM 要变色,就俩需求。

这里我采用的都是最直接的方式,上面那个用 LinearLayout 包几个按钮,下面那个用 ScrallView,整体用 FrameLayout 包起来。(这种简单的叠加别用耗性能的 RelativeLayout)

上布局代码:

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
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.zhanglf.goodsdetail.MainActivity">

<com.zhanglf.goodsdetail.ScrollViewDIY
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/scrollView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.zhanglf.goodsdetail.MainActivity">


<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">


<View
android:id="@+id/view_one"
android:layout_width="match_parent"
android:layout_height="400dp"
android:layout_marginTop="45dp"
android:background="@android:color/holo_orange_dark"
android:orientation="vertical">

</View>

<View
android:id="@+id/view_two"
android:layout_width="match_parent"
android:layout_height="700dp"
android:background="@android:color/holo_blue_bright"
android:orientation="vertical">

</View>

<View
android:id="@+id/view_three"
android:layout_width="match_parent"
android:layout_height="600dp"
android:background="@android:color/holo_green_dark"
android:orientation="vertical">

</View>

<View
android:id="@+id/view_four"
android:layout_width="match_parent"
android:layout_height="800dp"
android:background="@android:color/holo_red_light"
android:orientation="vertical">
</View>

</LinearLayout>

</com.zhanglf.goodsdetail.ScrollViewDIY>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/holo_purple"
android:orientation="horizontal">

<Button
android:id="@+id/bt_item1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text=" Item 1 "/>

<Button
android:id="@+id/bt_item2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text=" Item 2 "/>

<Button
android:id="@+id/bt_item3"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text=" Item 3 "/>

<Button
android:id="@+id/bt_item4"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text=" Item 4 "/>
</LinearLayout>
</FrameLayout>

写 4 个 ITEM 按钮的点击事件,下面模块的跳转用 ScrollView 的 smoothScrollTo() 方法就好了。

这个方法需要传入两个参数,分别是 x 和 y 的坐标。这里 x 我们传 0 就好了。y 的话直接用 getTop(); 获取距离顶部的距离。

这里有一点要注意,Activity 生命周期中,onStart, onResume, onCreate 都不是真正 visible 的时间点,真正的visible 时间点是 onWindowFocusChanged() 函数被执行时。

所以 getTop() 要放在 onWindowFocusChanged() 里面执行,否则过早调用 getTop(),比如在 onCreate() 中调用,可能会因为这个 view 还没有被加到 rootview 中获取到的值都是 0。

第二个需求是要根据滑动距离让上面对应的 ITEM 变色。

这个时候需要实现 ScrollView 的 OnScollChangedListener 接口,但是会发现 Call requires API 23 。

所以,最好还是自己创建一个类继承系统的 ScrollView 来兼容低版本。(不是很清楚为什么 Google要将 onScrollChanged() 定义成 protected)

上代码:

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
public class ScrollViewDIY extends ScrollView {
public ScrollViewDIY(Context context) {
this(context, null);
}

public ScrollViewDIY(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public ScrollViewDIY(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);

}

@Override
protected void onScrollChanged(int x, int y, int oldx, int oldy) {
super.onScrollChanged(x, y, oldx, oldy);
if (onScollChangedListener != null) {
onScollChangedListener.onScrollChanged(this, x, y, oldx, oldy);
}
}

//接口回调

public void setOnScollChangedListener(OnScollChangedListener onScollChangedListener) {
this.onScollChangedListener = onScollChangedListener;
}


public interface OnScollChangedListener {

void onScrollChanged(ScrollViewDIY scrollView, int x, int y, int oldx, int oldy);

}

private OnScollChangedListener onScollChangedListener;
}

有个小技巧,关于自定义的 View ,每次都要写那三段构造函数是不是很烦?

其实 Google 早就想到了,直接打 ViewConstructors 就可以自动完成了。你也可以在这里修改该 Templates :

然后就没有然后了,直接判断范围了好了。

整体代码:

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
public class MainActivity extends AppCompatActivity {

private ScrollViewDIY mScroll;
private Button mBt1;
private Button mBt2;
private Button mBt3;
private Button mBt4;
private View mView1;
private View mView2;
private View mView3;
private View mView4;
private int mTop1;
private int mTop2;
private int mTop3;
private int mTop4;


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

private void intView() {
mScroll = (ScrollViewDIY) findViewById(R.id.scrollView);
mView1 = findViewById(R.id.view_one);
mView2 = findViewById(R.id.view_two);
mView3 = findViewById(R.id.view_three);
mView4 = findViewById(R.id.view_four);
mBt1 = (Button) findViewById(R.id.bt_item1);
mBt2 = (Button) findViewById(R.id.bt_item2);
mBt3 = (Button) findViewById(R.id.bt_item3);
mBt4 = (Button) findViewById(R.id.bt_item4);

mBt1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mScroll.smoothScrollTo(0,mTop1);
}
});
mBt2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mScroll.smoothScrollTo(0,mTop2);
}
});
mBt3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mScroll.smoothScrollTo(0,mTop3);
}
});
mBt4.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mScroll.smoothScrollTo(0,mTop4);
}
});
mScroll.setOnScollChangedListener(new ScrollViewDIY.OnScollChangedListener() {
@Override
public void onScrollChanged(ScrollViewDIY scrollView, int x, int y, int oldx, int oldy) {
if (y<mTop2) {
setColor(1);
} else if (y>=mTop2&&y<mTop3) {
setColor(2);
} else if (y>=mTop3&&y<mTop4) {
setColor(3);
} else if (y>=mTop4) {
setColor(4);
}
}
});
}

private void setColor(int index) {
mBt1.setTextColor(Color.BLACK);
mBt2.setTextColor(Color.BLACK);
mBt3.setTextColor(Color.BLACK);
mBt4.setTextColor(Color.BLACK);
switch (index) {
case 1:
mBt1.setTextColor(Color.RED);
break;
case 2:
mBt2.setTextColor(Color.RED);
break;
case 3:
mBt3.setTextColor(Color.RED);
break;
case 4:
mBt4.setTextColor(Color.RED);
break;
}

}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
mTop1 = mView1.getTop();
mTop2 = mView2.getTop();
mTop3 = mView3.getTop();
mTop4 = mView4.getTop();
}

}

就是这么简单。