效果:
由一个横向ScrollView动态布置的一个可滑seekbar效果。
等级的Model
package com.leveldemo;
/**
* Created by KID on 2017/12/27.
*/
public class SimpleLevelModel {
private int levelId;
private int minExp;
public int getLevelId() {
return levelId;
}
public void setLevelId(int levelId) {
this.levelId = levelId;
}
public int getMinExp() {
return minExp;
}
public void setMinExp(int minExp) {
this.minExp = minExp;
}
}
一个px和dp的转换工具
import android.content.Context;
import android.util.TypedValue;
/**
* Created by Administrator on 2017/5/9 0009.
*/
public class DensityUtils {
private DensityUtils(){
/* cannot be instantiated */
throw new UnsupportedOperationException("cannot be instantiated");
}
/**
* dp 转 px
*
* @param context
* @param
* @return
*/
public static int dp2px(Context context, float dpVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
dpVal, context.getResources().getDisplayMetrics());
}
/**
* sp转px
* @param context
* @param spVal
* @return
*/
public static int sp2px(Context context, float spVal) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
spVal, context.getResources().getDisplayMetrics());
}
/**
* px转dp
* @param context
* @param pxVal
* @return
*/
public static float px2dp(Context context, float pxVal) {
final float scale = context.getResources().getDisplayMetrics().density;
return (pxVal / scale);
}
/**
* px转sp
* @param context
* @param pxVal
* @return
*/
public static float px2sp(Context context, float pxVal) {
return (pxVal / context.getResources().getDisplayMetrics().scaledDensity);
}
}
布局文件xml
<?xml version="1.0" encoding="utf-8"?>
<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:orientation="vertical"
android:gravity="center_vertical"
android:background="#356485">
<!-- 横向seekbar布局-->
<HorizontalScrollView
android:id="@+id/scrollview_level"
android:layout_marginTop="8dp"
android:layout_width="match_parent"
android:layout_height="80dp"
android:scrollbars="none"
>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingLeft="20dp"
android:paddingRight="20dp">
<View
android:layout_centerVertical="true"
android:id="@+id/white_line"
android:background="@color/white"
android:layout_width="match_parent"
android:layout_height="5dp"/>
<View
android:layout_centerVertical="true"
android:id="@+id/red_line"
android:background="@color/red"
android:layout_width="match_parent"
android:layout_height="5dp"/>
<TextView
android:textStyle="bold"
android:gravity="center"
android:id="@+id/tv_exp"
android:text="125"
android:textSize="9sp"
android:background="@drawable/exp_perent_bg"
android:textColor="@color/white"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/red_line"
android:visibility="visible"/>
<LinearLayout
android:id="@+id/ll_content_img"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:orientation="horizontal" >
</LinearLayout>
</RelativeLayout>
</HorizontalScrollView>
</LinearLayout>
看到布局,可能你已经大概猜测到实现原理了。嗯哼~其实这个功能本身就应该由一些线条,动态添加布局实现。或者你想过做成自定义View,去draw线和圆。道理我们都懂……怎么简单怎么实现呗
业务代码
package com.leveldemo;
import android.annotation.TargetApi;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
//横向seekbar的容器
private HorizontalScrollView horizontalScrollView;
private LinearLayout contentLl;
//经验值悬浮窗
private TextView expTv;
//当前等级到下一等级的百分比
private double percent;
//横向seekbar的宽度
private int width;
//底色白线
private View whiteLine;
//经验红线
private View redLine;
private SparseArray<ImageView> imageViews;
private SparseArray<TextView> textviews;
private List<SimpleLevelModel> simpleLevelModelList;
private int myLevel=15;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
initData();
}
private void initView() {
horizontalScrollView= (HorizontalScrollView) findViewById(R.id.scrollview_level);
contentLl= (LinearLayout) findViewById(R.id.ll_content_img);
expTv = (TextView) findViewById(R.id.tv_exp);
redLine=findViewById(R.id.red_line);
whiteLine=findViewById(R.id.white_line);
expTv.setText("10234");
simpleLevelModelList=new ArrayList<>();
for (int i = 0; i < 50; i++) {
SimpleLevelModel moel=new SimpleLevelModel();
moel.setLevelId(i+1);
simpleLevelModelList.add(moel);
}
}
private void initData() {
if (imageViews == null){
imageViews = new SparseArray<>();
}
if(textviews==null){
textviews=new SparseArray<>();
}
for (int i = 0; i <simpleLevelModelList.size(); i++) {
if(i!=simpleLevelModelList.size()-1){
contentLl.addView(getRadioView(i,false),i);
}else {
contentLl.addView(getRadioView(i,true),i);
}
}
contentLl.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onGlobalLayout() {
width=contentLl.getWidth();
contentLl.getViewTreeObserver().removeOnGlobalLayoutListener(this);
setDefault(myLevel);
}
});
}
private View getRadioView(final int i,boolean isLast){
View view = null;
if(!isLast){
view = LayoutInflater.from(this).inflate(R.layout.item_lv_tagpoint,contentLl,false);
ImageView imageview = (ImageView) view.findViewById(R.id.image);
TextView textview = (TextView) view.findViewById(R.id.tv_level_seekbar);
textview.setText("LV"+simpleLevelModelList.get(i).getLevelId());
imageViews.put(i,imageview);
textviews.put(i,textview);
}else {
view = LayoutInflater.from(this).inflate(R.layout.item_lv_lastpoint,contentLl,false);
ImageView imageview = (ImageView) view.findViewById(R.id.image);
TextView textview = (TextView) view.findViewById(R.id.tv_level_seekbar);
textview.setText("LV"+simpleLevelModelList.get(i).getLevelId());
imageViews.put(i,imageview);
textviews.put(i,textview);
}
return view;
}
private void setDefault(int level) {
percent= 0.82;
for (int i = 0; i <imageViews.size() ; i++) {
if(i<level){
imageViews.get(i).setImageResource(R.drawable.level_red_point);
}else {
imageViews.get(i).setImageResource(R.drawable.level_white_point);
}
}
// textviews.get(level).setText("LV"+simpleLevelModelList.get(level).getLevelId());
// backLine.getLayoutParams().width= width-((int)DensityUtils.dp2px(getApplicationContext(),itemwidth));
//进度底色
RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) whiteLine.getLayoutParams();
lp.width= (simpleLevelModelList.size()-1)* DensityUtils.dp2px(getApplicationContext(),100F);
lp.setMargins(DensityUtils.dp2px(getApplicationContext(),50F),0,0,0);
// backLine.getLayoutParams().width= (titles.size()-1)*DensityUtils.dp2px(getApplicationContext(),100F);
whiteLine.setLayoutParams(lp);
RelativeLayout.LayoutParams lp1 = (RelativeLayout.LayoutParams) redLine.getLayoutParams();
lp1.width= (myLevel-1)*DensityUtils.dp2px(getApplicationContext(),100F)+(int)(percent*DensityUtils.dp2px(getApplicationContext(),100F));
lp1.setMargins(DensityUtils.dp2px(getApplicationContext(),50F),0,0,0);
redLine.setLayoutParams(lp1);
horizontalScrollView.scrollTo(lp1.width,0);
RelativeLayout.LayoutParams lp2 = (RelativeLayout.LayoutParams) expTv.getLayoutParams();
//偏移时需要加悬浮窗宽度+point的宽度
lp2.setMargins(lp1.width+DensityUtils.dp2px(getApplicationContext(),50F)-expTv.getWidth()/2,0,0,DensityUtils.dp2px(getApplicationContext(),10F));
expTv.setLayoutParams(lp2);
}
}
其中setDefault(int level)是根据后台返回的数据设置默认的等级和经验值。
item_lv_tagpoint.xml和item_lv_lastpoint.xml是小圆点的布局,一个是normal态,一个是最后一个小球。 所以别问我为什么两个布局一样- -!,按照产品的尿性,达到最终等级总是要有一张不一样的图片的(¯﹃¯),只是我找不到我要的滑板鞋~~~
代码链接http://download.csdn.net/download/qq_31390699/10176050