View getWidth() возвращает ноль
История древняя, но не теряющая своей актуальности после onCreate() вид который уже вроде бы должен быть размечен возвращает нули по ширине
View getWidth() возвращает ноль
История древняя, но не теряющая своей актуальности после onCreate() вид который уже вроде бы должен быть размечен возвращает нули по ширине и высоте.
Конечно есть всякие правильные и монструозные решения
view.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
view.getViewTreeObserver()
.removeOnGlobalLayoutListener(this);
view.getHeight(); //height is ready
}
}
);
Но есть более элегантное:
view.post(new Runnable() {
@Override
public void run() {
view.getHeight(); //height is ready
}
});
все это подробно и почему работает и разные другие варианты показаны сдесь
От асинхронности тут к сожалению никак не избавиться и это очень печально.
Для меня один из частых юзер кейсов это задача получения размера вида в RecyclerView, пример картинки в ImageView которую не хотелось бы каждый раз уменьшать а сразу преобразовать в подходящий размер и потом кэшировать. Поэтому я для себя сделал маленький и симпатичный класс подходящий лично для моих нужд.
Котлинобразно, реактивно и молодежно:
class ViewSize {
private val emitter = BehaviorSubject.create<Pair<Int, Int>>()
private var isFirst = true
fun addView(view: View) {
view.also {
if (isFirst) view.post {
if (isFirst) emitter.onNext(
Pair(view.width, view.height))
isFirst = false
}
}
}
fun asSingle(): Single<Pair<Int, Int>> = emitter.firstOrError()
}
Да не феншуйно из-за использования Subject зато дешево и практично.
Где то в адаптере это выглядит так
...
private val viewSize = ViewSize()
init {
...
Observables.combineLatest(
viewSize.asSingle().map { it.first }.asObservable(),
imageObservable)
.observeOn(Schedulers.computation())
.map { (width, image) -> //уменьшаем до нужной ширины }
...
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
//говорим что картинка готова
}.let(disposable::add)
}
override fun onCreateViewHolder(parent: ViewGroup,
viewType: Int): RecyclerView.ViewHolder {
LayoutInflater.from(parent.context)
.inflate(R.layout.calendar_item, parent, false)
.also(viewSize.addView(it))
.let(CalendarAdapter::ItemHolder)
}
Вот таким способом можно решить проблему более позднего определения ширины и высоты видов
PS: Почему View.getWidth() а неView.getMeasuredWidth() ? Потому что первое отдает реальную ширину, а второе то которую хочет данный вид.
메타데이터
- post_id
- 7c6fc1feba8
- slug
- view-getwidth-возвращает-0-7c6fc1feba8
- url
- https://medium.com/@vit.onix/view-getwidth-%D0%B2%D0%BE%D0%B7%D0%B2%D1%80%D0%B0%D1%89%D0%B0%D0%B5%D1%82-0-7c6fc1feba8
- canonical_url
- https://medium.com/@vit.onix/view-getwidth-%D0%B2%D0%BE%D0%B7%D0%B2%D1%80%D0%B0%D1%89%D0%B0%D0%B5%D1%82-0-7c6fc1feba8
- author_url
- https://medium.com/@vit.onix
- status
- ok
- fetched_at
- 2026-07-30 09:39:55