今日、私はこのようなグループで下部ナビゲーション選択のハイライト効果を見ました
どうしたらいいか考えたところ、これとは違い、塩漬けの魚のようなものが真ん中に突き出ているのを覚えています。どちらを選んでも目立ちます。
最初の方法
シンプルで高速なUIで、背景が目立つ写真をいくつかカットできます。
写真を切り替えるために選択するのは簡単で失礼です
グループ内の小さなパートナーを見つけて、UIのカット画像を要求します。6枚の写真は同じサイズで、目立つ背景はありません。
だから私は達成するための2番目の方法があるかどうか疑問に思いました
Baiduは長い間働いてきました、多分私が探している方法が間違っているかもしれません、多分誰もそのようなUIに遭遇していません。
何をすべきか、自分で考え、落ち着いてUI効果を見て、目立つ場所がベジエ曲線に少し似ていることがわかりました
ハイライトがベジエ曲線の場合、固定位置が目立つように直線を描く方法を詳しく分析しますか?
BezierカーブはPathのapiであり、Pathは連続的に線を引くことができます。
そうすれば簡単に達成でき、出発点を真正面に設定します
mPath.moveTo(0, 0);//起始点
次に、途中で直接呼び出しがあります
mPath.lineTo(x,y);
ハイライトする必要がある場合は、2次ベジエ曲線を呼び出します
mPath.quadTo(x1,y1,x2,y2);
案の定、効果はこんな感じ
はい、それは最初のステップですが、注意深く観察すると、家の下に白い背景があり、目立つ場所にも白い背景があるはずです。
Path and Paint Apiをもう一度確認したところ、この効果を実現する方法があることがわかりました。
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
ブラシはこのスタイルに設定する必要があります
mPath.lineTo(getWidth(), getHeight());
mPath.lineTo(0, getHeight());
mPath.close(); //封闭path路径
パスパスが完全に占有されている
その後、あなたは効果を達成することができます
ブラシの色を白に設定することを忘れないでください
mPaint.setColor(Color.WHITE);
それは実際に動作します!
食事レイアウトの効果はこんな感じ
とても醜い
しかし、成功への第一歩が踏み出され、改善を続けています
まず第一に、この目立つ弧はUIとは異なるようです
別の分析であり、目立つ場合は3つの曲線があることがわかりました。
次に、3つのコントロールポイントがあります
絵は少し醜いです
a b c 都是控制点
1-2 是第一段
2-3 是第二段
3-4 是第三段
3つのセグメントは3つの制御点に対応します
したがって、4次のベジエ曲線を描く必要があります
その結果、パスでは最大3つのレベルがサポートされます。。。。。。。
3つに分割するしかない
図によれば、abc制御点と1 2 34点の位置を計算することができます。
電話スクリーンの長さはwと想定されます
現在、下部に3つのモジュールがあるため、1つのモジュールが占める距離はi = w / 3です。
次に、1が開始点です
bはiの中心点です
4はポイントiです
Y方向の最高の高さは-yです(負の数であることに注意してください)
3つのベジエ曲線の長さが同じである場合、ポイントの位置は次のようになります。
1(0,0)
2(i/2/2,y/2)
3(i-i/2/2,y/2)
4(i,0)
a(i/2/2/2,y/2/2/2)
b(i/2,y)
c(i-i/2/2/2,y/2/2/2)
次に、これらのポイントをベジエ曲線に入れます
//第一条贝塞尔曲线 a 2
mPath.quadTo(i / 2 / 2 / 2 , -(minHeight / 2 / 2 / 2), i / 2 / 2 , -(minHeight / 2));
//第二条贝塞尔曲线 b 3
mPath.quadTo(i / 2 + i , -minHeight, i - i / 2 / 2 + i , -(minHeight / 2));
//第三条贝塞尔曲线 c 4
mPath.quadTo(i - i / 2 / 2 / 2 , -(minHeight / 2 / 2 / 2), i + i * (count - 1), 0);
次に、これが最初のモジュールです。後続のモジュールの計算では、いくつかのi値を追加します。
モジュールは1から始まり、現在3つのモジュール値があります(1 2 3)
//第一条贝塞尔曲线 a 2
mPath.quadTo(i / 2 / 2 / 2 + i * (count - 1), -(minHeight / 2 / 2 / 2), i / 2 / 2 + i * (count - 1) + minHeight / 5, -(minHeight / 2));
//第二条贝塞尔曲线 b 3
mPath.quadTo(i / 2 + i * (count - 1), -minHeight, i - i / 2 / 2 + i * (count - 1) - minHeight / 5, -(minHeight / 2));
//第三条贝塞尔曲线 c 4
mPath.quadTo(i - i / 2 / 2 / 2 + i * (count - 1), -(minHeight / 2 / 2 / 2), i + i * (count - 1), 0);
このようにして、カウント値を直接設定して再描画し、クリックスイッチを完了することができます。
すべてのコード
package com.wavewave.mylibrary;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import androidx.annotation.Nullable;
/**
* @author wavewave
* @CreateDate: 2020/10/28 10:23 AM
* @Description: 底部导航 选中突出View 背景
* @Version: 1.0
*/
public class BottomOutNavigation extends View {
private Paint mPaint;
//起始点
private int beginY = dip2px(0);
//边距
private int margin = dip2px(0);
/**
* 默认 突出最高点 Y
*/
private int minHeight = dip2px(40);
//第几个从0开始
private int count = 1;
/**
* 默认3个 根据实际情况写
*/
private int maxCount = 3;
public static String TAG = "LineView";
private int height;
private int width;
private Path mPath;
public BottomOutNavigation(Context context) {
this(context, null);
}
public BottomOutNavigation(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public BottomOutNavigation(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mPath = new Path();
mPaint = new Paint();
// mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setColor(Color.WHITE);
mPaint.setAntiAlias(true);//抗锯齿
//2、通过Resources获取
DisplayMetrics dm = getResources().getDisplayMetrics();
height = dm.heightPixels;
width = dm.widthPixels;
}
/**
* 设置选择
*
* @param count
*/
public void setCount(int count) {
this.count = count;
invalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int i = width / maxCount;//单个所占大小
Log.d(TAG, "i:" + i);
mPath.reset();
mPath.moveTo(0, 0);//起始点
mPath.lineTo(margin + i * (count - 1), 0);
//
//第一条贝塞尔曲线 a 2
mPath.quadTo(i / 2 / 2 / 2 + i * (count - 1), -(minHeight / 2 / 2 / 2), i / 2 / 2 + i * (count - 1) + minHeight / 5, -(minHeight / 2));
//第二条贝塞尔曲线 b 3
mPath.quadTo(i / 2 + i * (count - 1), -minHeight, i - i / 2 / 2 + i * (count - 1) - minHeight / 5, -(minHeight / 2));
//第三条贝塞尔曲线 c 4
mPath.quadTo(i - i / 2 / 2 / 2 + i * (count - 1), -(minHeight / 2 / 2 / 2), i + i * (count - 1), 0);
mPath.lineTo(width, beginY);
mPath.lineTo(getWidth(), getHeight());
mPath.lineTo(0, getHeight());
mPath.close(); //封闭path路径
canvas.drawPath(mPath, mPaint);
}
/**
* 根据屏幕的分辨率从 dp 的单位 转成为 px(像素)
*/
public int dip2px(float dpValue) {
final float scale = getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
真ん中の突き出た部分は、半分にした後、少し距離を引いて計算されます。アッパーgif
コードをgithubに配置しました。デモを直接ダウンロードして実行し、確認することができます。