“PK creative Spring Festival, I am participating in the” Spring Festival Creative submission contest “, please see: Spring Festival Creative Submission Contest”

Without further ado, let’s go to the picture above

  • As can be seen from the figure, it is divided intoUp and downTwo parts. The first part is traditionSpring Festival couplets and the word "fu", is for everyoneNew Year greetingThe next part isThe mainFunction module, includingThe amount of red envelopes, lucky New Year cards and yes or no.
  • usingKotlinLanguage writing, involving the technology are:ConstraintLayout,Drawable,The custom View,Android animation,Viewpager2,Font SettingsandUse of sensors.

    Sources.

  • The source of this idea is mainly old people, they will give it to their nieces and nephewsSend a red envelopeHahaha, this time the amount can be their ownShake out, has theInteraction and randomnessMore fun, forAdd fun to the New Year!
  • The New YearLucky signIt’s for everyoneblessing!
  • You’re going to have a lot of scenarios that are going to happenChoose difficult, soIs and is notThis module isSolve such problemsAdd the!
  • New Year ismoveAh, just traditionalThe headYou can use your cell phoneshakeTo simulate theThe effectMove your wristKill two birds with one stoneWhat a good idea!
  • The android mobile phoneFriends canDownloading the Installation package experienceA handful, I amCan't stop!

Here we go

  • First of all, this layout looks pretty simple, right,LinearLayoutSet the directionverticalI’m using one in the middleLinearLayoutSet the directionhorizontal.
    • But that raises a question,Nested layoutSo that’s why I use it. RightConstraintLayoutTo implement the reason, as shown below, only usedA layer of.

ConstraintLayout use

  • Long-winded two sentences, some small partners can be used, you can refer to
    • inConstraintLayoutIn the controlEither wayallSelect at least one constraintOtherwise, the control will be inThe top left corner is placed.
    • topRefers to the topbottomRefers to the bottomstartRefers to the leftendPoint to the right. Here’s an example
<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=" 12sp "Android :textSize="24sp" Android :textStyle="bold" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" />Copy the code
  • This is aHorizontal batchThe text can be seen on itAt the top of theandTop of parent layout constraints.On the leftandThe left side of the parent layout is constrained.On the rightandThe right side of the parent layout is constrained.
    • The horizontal centerNeed to bePut constraints on the left and the rightIf not, you want the control inWhich way to start, let itConstrain to that direction, such asHorizontal batch is placed at the top.
  • And what I want to do is letThe upper part accounts for 70 percent.The lower part is thirty percent
    • addGuideline control.Up and downSet up theFor horizontal orientationAnd want toAbout pointsInstead ofverticalCan.
    • layout_constraintGuide_percentProperty to setOr on the leftHow much? The range of values is0 to 1.

<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" / >Copy the code
  • In the middle of thecoupletsandblessingWord, I intend toblessingWord ofThirty percentAnd the restTen percent each, so the width and height of the controls are set to 0dp, that is, to fill the remaining spaceThe transversetheThe weight.1:3:1.
    • Lateral weightapp:layout_constraintHorizontal_weight
    • Because the word “fu” should be wide and high, set the ratio of 1:1app:layout_constraintDimensionRatio="1:1"
    • Note: between controlsThey have to be interdependentTo make a difference.
  • The code is as follows:
<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 :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=" 24SP "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" />Copy the code
  • The followingViewPager2andindicatorusingThe weight, press the remaining space4:1I’m going to distribute, right hereThe weightandLinearLayoutIs consistent with.
<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" />
Copy the code

Drawable used

  • I’m going to use thetaShapeDrawable
    • Its advantage is that it can be used for controlsAdd background.To reduceImage resourceuseAnd thusReduced package volumetheThe size of the.

  • In the picture abovecoupletsandStroke gold threadAll fromShapeDrawable, the code is as follows
<? The 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>Copy the code

The custom View

Horizontal batch

  • I don’t know if you noticed,The fontIt’s not a system font, we’re going to change itThe fontThe easiest way to do this isInherit the TextViewAnd rewrite hissetTypefacemethods

  • New as abovedirectoryPut in what we needThe font.
  • Use this fontAnd,To the parent class.
  • inLayout fileIn theuse, the code inConstraintLayoutIn the chapter.
class SpringTextView(context: Context? , attrs: AttributeSet?) Override fun setTypeface(tf: Typeface?); { super.setTypeface(Typeface.createFromAsset(context.assets, "fonts/hwxk.ttf")) } }Copy the code

couplets

  • As I’m sure you all know,TextViewYou can useandroid:ems="1"To achieveVertical array, butStick together.Can't divideveryNot beautifulSo let’s move onInherit the TextView, the customVertical equalization effect.
    • This time weRewrite the onDraw methodDo it yourselfText drawing.
    • height-drawnThe key pointIs thatFigure out the space between each text(Total height minus the padding and width of the text divided by the number of text minus one)
    • Width drawing (Total width minus the width of the text divided by two)
  • The code is as follows:
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++ } }Copy the code

everyone

  • The diamond TextViewThe system didn’t give us anything. What do we do? Go onThe custom!
    • Old ruleRewrite the ontouchTo obtainWide high, take the shortest, usePathLet me draw oneTextView sets the backgroundCan.
    • Here I amDrew twiceBecause theeveryoneHow could there be lessPhnom penh!
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))
Copy the code

ViewPager2

  • ViewPager2 before written a Banner to create the rotation of the map, here in a simple worded two sentences, may be some friends did not see the previous article.

The implementation of infinite sliding

  • The first digit of the data sourceaddLast picture
val newList = arrayListOf<String>()
newList.add(pic[pic.size-1])
Copy the code
  • The last bit adds the first diagram
for (item in pic) {
    newList.add(item)
}
newList.add(pic[0])
Copy the code
  • whenViewPager2 slides to bit 0andThe last oneThe treatment is as follows
location To deal with
currentPosition == 0 setCurrentItem(adapter.itemCount - 2, false)
currentPosition == adapter.itemCount - 1 setCurrentItem(1, false)
  • ViewPager2Add the slide listener code below

The key point is the onPageScrollStateChanged method

bannerVp.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { override fun onPageSelected(position: Int) { currentPosition = position } override fun onPageScrollStateChanged(state: Int) {// Only in idle state, 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) } } } })Copy the code

The shape of the item

  • This is also throughShapeDrawableThe code is as follows
<? The 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>Copy the code

Adding indicators

  • According to the number ofDynamically creating a View, the code is as follows:
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) } }Copy the code
  • When you slideUpdate indicator background
    • inViewPager2Slide listeningonPageSelectedMethod to call the following method
      • Remember to do the followingjudge
if (position <= llPointContainer.childCount) updateIndicator(position)
Copy the code
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) } } }Copy the code
  • The shape here is also throughShapeDrawableThe implementation.

ViewPager2 Multiple pages on one screen

  • Here andViewPagertheMore than one screen pageThere is a bigThe difference between.ViewPagerUsed forSelf set marginAnd set theThe clipChildren property is false.
  • ViewPager2By givingRecyclerViewSet up thePaddingandPageTransformerTo achieve
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 } }Copy the code

ViewPager2 slides to scale

  • So that’s the pointPageTransformerIt can be used to setPage animation, you can also setPage space.Spacing and animationIf you want to useCompositePageTransformer.
  • I like hereOn aTo set upPage spacing and zoomingSo let’s seeSpecific code.
val compositePageTransformer = CompositePageTransformer()
compositePageTransformer.addTransformer(ScaleInTransformer())
compositePageTransformer.addTransformer(
    MarginPageTransformer(
        resources.getDimension(R.dimen.common_margin_middle).toInt()
    )
)
OptionVp.setPageTransformer(compositePageTransformer)
Copy the code
  • Isn’t itVery sweetFast,To use!.

The sensor

  • AndroidThere are a lot of sensors, and here we’re usingAcceleration sensor, the procedure is as follows:
    • To obtainSensor managerobject
    • To obtainAcceleration sensorobject
    • registeredSensors (onCreateIn the call)
    • removeSensors (onDestoryIn the call)
sensorManager = getSystemService(SENSOR_SERVICE) as SensorManager
Copy the code
sensor = sensorManager!! .getDefaultSensor(Sensor.TYPE_ACCELEROMETER)Copy the code
sensorManager!! .registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL)Copy the code
sensorManager!! .unregisterListener(this)Copy the code
  • registeredThe listenerAfter theonSensorChangedMethod to dobusinessThe judgment of (here use getEvent. Values greater than 15) in accordance with the business conditionsCall to vibrateandA dialog box is displayed..
Override fun onSensorChanged(event: SensorEvent) {override fun onSensorChanged(event: SensorEvent) {/* Function that is called when the sensor value changes */ 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.h abs (y) > minValue | | math.h abs (z) > minValue) {/ / vibration isShake = true val pattern = longArrayOf(300, 500) vibrator!! .vibrate(pattern, -1) MyDialog(this).showdialog (currentPosition-1)}}Copy the code

Realization of vibration

  • The vibration needs to bemanifestIn the fileTo apply for permission
  • To obtainVibrator managerobject
  • callVibrate Activates vibration
<! - vibrator access - > < USES - permission android: name = "android. Permission. VIBRATE" / >Copy the code
// Get vibrator manager object vibrator = getSystemService(VIBRATOR_SERVICE) as vibratorCopy the code
Val Pattern = longArrayOf(300, 500) vibrator!! .vibrate(pattern, -1)Copy the code

Android animation

  • So here we’re usingThe View animationtoDialogaddEntry and exit animations. *The View animationLike aPan, scale, rotate and transparenceThis is used hereThe zoom.
The label meaning
interpolator Accelerate_interpolator specifies animation interpolator. The common accelerate_interpolator is elerate_interpolator, decelerate interpolator.
pivotX Horizontal animation starting position, relative to the percentage of the screen, 50% indicates that the animation starts in the middle of the screen
pivotY The starting position of the vertical animation, relative to the percentage of the screen. 50% indicates that the animation starts in the middle of the screen
fromXScale Zoom before the start of the horizontal animation, 0.0 is not shown, 1.0 is normal size
toXScale The final zoom of the horizontal animation, 1.0 is the normal size, greater than 1.0 magnification
fromYScale Zoom before the start of vertical animation, 0.0 is not shown, 1.0 is normal size
toYScale The final zoom of the vertical animation, 1.0 is the normal size, greater than 1.0 magnification
  • With that in mind, what followsEnter the animation, andPlay the animationIt’s easier to understand
    • Center positionFrom zero to oneforThe zoom.
<! - when the pop-up animation -- -- > < 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 :fillAfter="false" android:duration="400"/> </set>Copy the code
<! - exit animation effects - > < 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 :fillAfter="false" android:duration="400"/> </set>Copy the code
  • Exit from theOne to zeroBack to theCenter position.

Random results

  • There is no network request hereWrite your answers locally.A random sampleDisplay.
    • randomThe code inKotlinIt is very simple as follows
(answerList.indices).random()
Copy the code
  • Originally wanted to add a database, support artificial input, the late slowly realize it.

The last

I wish you all the best in the year of the Tiger. I wish you all the best in 2022. After several revisions of my idea, I almost lost my baby.

Writing is not easy, if you have a drop of help or inspiration, thank you for your support, if you have a question, also welcome to leave a message!