如何创建一个带点指示器的 Android 视图寻呼机?

也许你们中的很多人(像我一样)在创建带有底部点的 ViewPager时遇到了问题,比如: enter image description here

如何创建这样一个 Android ViewPager?

131658 次浏览

所有我们需要的是: 浏览器TabLayout和2选择和默认点绘制。

首先,我们必须添加 TabLayout到我们的屏幕布局,并连接它与 ViewPager。我们可以通过两种方式做到这一点:


ViewPager中嵌套 TabLayout

<androidx.viewpager.widget.ViewPager
android:id="@+id/photos_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent">


<com.google.android.material.tabs.TabLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</androidx.viewpager.widget.ViewPager>

在这种情况下,TabLayout将自动连接到 ViewPager,但 TabLayout将旁边的 ViewPager,而不是在它。


分离 TabLayout

<androidx.viewpager.widget.ViewPager
android:id="@+id/photos_viewpager"
android:layout_width="match_parent"
android:layout_height="match_parent"/>


<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>

在这种情况下,我们可以将 TabLayout放在任何地方,但是我们必须以编程方式将 TabLayoutViewPager连接起来

ViewPager pager = (ViewPager) view.findViewById(R.id.photos_viewpager);
PagerAdapter adapter = new PhotosAdapter(getChildFragmentManager(), photosUrl);
pager.setAdapter(adapter);


TabLayout tabLayout = (TabLayout) view.findViewById(R.id.tab_layout);
tabLayout.setupWithViewPager(pager, true);

一旦我们创建了我们的布局,我们必须准备我们的点。所以我们创建三个文件: selected_dot.xmldefault_dot.xmltab_selector.xml


Select _ dot. xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
android:innerRadius="0dp"
android:shape="ring"
android:thickness="8dp"
android:useLevel="false">
<solid android:color="@color/colorAccent"/>
</shape>
</item>
</layer-list>

Default _ dot. xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
android:innerRadius="0dp"
android:shape="ring"
android:thickness="8dp"
android:useLevel="false">
<solid android:color="@android:color/darker_gray"/>
</shape>
</item>
</layer-list>

Tab _ selector. xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">


<item android:drawable="@drawable/selected_dot"
android:state_selected="true"/>


<item android:drawable="@drawable/default_dot"/>
</selector>

现在我们只需要在 XML 布局中向 TabLayout添加3行代码。

app:tabBackground="@drawable/tab_selector"
app:tabGravity="center"
app:tabIndicatorHeight="0dp"

首先创建一个布局,在这给一个线性布局的点,显示在您的查看页面

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">


<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>




<LinearLayout
android:id="@+id/pager_dots"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="10dp"
android:background="@android:color/transparent"
android:gravity="center_horizontal"
android:orientation="horizontal">
</LinearLayout>


</RelativeLayout>

然后创建2个可绘制的内容

1. 未选择的可绘制

<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="oval" xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/transparent"/>
<size android:width="12dp" android:height="12dp"/>


<stroke android:width="1dp" android:color="#ffffff"/>
</shape>

2. 选择可绘制

<?xml version="1.0" encoding="utf-8"?>
<shape android:shape="oval" xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/transparent"/>
<size android:width="12dp" android:height="12dp"/>


<stroke android:width="1dp" android:color="#000000"/>
</shape>

在设置适配器之后

private LinearLayout llPagerDots;
private ViewPager viewPager;
private ArrayList<String> eventImagesUrl;
private HomeViewPagerAdapter homeViewPagerAdapter;
private ImageView[] ivArrayDotsPager;


public void setUpViewPager() {
viewPager = (ViewPager) findViewById(R.id.view_pager);
llPagerDots = (LinearLayout) findViewById(R.id.pager_dots);


homeViewPagerAdapter = new HomeViewPagerAdapter(mContext, eventImagesUrl);


viewPager.setAdapter(homeViewPagerAdapter);


setupPagerIndidcatorDots();


ivArrayDotsPager[0].setImageResource(R.drawable.page_indicator_selected);


viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {


}


@Override
public void onPageSelected(int position) {
for (int i = 0; i < ivArrayDotsPager.length; i++) {
ivArrayDotsPager[i].setImageResource(R.drawable.page_indicator_unselected);
}
ivArrayDotsPager[position].setImageResource(R.drawable.page_indicator_selected);
}


@Override
public void onPageScrollStateChanged(int state) {


}
});
}

创建一个方法 setupPagerIndidcatorDots () :

private void setupPagerIndidcatorDots() {
ivArrayDotsPager = new ImageView[eventImagesUrl.size()];
for (int i = 0; i < ivArrayDotsPager.length; i++) {
ivArrayDotsPager[i] = new ImageView(getActivity());
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.setMargins(5, 0, 5, 0);
ivArrayDotsPager[i].setLayoutParams(params);
ivArrayDotsPager[i].setImageResource(R.drawable.page_indicator_unselected);
//ivArrayDotsPager[i].setAlpha(0.4f);
ivArrayDotsPager[i].setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
view.setAlpha(1);
}
});
llPagerDots.addView(ivArrayDotsPager[i]);
llPagerDots.bringToFront();
}

您可以查看我的库来处理您的请求: https://github.com/tommybuonomo/dotsindicator

在 XML 布局中

  <com.tbuonomo.viewpagerdotsindicator.DotsIndicator
android:id="@+id/dots_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
app:dotsColor="@color/colorPrimary"
app:dotsSize="16dp"
app:dotsWidthFactor="3"
/>

在你的 Java 代码中

dotsIndicator = (DotsIndicator) findViewById(R.id.dots_indicator);
viewPager = (ViewPager) findViewById(R.id.view_pager);
adapter = new ViewPagerAdapter();
viewPager.setAdapter(adapter);
dotsIndicator.setViewPager(viewPager);

您的 xml

  <RelativeLayout
android:id="@+id/rl_speed"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/ll_dashboard_buttons"
android:layout_below="@+id/ib_menu">


<com.smart.gps.speedometer.app.utils.SmartViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
</com.smart.gps.speedometer.app.utils.SmartViewPager>


<android.support.design.widget.TabLayout
android:id="@+id/sliding_tabs"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabBackground="@drawable/tab_selector"
app:tabIndicatorHeight="0dp"
app:tabGravity="center"
/>

创建一个可绘制的。右键单击可绘制的-> 新建-> 可绘制的文件资源 说出那个文件的名字

Tab _ selector. xml

<item android:drawable="@drawable/selected_tab"
android:state_selected="true"/>


<item android:drawable="@drawable/unselected_tab"/>

现在又有两个 xml 文件。创建另外两个名称受人尊敬的 xml 文件。这些是选择器指示器和未选择的指示器

Select _ tab. xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
android:innerRadius="0dp"
android:shape="ring"
android:thickness="4dp"
android:useLevel="false">
<solid android:color="@color/highspeed"/>
</shape>
</item>
</layer-list>

Unselect _ tab. xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
android:innerRadius="0dp"
android:shape="ring"
android:thickness="2dp"
android:useLevel="false">
<solid android:color="@android:color/darker_gray"/>
</shape>
</item>
</layer-list>

将 ViewFlipper 和 viewFlipper _ line _ dot _ lay (线性布局)放置在相同的基线上,并遵循下面的基线

viewFlipper_linear_dot_lay= (LinearLayout) findViewById(R.id.dots_lay);
setupDotsOnViewPager(images_viewFlipper);
for (int i = 0; i < images_viewFlipper.size(); i++) {
//Add Images to ViewFlipper
}






private void setupDotsOnViewPager(ArrayList images_viewFlipper) {
images_linear = new ImageView[images_viewFlipper.size()];
for (int i = 0; i < images_linear.length; i++) {
images_linear[i] = new ImageView(this);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.setMargins(5, 0, 5, 0);
params.gravity = Gravity.BOTTOM | Gravity.CENTER;
images_linear[i].setLayoutParams(params);
images_linear[i].setImageResource(R.drawable.unselected);
viewFlipper_linear_dot_lay.addView(images_linear[i]);
viewFlipper_linear_dot_lay.bringToFront();
}
}

OnRight & OnLeft 获取放置下面的代码

for (int i = 0; i < images_linear.length; i++) {
images_linear[i].setImageResource(R.drawable.unselected);
}
images_linear[viewFlipper.getDisplayedChild()].setImageResource(R.drawable.selected);
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">


<androidx.viewpager.widget.ViewPager
android:id="@+id/vpImage"
android:layout_width="match_parent"
android:layout_height="@dimen/_150sdp" />


<com.google.android.material.tabs.TabLayout
android:id="@+id/tlImage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabBackground="@drawable/selector_product_image"
app:tabGravity="center"
app:tabIndicatorHeight="0dp"
app:tabMaxWidth="12dp"
app:tabRippleColor="@null" />


</androidx.appcompat.widget.LinearLayoutCompat>

ImageAdapter imageAdapter = new ImageAdapter(getActivity(), arrayListSlider);
binding.vpImage.setOffscreenPageLimit(1);
binding.vpImage.setAdapter(imageAdapter);
binding.tlImage.setupWithViewPager(binding.vpImage);

Selector _ product _ image. xml

<selector xmlns:android="http://schemas.android.com/apk/res/android">


<item android:drawable="@drawable/image_selected" android:state_selected="true" />
<item android:drawable="@drawable/image_unselected" />


</selector>

Image _ select. xml

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
android:innerRadius="0dp"
android:shape="ring"
android:thickness="4dp"
android:useLevel="false">
<solid android:color="@color/colorAccent" />
</shape>
</item>
</layer-list>

Image _ unselect. xml

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape
android:innerRadius="0dp"
android:shape="ring"
android:thickness="4dp"
android:useLevel="false">
<solid android:color="@color/colorPrimary" />
</shape>
</item>
</layer-list>

Java

class ImageAdapter extends PagerAdapter {


private Context context;
private ArrayList<ImageModel> arrayList;
private LayoutInflater layoutInflater;


public ImageAdapter(Context context, ArrayList<ImageModel> arrayList) {
this.context = context;
this.arrayList = arrayList;
this.layoutInflater = (LayoutInflater) this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}


@Override
public int getCount() {
return arrayList.size();
}


@Override
public boolean isViewFromObject(@NonNull View view, @NonNull Object o) {
return view == ((View) o);
}


@Override
public Object instantiateItem(ViewGroup container, int position) {
View view = layoutInflater.inflate(R.layout.row_slider_image, container, false);


AppCompatImageView ivProductImage = view.findViewById(R.id.ivProductImage);


if (!TextUtils.isEmpty(arrayList.get(position).getImage())) {
Glide.with(context)
.load(arrayList.get(position).getImage())
.apply(new RequestOptions().placeholder(R.drawable.no_image).error(R.drawable.no_image))
.into(ivProductImage);
}


container.addView(view);
return view;
}


@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
}

Row _ slider _ image. xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">


<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/ivProductImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:scaleType="fitXY"
android:src="@drawable/no_image" />


</androidx.appcompat.widget.LinearLayoutCompat>

当你想要类似的东西与最新的 ViewPager2科特林

一切都是自我解释,不需要解释!

enter image description here

你的活动或片段

val imageList = listOf(
ImageModel(R.drawable.offer1),
ImageModel(R.drawable.splash),
ImageModel(R.drawable.offer1),
ImageModel(R.drawable.splash2)
)


val adapter = HomeOffersAdapter()
adapter.setItem(imageList)
photos_viewpager.adapter = adapter


TabLayoutMediator(tab_layout, photos_viewpager) { tab, position ->
}.attach()
}

2. 布局

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_200">


<androidx.viewpager2.widget.ViewPager2
android:id="@+id/photos_viewpager"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_200" />


<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_gravity="bottom|center"
app:tabBackground="@drawable/tab_selector"
app:tabGravity="center"
app:tabIndicatorHeight="0dp"
app:tabSelectedTextColor="@android:color/transparent"
app:tabTextColor="@android:color/transparent" />

3. 可绘制: tab _ selector. xml

<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/dot_selected" android:state_selected="true" />
<item android:drawable="@drawable/dot_default" />

4. 可绘制: dot _ select. xml

<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:innerRadius="0dp"
android:shape="ring"
android:thickness="@dimen/dp_8"
android:useLevel="false">


<solid android:color="@color/colorPrimary" />


<stroke
android:width="@dimen/dp_1"
android:color="@android:color/white" />

5. 可绘制: dot _ default. xml

<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:innerRadius="0dp"
android:shape="ring"
android:thickness="@dimen/dp_8"
android:useLevel="false">


<solid android:color="@android:color/transparent" />


<stroke
android:width="@dimen/dp_1"
android:color="@android:color/white" />

6. 适配器

class HomeOffersAdapter : RecyclerView.Adapter<HomeOffersAdapter.HomeOffersViewHolder>() {


private var list: List<ImageModel> = listOf()




override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeOffersViewHolder {
return HomeOffersViewHolder(parent)
}




override fun onBindViewHolder(holder: HomeOffersViewHolder, position: Int) {
holder.bind(list[position])
}


fun setItem(list: List<ImageModel>) {
this.list = list
notifyDataSetChanged()
}


override fun getItemCount(): Int = list.size


class HomeOffersViewHolder constructor(itemView: View) : RecyclerView.ViewHolder(itemView) {


constructor(parent: ViewGroup) : this(
LayoutInflater.from(parent.context).inflate(
R.layout.pager_item,
parent, false
)
)


fun bind(imageModel: ImageModel) {
itemView.offerImage.setImageResource(imageModel.image)
}
}

}

7. 布局: pager _ item. xml

<LinearLayout 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"
android:fitsSystemWindows="true"
android:orientation="vertical">


<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/offerImage"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_200"
android:adjustViewBounds="true"
android:scaleType="fitXY"
tools:src="@drawable/offer1" />

添加依赖 > 同步级别

implementation 'com.tbuonomo.andrui:viewpagerdotsindicator:4.1.2'

在你的 Java 代码里

 dotsIndicator = (DotsIndicator) findViewById(R.id.dots_indicator3);




myViewPagerAdapter = new MyViewPagerAdapter();
viewPager.setAdapter(myViewPagerAdapter);
viewPager.addOnPageChangeListener(viewPagerPageChangeListener);
dotsIndicator.setViewPager(viewPager);

在你的布局里

<com.tbuonomo.viewpagerdotsindicator.SpringDotsIndicator
android:id="@+id/spring_dots_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:dampingRatio="0.5"
app:dotsColor="@color/material_white"
app:dotsStrokeColor="@color/material_yellow"
app:dotsCornerRadius="2dp"
app:dotsSize="16dp"
app:dotsSpacing="6dp"
app:dotsStrokeWidth="2dp"
app:stiffness="300"
/>

2021,如何实际做到这一点。 ViewPager2只。

请参考这篇优秀的短文,它有几个问题:

Https://medium.com/@adrian.kuta93/android-viewpager-with-dots-indicator-a34c91e59e3a

从2021年的一个普通的 Android Studio 默认项目开始,合理的新的最小值(目前为24) ..。

一般概念:

制作一个标准的 TabLayout,但是将每个“ tab 单元”替换为“一个小点”,而不是通常的文本。

在 TabLayout 中,您确实可以使用“ tabBack”替换每个“ tab 单元”:

        app:tabBackground="@drawable/tab_selector"

因此,将以下内容添加到屏幕的 XML 中,该 XML 具有 ViewPager2:

    <com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:background="#00FFFFFF"
app:tabBackground="@drawable/tab_selector"
app:tabIndicatorGravity="center"
app:tabIndicatorHeight="0dp"/>

注意,我们正在用我们自己的 “ tab _ selector”代替 TabLayout 中的“ tab 单元”。

为了完全清楚,“标签背景”意味着个人小“标签单位”,没有整个标签栏系统。

(除此之外,请注意,tabIndicatorGravity 和 tabIndicatorHeight 这两个技巧确实可以去掉通常的“ tab 单元”的“ box”。)

接下来用显而易见的方式创建三个绘图,Tab _ selector和两个不同的点。请参阅上面的文章或本页上的100个例子。

魔法密码:

在你的 onCreate有预期的代码..。

viewPager = findViewById(R.id.simple_slide_pager);
tab_layout = findViewById(R.id.tab_layout);
viewPager.setAdapter(new ScreenSlidePagerAdapter(this));

最后,这里是使其工作的神奇代码片段:

2021年最新数据:

TabLayoutMediator tabLayoutMediator =
new TabLayoutMediator(tab_layout, viewPager, true,
new TabLayoutMediator.TabConfigurationStrategy() {
@Override public void onConfigureTab(
@NonNull TabLayout.Tab tab, int position) { }
}
);
tabLayoutMediator.attach();

结束了。

(在 onConfigureTab内部,你可以做任何音效或任何可能需要的东西。有关更短的语法,请参见上面@F1iX 的关键注释。)

对于 Viewpager2,遵循@RediOne1建议的相同步骤,并且在活动或片段中使用下面的代码附加 tablaywith viwpager2

 val tabLayoutMediator  = TabLayoutMediator(binding.tabLayout,binding.offersVp) { _, _ -> }
tabLayoutMediator.attach()