為了實現廣告輪播功能,在網上找了很多方法,有的效果很好,但是代碼太麻煩,並且大多是用的viewpager,總之不是很滿意。
於是看了一下sdk有個控件是ViewFlipper,使用比較方便,於是嘗試了一下,最終實現了所需效果。在這里與大家分享。
首先看一下效果(主要是布局方面的效果,畢竟手勢識別和滑動不太好顯示,懶得弄成gif了):

1、布局文件.xml
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<ViewFlipper
android:layout_width="fill_parent"
android:layout_height="120dp"
android:id="@+id/details"
>
</ViewFlipper>
<RelativeLayout
android:layout_width="fill_parent"
android:layout_height="16dp"
>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="16dp"
android:orientation="horizontal"
android:gravity="right"
>
<View
android:id="@+id/v_dot0"
style="@style/dot_style"
android:background="@drawable/dot_focused"
/>
<View
android:id="@+id/v_dot1"
style="@style/dot_style"
/>
<View
android:id="@+id/v_dot2"
style="@style/dot_style"
/>
</LinearLayout>
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="left"
android:text="hello"
/>
</RelativeLayout>
</LinearLayout>
我來解釋一下這個布局
首先,最外層是一個LinearLayout布局來填充整個屏幕。
第二層就是控件ViewFlipper與RelativeLayout並列。其中ViewFlipper是實現圖片輪播的,RelationLayout是圖片下面的信息,比如圖片的標題(如圖中的&&)和圖片在所有圖片中的位置(表現形式為最右邊的白色小點)
第三層其實就是把第二層的RelativeLayout展開,里面有一個TextView控件來顯示標題,和三個View控件來顯示小點。
下面是要用到的一些style和drawable代碼(該部分代碼來自網絡):
前5個放在res/drawable文件夾下
1、btn_back_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/btn_top_pressed" android:state_focused="true"></item>
<item android:drawable="@drawable/btn_top_pressed" android:state_pressed="true"></item>
<item android:drawable="@drawable/btn_top_pressed" android:state_selected="true"></item>
<item android:drawable="@drawable/title_bk"></item>
</selector>
2、btn_top_pressed.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<gradient
android:angle="270"
android:endColor="#009ad6"
android:startColor="#11264f" />
</shape>
3、dot_focused.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval" >
<solid android:color="#aaFFFFFF" />
<corners android:radius="5dip" />
</shape>
4、dot_normal.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval" >
<solid android:color="#33000000" />
<corners android:radius="5dip" />
</shape>
5、title_bk.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle" >
<gradient
android:angle="270"
android:endColor="#11264f"
android:startColor="#009ad6" />
</shape>
6、styles.xml(放在values文件夾之下)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="dot_style">
<item name="android:layout_width">5dip</item>
<item name="android:layout_height">5dip</item>
<item name="android:background">@drawable/dot_normal</item>
<item name="android:layout_marginLeft">1.5dip</item>
<item name="android:layout_marginRight">1.5dip</item>
</style>
</resources>
這上面的代碼我也不怎么懂,但是目的就是為了操作那些小點點。
下面問題來了,java代碼呢。不要急,這就上來。
下面高能,膽小誤入。
java代碼(先全都發上來,容我慢慢解釋)
package com.example.mynews;
import java.util.ArrayList;
import java.util.List;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ViewFlipper;
public class MainActivity extends Activity{
private ViewFlipper viewFlipper;
private String[] titles;
private TextView tv_title;
private List<View> dots;
float startx;
float x = 0;
float y = 0;
@Override
@SuppressWarnings("deprecation")
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewFlipper = (ViewFlipper)findViewById(R.id.details);
tv_title = (TextView)findViewById(R.id.title);
int image[] = new int[]
{
R.drawable.a,R.drawable.b,R.drawable.c
};
for(int i=0;i<image.length;i++)
{
ImageView iv = new ImageView(getApplicationContext());
iv.setBackgroundResource(image[i]);
iv.setScaleType(ScaleType.CENTER_INSIDE);
iv.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT));
viewFlipper.addView(iv);
}
titles = new String[image.length];
titles[0] = "hello";
titles[1] = "&&";
titles[2] = "world";
dots = new ArrayList<View>();
dots.add(findViewById(R.id.v_dot0));
dots.add(findViewById(R.id.v_dot1));
dots.add(findViewById(R.id.v_dot2));
handler.sendMessageDelayed(new Message(), 5000);
viewFlipper.setOnTouchListener(new OnTouchListener() {
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
switch(event.getAction())
{
case MotionEvent.ACTION_DOWN:
{ x = event.getX();
Toast.makeText(getApplicationContext(), "down"+event.getX(), 1).show();
}break;
case MotionEvent.ACTION_UP:
{
y = event.getX();
if(y>x)
{
Log.v(null, "result:y>x");
showPre();
}
else if(x==y)
{
Log.v(null, "result:y=x");
showDetail();
}
else
{
Log.v(null, "result:x>y");
showNext();
}
}break;
}
return true;
}
});
}
private Handler handler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
super.handleMessage(msg);
showNext();
handler.sendMessageDelayed(new Message(), 5000);
}
};
private void showNext()
{
viewFlipper.showNext();
int cur = viewFlipper.getDisplayedChild();
if(cur == 0)
{
dots.get(2).setBackgroundResource(R.drawable.dot_normal);
}
else
{
dots.get(cur-1).setBackgroundResource(R.drawable.dot_normal);
}
dots.get(cur).setBackgroundResource(R.drawable.dot_focused);
tv_title.setText(titles[cur]);
}
private void showPre()
{
viewFlipper.showPrevious();
int cur = viewFlipper.getDisplayedChild();
if(cur == 2)
{
dots.get(0).setBackgroundResource(R.drawable.dot_normal);
}
else
{
dots.get(cur+1).setBackgroundResource(R.drawable.dot_normal);
}
dots.get(cur).setBackgroundResource(R.drawable.dot_focused);
tv_title.setText(titles[cur]);
}
private void showDetail()
{
Toast.makeText(getApplicationContext(),"x=y", 1).show();
}
}
1、先准備圖片,這里我准備了三張,初始化代碼如下:
int image[] = new int[]//用int型數組來儲存三張照片的編號
{
R.drawable.a,R.drawable.b,R.drawable.c
};
for(int i=0;i<image.length;i++)//將三張照片加入viewflipper里
{
ImageView iv = new ImageView(getApplicationContext());
iv.setBackgroundResource(image[i]);
iv.setScaleType(ScaleType.CENTER_INSIDE);//這里設置圖片變換格式
iv.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT));
viewFlipper.addView(iv);
}
2、對ViewFlipper設置監聽事件(進行手勢操作的核心),注意,這里的監聽不是onclicklistener,而是ontouchlistener
viewFlipper.setOnTouchListener(new OnTouchListener() {
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub
switch(event.getAction())
{
case MotionEvent.ACTION_DOWN://手指按下
{ x = event.getX();//全局變量,接收按下是的手指坐標
Toast.makeText(getApplicationContext(), "down"+event.getX(), 1).show();
}break;
case MotionEvent.ACTION_UP://手指松開
{
y = event.getX();//全局變量,接收松開是的手指坐標
//下面就是簡單的邏輯判斷,從而區分向左滑、向右滑以及不滑(也就是點擊事件)
if(y>x)
{
Log.v(null, "result:y>x");
showPre();
}
else if(x==y)
{
Log.v(null, "result:y=x");
showDetail();
}
else
{
Log.v(null, "result:x>y");
showNext();
}
}break;
}
return true;
}
});
這里要重點說下,本來我采用的不是這種方法,而是將activity使用ontouch接口、ViewFlipper使用onclicklistener,而且還要聲明一個gesturedetector變量,這樣會出現一個問題,就是ontouch與onclick的事件會相互影響,具體怎么回事,我也沒搞明白。有事件會仔細研究研究。此外,如果使用gesturedetector又會增加復雜度。
然后是圖片切換動作,也就是上段代碼中的showPre()、showNext()、showDetail()方法。作用分別是向左滑、向右滑、不滑(這里可以用來實現點擊事件)代碼如下:
private void showNext()
{
viewFlipper.showNext();//sdk封裝好的,使用非常方便
int cur = viewFlipper.getDisplayedChild();
if(cur == 0)
{
dots.get(2).setBackgroundResource(R.drawable.dot_normal);//這是控制那些小點點的,邏輯應該能看懂,就不解釋了
}
else
{
dots.get(cur-1).setBackgroundResource(R.drawable.dot_normal);
}
dots.get(cur).setBackgroundResource(R.drawable.dot_focused);
tv_title.setText(titles[cur]);
}
private void showPre()
{
viewFlipper.showPrevious();//sdk封裝好的,使用非常方便
int cur = viewFlipper.getDisplayedChild();
if(cur == 2)
{
dots.get(0).setBackgroundResource(R.drawable.dot_normal);
}
else
{
dots.get(cur+1).setBackgroundResource(R.drawable.dot_normal);
}
dots.get(cur).setBackgroundResource(R.drawable.dot_focused);
tv_title.setText(titles[cur]);
}
private void showDetail()
{
Toast.makeText(getApplicationContext(),"x=y", 1).show();
}
下面又到了另外一個重點,handler機制,其實和定時器差不多(至少在這里是)
handler.sendMessageDelayed(new Message(), 5000);
沒5000ms也就是5s發送一次消息,這個消息是干嘛的?請看下端代碼
private Handler handler = new Handler()
{
@Override
public void handleMessage(Message msg)
{
super.handleMessage(msg);
showNext();
handler.sendMessageDelayed(new Message(), 5000);
}
};
簡單的講,它是給他自己發消息,提醒自己時間到了,該吃葯了(該做某件事了)。然后做完之后還要告訴自己,過5s還要吃葯,就這樣一直吃葯,不放棄治療。
我想,說到這里,應該明白,這段代碼的功能就是實現圖片的自動切換。
至此,代碼的重點部分解釋完了。至於標題和那些小點點怎么處理,都在那三個方法里寫好了,肯定可以看明白,就不多贅述了。
附:
1、代碼出問題盡量不要找我,雖然是我寫的,但是它自己長歪了。
2、轉載請注明出處。
謝謝閱讀,歡迎批評指正。
