自定义控件简化开发Android 自定义view

ConstraintLayout+ViewPager2打造《摇一

2022-01-24  本文已影响0人  爺珍爱那颗心

话不多说直接上图

image.png

正文开始啦

image.png

ConstraintLayout使用

<com.android.springfestival.view.SpringTextView
    android:id="@+id/top"
    android:layout_width="wrap_content"
    android:layout_height="?actionBarSize"
    android:background="@drawable/shape_red_solid"
    android:gravity="center"
    android:paddingLeft="10dp"
    android:paddingRight="10dp"
    android:text="金 虎 迎 福"
    android:textSize="24sp"
    android:textStyle="bold"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<androidx.constraintlayout.widget.Guideline
    android:id="@+id/guideline"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    app:layout_constraintGuide_percent="0.7" />
<com.android.springfestival.view.VerticalTextView
   android:id="@+id/left"
   android:layout_width="0dp"
   android:layout_height="0dp"
   android:layout_marginLeft="5dp"
   android:background="@drawable/shape_red_solid"
   android:ems="1"
   android:paddingTop="10dp"
   android:paddingBottom="10dp"
   android:text="迎春迎福迎富贵"
   android:textSize="24sp"
   android:textStyle="bold"
   app:layout_constraintHorizontal_weight="1"
   app:layout_constraintBottom_toTopOf="@id/guideline"
   app:layout_constraintEnd_toStartOf="@id/ling"
   app:layout_constraintStart_toStartOf="parent"
   app:layout_constraintTop_toBottomOf="@id/top" />

<com.android.springfestival.view.VerticalTextView
   android:id="@+id/right"
   android:layout_width="0dp"
   android:layout_height="0dp"
   android:layout_marginRight="5dp"
   android:background="@drawable/shape_red_solid"
   android:ems="1"
   android:paddingTop="10dp"
   android:paddingBottom="10dp"
   android:text="接财接福接平安"
   android:textSize="24sp"
   android:textStyle="bold"
   app:layout_constraintHorizontal_weight="1"
   app:layout_constraintBottom_toBottomOf="@id/guideline"
   app:layout_constraintEnd_toEndOf="parent"
   app:layout_constraintStart_toEndOf="@id/ling"
   app:layout_constraintTop_toBottomOf="@id/top" />

<com.android.springfestival.view.DiamondTextView
   android:id="@+id/ling"
   android:layout_width="0dp"
   app:layout_constraintDimensionRatio="1:1"
   app:layout_constraintHorizontal_weight="3"
   android:layout_height="0dp"
   android:layout_margin="5dp"
   android:autoSizeTextType="uniform"
   android:gravity="center"
   android:text="福"
   android:textStyle="bold"
   app:layout_constraintBottom_toTopOf="@+id/OptionVp"
   app:layout_constraintEnd_toStartOf="@id/right"
   app:layout_constraintStart_toEndOf="@id/left"
   app:layout_constraintTop_toBottomOf="@id/top"
   />
<androidx.viewpager2.widget.ViewPager2
    android:id="@+id/OptionVp"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    app:layout_constraintBottom_toTopOf="@id/llPointContainer"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@id/guideline"
    app:layout_constraintVertical_weight="4" />

<LinearLayout
    android:id="@+id/llPointContainer"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_marginTop="10dp"
    android:gravity="center_horizontal"
    android:orientation="horizontal"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toBottomOf="@id/OptionVp"
    app:layout_constraintVertical_weight="1" />

Drawable使用

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

 <stroke
     android:width="1dp"
     android:color="@color/colorGold" />
 <solid android:color="@color/colorRed" />
</shape>

自定义View

横批

image.png
class SpringTextView(context: Context?, attrs: AttributeSet?) :
    AppCompatTextView(context, attrs) {
    //重写设置字体方法
    override fun setTypeface(tf: Typeface?) {
        super.setTypeface(Typeface.createFromAsset(context.assets, "fonts/hwxk.ttf"))
    }
}

对联

override fun onDraw(canvas: Canvas) {
    paint.textSize = textSize
    paint.apply {
        typeface = Typeface.createFromAsset(context.assets,"fonts/hwxk.ttf")
    }
    var textLengthHeight = 0
    val r = Rect()
    val arr = IntArray(text.length)
    canvasLength = measuredHeight - paddingTop - paddingBottom
    if (!TextUtils.isEmpty(text) && text.length > 1) {
        var i = 0
        while (i < text.length) {
            paint.getTextBounds(text.substring(i, i + 1), 0, 1, r)
            textLengthHeight += (r.bottom - r.top)
            arr[i] = r.bottom - r.top
            i++
        }
        space = (canvasLength - textLengthHeight).toDouble() / (text.length - 1)
    }
    var arrlength = 0f
    var i = 0
    while (i < text.length) {
        arrlength += arr[i]
        if (i == 0) {
            canvas.drawText(
                text.substring(i, i + 1),
                ((width - r.right - r.left) / 2).toFloat(),
                (i * space + arrlength).toFloat() + paddingTop,
                paint
            )
        } else {
            canvas.drawText(
                text.substring(i, i + 1),
                ((width - r.right - r.left) / 2).toFloat(),
                (i * space + arrlength).toFloat(),
                paint
            )
        }
        i++
    }
}

福字

override fun onDraw(canvas: Canvas) {
   super.onDraw(canvas)
   var min = min(width, height)
   var mPath = Path().apply {
       moveTo(0F, (min / 2).toFloat());
       lineTo((min / 2).toFloat(), 0F);
       lineTo(min.toFloat(), (min / 2).toFloat());
       lineTo((min / 2).toFloat(), min.toFloat());
       close();
   }
   val bmp = Bitmap.createBitmap(min, min, Bitmap.Config.ARGB_8888)
   val c = Canvas(bmp)
   c.drawPath(mPath, paint)
   c.drawPath(mPath, paintStock)
   setBackgroundDrawable(BitmapDrawable(resources, bmp))

ViewPager2

无限滑动的实现

val newList = arrayListOf<String>()
newList.add(pic[pic.size-1])
for (item in pic) {
    newList.add(item)
}
newList.add(pic[0])
位置 处理
currentPosition == 0 setCurrentItem(adapter.itemCount - 2, false)
currentPosition == adapter.itemCount - 1 setCurrentItem(1, false)
bannerVp.registerOnPageChangeCallback(object :
    ViewPager2.OnPageChangeCallback() {
    override fun onPageSelected(position: Int) {
        currentPosition = position
    }
    override fun onPageScrollStateChanged(state: Int) {
        //只有在空闲状态,才让自动滚动
        if (state == ViewPager2.SCROLL_STATE_IDLE) {
            if (currentPosition == 0) {
                bannerVp.setCurrentItem(adapter.itemCount - 2, false)
            } else if (currentPosition == adapter.itemCount - 1) {
                bannerVp.setCurrentItem(1, false)
            }
        }
    }
})

item的形状

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

    <corners
        android:bottomRightRadius="50dp"
        android:topLeftRadius="50dp" />
    <stroke
        android:width="1dp"
        android:color="@color/colorGold" />
    <solid android:color="#F02A2A" />
</shape>

指示器的添加

private fun initIndicator(){
    llPointContainer.removeAllViews()
    for (index in 1..size-2) {
        val view = View(this)
        val layoutParams = LinearLayout.LayoutParams(10.dp.toInt(), 10.dp.toInt())
        layoutParams.marginEnd = 8
        layoutParams.marginStart = 8
        view.layoutParams = layoutParams
        llPointContainer.addView(view)
    }
}
if (position <= llPointContainer.childCount) updateIndicator(position)
private fun updateIndicator(position: Int){
    llPointContainer.run {
        for (index in 1..childCount) {
            getChildAt(index - 1).background = resources.getDrawable(R.drawable.circlered)
        }
        if (position > 0) {
            getChildAt(position - 1).background = resources.getDrawable(R.drawable.circlegold)
        }
    }
}

ViewPager2一屏多页效果

OptionVp.apply {
 offscreenPageLimit=1
 val recyclerView= getChildAt(0) as RecyclerView
 recyclerView.apply {
     val padding = resources.getDimensionPixelOffset(R.dimen.common_line_height) +
             resources.getDimensionPixelOffset(R.dimen.common_line_height)
     // setting padding on inner RecyclerView puts overscroll effect in the right place
     setPadding(padding, 0, padding, 0)
     clipToPadding = false
 }
}

ViewPager2滑动缩放

val compositePageTransformer = CompositePageTransformer()
compositePageTransformer.addTransformer(ScaleInTransformer())
compositePageTransformer.addTransformer(
    MarginPageTransformer(
        resources.getDimension(R.dimen.common_margin_middle).toInt()
    )
)
OptionVp.setPageTransformer(compositePageTransformer)

传感器

sensorManager = getSystemService(SENSOR_SERVICE) as SensorManager
sensor = sensorManager!!.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
sensorManager!!.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL)
sensorManager!!.unregisterListener(this)
override fun onSensorChanged(event: SensorEvent) {
        /* 当传感器数值发生改变时调用的函数*/
        val values: FloatArray = event.values
        val x = values[0]
        val y = values[1]
        val z = values[2]
        val minValue = 15
        if(!isShake) {
            if (Math.abs(x) > minValue || Math.abs(y) > minValue || Math.abs(z) > minValue) {
                //开始震动
                isShake = true
                val pattern = longArrayOf(300, 500)
                vibrator!!.vibrate(pattern, -1)
                //开始动画效果
                MyDialog(this)
                    .showDialog(currentPosition - 1)

            }
        }
    }

震动的实现

<!-- 振动器使用权限-->
<uses-permission android:name="android.permission.VIBRATE"/>
//获取振动器管理者对象
vibrator = getSystemService(VIBRATOR_SERVICE) as Vibrator
//开启震动
val pattern = longArrayOf(300, 500)
vibrator!!.vibrate(pattern, -1)

Android动画

标签 含义
interpolator 指定动画插入器,常见的有加速减速插入器accelerate_decelerate_interpolator,加速插入器elerate_interpolator,减速插入器decelerate_interpolator。
pivotX 横向动画起始位置,相对于屏幕的百分比,50%表示动画从屏幕中间开始
pivotY 纵向动画起始位置,相对于屏幕的百分比,50%表示动画从屏幕中间开始
fromXScale 横向动画开始前的缩放,0.0为不显示,1.0为正常大小
toXScale 横向动画最终缩放的倍数,1.0为正常大小,大于1.0放大
fromYScale 纵向动画开始前的缩放,0.0为不显示,1.0为正常大小
toYScale 纵向动画最终缩放的倍数,1.0为正常大小,大于1.0放大
<!-- 弹出时动画 -->
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale
        android:interpolator="@android:anim/accelerate_interpolator"
        android:fromXScale="0.0"
        android:toXScale="1.0"
        android:fromYScale="0.0"
        android:toYScale="1.0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:fillAfter="false"
        android:duration="400"/>
</set>
<!-- 退出时动画效果 -->
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <scale
        android:interpolator="@android:anim/accelerate_interpolator"
        android:fromXScale="1.0"
        android:toXScale="0.0"
        android:fromYScale="1.0"
        android:toYScale="0.0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:fillAfter="false"
        android:duration="400"/>
</set>

随机结果

(answerList.indices).random()

最后

祝各位工程师,虎年大吉,2022年心想事成,想法几经改版,差点流产,还好最后坚持做了出来。

写作不易,如果对你有一丢丢帮助或启发,感谢点赞支持,有问题也欢迎留言交流哦!

上一篇 下一篇

猜你喜欢

热点阅读