慣例,先上GIF
栗子.gif更新v1.1版本 2017-6-2 11:55:30
詳見github
一、使用姿勢
1、引入(使用Gradle或者Maven)
1)Gradleallprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
dependencies {
compile 'com.github.FJ917:FJMtSortButton:v1.1'
}
2)Maven
jitpack.io
https://jitpack.io
com.github.FJ917
FJMtSortButton
v1.1
2、使用方法
1)xml檔案
android:id="@+id/soreButton"
android:background="#ffffff"
android:layout_width="match_parent"
android:layout_height="170dp"/>
2)java檔案
1.對自定義控件做一些設定//設定界面監聽
soreButton.setViewControl(this);
//添加界面到list
list = new ArrayList<>();
list.add(R.layout.viewpager_page);
list.add(R.layout.viewpager_page);
list.add(R.layout.viewpager_page_text);
//控件相關設定
soreButton
//設定選中和未選中訓示器圖示
.setIndicator(R.drawable.radio1,R.drawable.radio2)
//設定訓示器半間距px
.setDistance(10)
//設定view組
.setView(list)
.init();
将layout的布局add進去list中,然後調用setView方法把list傳過去,
還提供了設定訓示器圖示的方法,以及訓示器間距的方法,最後必須調用初始化方法init進行初始化
這是其中的一個layout布局,其實這裡可以添加任意布局檔案進去,是不是比美團更靈活呢?
布局R.layout.viewpager_page<?xml version="1.0" encoding="utf-8"?>
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="5dp"
android:background="#ffffff" >
android:id="@+id/gridView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:horizontalSpacing="5dp"
android:numColumns="5"
android:scrollbars="none"
android:stretchMode="columnWidth"
android:verticalSpacing="10dp" />
2.設定soreButton監聽事件(具體的可以參考GIt上面的Demo,Git位址文章末尾)public class MainActivity extends AppCompatActivity implements ViewControl {
private SoreButton soreButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
soreButton = (SoreButton) findViewById(R.id.soreButton);
soreButton.setViewControl(this);
}
@Override
public void setView(View view, final int type) {
//這裡會傳回前面設定進去的View及對應的type,然後就可以進行操作了
}
}
劃重點:上面的list中可以傳入任意layout布局,然後通過接口回掉拿到View。比美團更加靈活。好了使用姿勢已經講完了,伸手可以撤退了~ 接下來開始講講實作原理
二、實作原理
1. 需求分析
需求.png
界面:分為兩部分,上面的按鈕以及下面的訓示點。上面使用ViewPager作為View的容器,下面的訓示器用LinearLayout将動态建立的ImageView添加進去。
ViewPager中的按鈕使用GridView來做,當然這一部分我們需要做的靈活些,不一定隻放按鈕,也可以方其他View,超越美團,//手動滑稽。
重點:通過自定義組合控件的方式來進行封裝,友善以後的使用。
2.下面開始封裝
1)xml<?xml version="1.0" encoding="utf-8"?>
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent">
android:id="@+id/viewPager"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="0dp" />
android:layout_below="@+id/viewPager"
android:id="@+id/llIndicator"
android:layout_width="match_parent"
android:layout_height="20dp"
android:background="#ffffff"
android:gravity="center"
android:orientation="horizontal" >
和普通的布局沒啥差別,外層LinearLayout垂直布局,其中有ViewPager作為滑動切換的容器,内部的LinearLayout作為訓示器容器。
2)自定義控件SoreButton.java
設定了預設值變量,以及控件和接口定義Context mContext;
private ViewPager viewPager;
private LinearLayout llIndicator;
//選中圖檔
private int RadioSelect = R.drawable.radio_select;
//未選中圖檔
private int RadioUnselected = R.drawable.radio_unselected;
//圓點間距
private int distance = 10;
List listSoreView = new ArrayList<>();
View soreView;
private List listView;
//接口
private ViewControl viewControl;
//設定接口
public void setViewControl(ViewControl viewControl) {
this.viewControl = viewControl;
}
拿到了自定義控件的布局中ViewPager和LinearLayout,并且設定了一個空布局。public SoreButton(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
LayoutInflater.from(context).inflate(R.layout.anfq_sore_button, this, true);
viewPager = (ViewPager) findViewById(R.id.viewPager);
llIndicator = (LinearLayout) findViewById(R.id.llIndicator);
//設定空布局
listView = new ArrayList<>();
listView.add(R.layout.viewpager_default);
}
對外提供的參數設定方法,當調用了init()方法後,會調用initViewPager方法進行ViewPager的初始化。
public SoreButton setDistance(int distance){
this.distance = distance;
return this;
}
public SoreButton setIndicator(int radioSelect,int radioUnselected){
//選中圖檔
RadioSelect = radioSelect;
//未選中圖檔
RadioUnselected = radioUnselected;
return this;
}
public SoreButton setView(List listView){
this.listView = listView;
return this;
}
public SoreButton init(){
initViewPager();
return this;
}
接下來我們看看initViewPager中都做了那些操作//初始化ViewPager
private void initViewPager(){
listSoreView = new ArrayList<>();
LayoutInflater layoutInflater = (LayoutInflater)
mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
int size = listView.size();
for (int i = 0; i
//循環拿到傳入的View
soreView = layoutInflater.inflate(listView.get(i), null);
//通過接口回掉的形式傳回目前的View,實作接口後開源拿到每個View然後進行操作
if (viewControl!=null){
viewControl.setView(soreView,i);
}
//将擷取到的View添加到List中
listSoreView.add(soreView);
}
//設定viewPager的Adapter
viewPager.setAdapter(new ViewPagerAdapter(listSoreView));
//初始化LinearLayout,加入訓示器
initLinearLayout(viewPager, size, llIndicator);
}
因為之前調用了setView方法,傳入了一組布局,我們通過循環來拿到這組View并添加到list中,然後設定到viewPager的Adapter,然後調用initLinearLayout方法初始化訓示器。
接下來我們來看initLinearLayout中又做了那些操作
private void initLinearLayout(ViewPager viewPager, int pageSize, LinearLayout linearLayout) {
//定義數組放置訓示器的點,pageSize是View個數
final ImageView[] imageViews = new ImageView[pageSize];
for (int i = 0; i
//建立ImageView
ImageView image = new ImageView(mContext);
//将ImageView放入數組
imageViews[i] = image;
//預設選中第一個
if (i == 0) {
//選中的點
image.setImageResource(RadioSelect);
} else {
//未選中的點
image.setImageResource(RadioUnselected);
}
//設定寬高
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
params.setMargins(distance, 0, distance, 0);
//将點添加到LinearLayout中
linearLayout.addView(image, params);
}
//ViewPager的滑動事件
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrollStateChanged(int arg0) {}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {}
@Override
public void onPageSelected(int arg0) {
//arg0目前ViewPager
for (int i = 0; i
//設定為選中的點
imageViews[arg0].setImageResource(RadioSelect);
//判斷目前的點i如果不等于目前頁的話就設定為未選中
if (arg0 != i) {
imageViews[i].setImageResource(RadioUnselected);
}
}
}
});
}
定義了一個數組,用來放置訓示器的點,通過循環pageSize來動态建立ImageView,然後判斷i來将第一頁的ImageView設定為選中的點,其餘設定為未選中的點。接着設定了寬高,然後添加到LinearLayout中。
當然這樣還不行,在viewPager滑動的時候我們得更新訓示器上的點
我們對ViewPager設定了監聽事件setOnPageChangeListener,在滑動的時候會調用onPageSelected,在這裡可以拿到目前頁,之後我們通過循環剛剛的數組,将目前頁對應的點設定為選中圖示,不等于目前頁的設定為未選中的點。
**然後就沒有然後了,封裝完成~
這樣就可以通過上面所說的方式,來使用這個自定義控件實作仿美團的效果,而且不止是仿美團的效果,可以傳入其他View,來實作其他效果。比如:稍加改動布局的話可以作為應用的啟動引導頁。
**總結:通過自定義組合控件,可以對一些常用的布局以及邏輯代碼進行封裝,以減少使用時代碼量,使得代碼更加簡潔。